From a87a86198c8736d6334bd236f0dc6e8e7e6784eb Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Sat, 6 Jun 2015 15:27:03 -0700 Subject: [PATCH 001/335] Transfer friction to swimmable 3D floors. --- src/p_map.cpp | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b76919a7d..3676225b1 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -574,6 +574,27 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) { friction = secfriction(mo->Sector); movefactor = secmovefac(mo->Sector) >> 1; + +#ifdef _3DFLOORS + // Check 3D floors -- might be the source of the waterlevel + for (unsigned i = 0; i < mo->Sector->e->XFloor.ffloors.Size(); i++) + { + F3DFloor *rover = mo->Sector->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + if (!(rover->flags & FF_SWIMMABLE)) continue; + + if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || + mo->z < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + continue; + + newfriction = secfriction(rover->model); + if (newfriction < friction || friction == ORIG_FRICTION) + { + friction = newfriction; + movefactor = secmovefac(rover->model) >> 1; + } + } +#endif } else if (var_friction && !(mo->flags & (MF_NOCLIP | MF_NOGRAVITY))) { // When the object is straddling sectors with the same @@ -590,10 +611,22 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) { F3DFloor *rover = sec->e->XFloor.ffloors[i]; if (!(rover->flags & FF_EXISTS)) continue; - if (!(rover->flags & FF_SOLID)) continue; - // Player must be on top of the floor to be affected... - if (mo->z != rover->top.plane->ZatPoint(mo->x, mo->y)) continue; + if (rover->flags & FF_SOLID) + { + // Must be standing on a solid floor + if (mo->z != rover->top.plane->ZatPoint(mo->x, mo->y)) continue; + } + else if (rover->flags & FF_SWIMMABLE) + { + // Or on or inside a swimmable floor (e.g. in shallow water) + if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || + (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + continue; + } + else + continue; + newfriction = secfriction(rover->model); if (newfriction < friction || friction == ORIG_FRICTION) { From 8a428e69b6bcd4ec18832f4706866da224babf65 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Sat, 6 Jun 2015 15:31:12 -0700 Subject: [PATCH 002/335] Don't play a terrain splash if the player didn't take damage. --- src/p_spec.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 42a7b9ca4..5f29c3c53 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -738,12 +738,13 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType) } } + int damage = 0; if (ironfeet == NULL) { - P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount, + damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount, Terrains[floorType].DamageMOD); } - if (Terrains[floorType].Splash != -1) + if (damage > 0 && Terrains[floorType].Splash != -1) { S_Sound (player->mo, CHAN_AUTO, Splashes[Terrains[floorType].Splash].NormalSplashSound, 1, From 221c2d2d822bc44d1ccafa9f53fca3225aacd860 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Sat, 6 Jun 2015 16:03:11 -0700 Subject: [PATCH 003/335] Transfer flat-based damage (P_PlayerOnSpecialFlat) to 3D floors. --- src/p_3dfloors.cpp | 12 ++++++++++-- src/p_spec.cpp | 6 ------ src/p_user.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index cc76beaa3..2f81dd6a8 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -41,6 +41,7 @@ #include "w_wad.h" #include "sc_man.h" #include "g_level.h" +#include "p_terrain.h" #include "r_data/colormaps.h" #ifdef _3DFLOORS @@ -341,8 +342,15 @@ void P_PlayerOnSpecial3DFloor(player_t* player) (player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y)) continue; } - - if (rover->model->special || rover->model->damage) P_PlayerInSpecialSector(player, rover->model); + + // Apply sector specials + if (rover->model->special || rover->model->damage) + P_PlayerInSpecialSector(player, rover->model); + + // Apply flat specials (using the ceiling!) + P_PlayerOnSpecialFlat( + player, TerrainTypes[rover->model->GetTexture(sector_t::ceiling)]); + break; } } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 5f29c3c53..9bc0d4a9b 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -718,12 +718,6 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu void P_PlayerOnSpecialFlat (player_t *player, int floorType) { - if (player->mo->z > player->mo->Sector->floorplane.ZatPoint ( - player->mo->x, player->mo->y) && - !player->mo->waterlevel) - { // Player is not touching the floor - return; - } if (Terrains[floorType].DamageAmount && !(level.time & Terrains[floorType].DamageTimeMask)) { diff --git a/src/p_user.cpp b/src/p_user.cpp index 5f9a69c3a..0617e5d6a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2535,7 +2535,13 @@ void P_PlayerThink (player_t *player) { P_PlayerInSpecialSector (player); } - P_PlayerOnSpecialFlat (player, P_GetThingFloorType (player->mo)); + if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint( + player->mo->x, player->mo->y) || + player->mo->waterlevel) + { + // Player must be touching the floor + P_PlayerOnSpecialFlat(player, P_GetThingFloorType(player->mo)); + } if (player->mo->velz <= -player->mo->FallingScreamMinSpeed && player->mo->velz >= -player->mo->FallingScreamMaxSpeed && !player->morphTics && player->mo->waterlevel == 0) From 8fa9aa26275e71b32cd92065c7ba6d80c7fd1b17 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Sat, 6 Jun 2015 18:08:18 -0700 Subject: [PATCH 004/335] Use the correct sidedef's middle scaling when drawing 3D floors. This wants `curline->sidedef`, which is the 3D sidedef currently being drawn. `sidedef` appears to be the last regular sidedef that happened to be drawn? The perils of globals. --- src/r_segs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index cf00abc45..bfa4fdee4 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -557,8 +557,8 @@ void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover) MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1; // find positioning - xscale = FixedMul(rw_pic->xScale, sidedef->GetTextureXScale(side_t::mid)); - yscale = FixedMul(rw_pic->yScale, sidedef->GetTextureYScale(side_t::mid)); + xscale = FixedMul(rw_pic->xScale, curline->sidedef->GetTextureXScale(side_t::mid)); + yscale = FixedMul(rw_pic->yScale, curline->sidedef->GetTextureYScale(side_t::mid)); // encapsulate the lifetime of rowoffset fixed_t rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid); dc_texturemid = rover->model->GetPlaneTexZ(sector_t::ceiling); From 15b97c14093d80563f4773d17ea00e86b7b13ad0 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Sat, 6 Jun 2015 18:26:13 -0700 Subject: [PATCH 005/335] Fix scaling of 3D floor wall textures. The scale factors are now taken from the same part of the sidedef that provides the texture. --- src/r_segs.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index bfa4fdee4..7bcfec13a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -557,8 +557,25 @@ void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover) MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1; // find positioning - xscale = FixedMul(rw_pic->xScale, curline->sidedef->GetTextureXScale(side_t::mid)); - yscale = FixedMul(rw_pic->yScale, curline->sidedef->GetTextureYScale(side_t::mid)); + side_t *scaledside; + side_t::ETexpart scaledpart; + if (rover->flags & FF_UPPERTEXTURE) + { + scaledside = curline->sidedef; + scaledpart = side_t::top; + } + else if (rover->flags & FF_LOWERTEXTURE) + { + scaledside = curline->sidedef; + scaledpart = side_t::bottom; + } + else + { + scaledside = rover->master->sidedef[0]; + scaledpart = side_t::mid; + } + xscale = FixedMul(rw_pic->xScale, scaledside->GetTextureXScale(scaledpart)); + yscale = FixedMul(rw_pic->yScale, scaledside->GetTextureYScale(scaledpart)); // encapsulate the lifetime of rowoffset fixed_t rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid); dc_texturemid = rover->model->GetPlaneTexZ(sector_t::ceiling); From 3fea074d35d971cbfceef96c1b5dd57a468455fe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Jun 2015 09:33:15 +0200 Subject: [PATCH 006/335] - respect FF_INVERTSECTOR when checking a 3D floor's terrain. --- src/p_3dfloors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 2f81dd6a8..8091ffb92 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -349,7 +349,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) // Apply flat specials (using the ceiling!) P_PlayerOnSpecialFlat( - player, TerrainTypes[rover->model->GetTexture(sector_t::ceiling)]); + player, TerrainTypes[rover->model->GetTexture(rover->flags & FF_INVERTSECTOR? sector_t::floor : sector_t::ceiling)]); break; } From 4444d3c0c50c220978ec1c7a8d62eaa43a9d42ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Jun 2015 09:41:44 +0200 Subject: [PATCH 007/335] - removed the _3DFLOOR #define because we really do not want to comment this out anymore, right? --- src/am_map.cpp | 8 ------- src/g_heretic/a_hereticweaps.cpp | 4 ---- src/g_shared/a_decals.cpp | 2 -- src/p_3dfloors.cpp | 4 ---- src/p_3dfloors.h | 38 -------------------------------- src/p_enemy.cpp | 2 -- src/p_map.cpp | 32 --------------------------- src/p_mobj.cpp | 16 -------------- src/p_setup.cpp | 2 -- src/p_sight.cpp | 6 ----- src/p_trace.cpp | 10 --------- 11 files changed, 124 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 0133a2493..fdbacd34f 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1935,8 +1935,6 @@ void AM_drawSubsectors() scalex = sec->GetXScale(sector_t::floor); scaley = sec->GetYScale(sector_t::floor); -#ifdef _3DFLOORS - if (sec->e->XFloor.ffloors.Size()) { secplane_t *floorplane = &sec->floorplane; @@ -1997,7 +1995,6 @@ void AM_drawSubsectors() floorlight = *light->p_lightlevel; colormap = light->extra_colormap; } -#endif if (maptex == skyflatnum) { continue; @@ -2153,8 +2150,6 @@ void AM_showSS() } } -#ifdef _3DFLOORS - //============================================================================= // // Determines if a 3D floor boundary should be drawn @@ -2214,7 +2209,6 @@ bool AM_Check3DFloors(line_t *line) // All 3D floors could be matched so let's not draw a boundary. return false; } -#endif //============================================================================= // @@ -2345,12 +2339,10 @@ void AM_drawWalls (bool allmap) { AM_drawMline(&l, AMColors.CDWallColor); // ceiling level change } -#ifdef _3DFLOORS else if (AM_Check3DFloors(&lines[i])) { AM_drawMline(&l, AMColors.EFWallColor); // Extra floor border } -#endif else if (am_cheat > 0 && am_cheat < 4) { AM_drawMline(&l, AMColors.TSWallColor); diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 17c9621d5..afc4f6007 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -1046,7 +1046,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) x = self->x + ((pr_storm()&127) - 64) * FRACUNIT; y = self->y + ((pr_storm()&127) - 64) * FRACUNIT; mo = Spawn (x, y, ONCEILINGZ, ALLOW_REPLACE); -#ifdef _3DFLOORS // We used bouncecount to store the 3D floor index in A_HideInCeiling if (!mo) return; fixed_t newz; @@ -1058,7 +1057,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz); if (moceiling >= 0) mo->z = newz - mo->height; -#endif mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0; mo->target = self->target; @@ -1098,7 +1096,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) { -#ifdef _3DFLOORS // We use bouncecount to store the 3D floor index fixed_t foo; for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++) @@ -1114,7 +1111,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) } } self->bouncecount = -1; -#endif self->z = self->ceilingz + 4*FRACUNIT; } diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 576ff6a5c..29fcbf8cb 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -272,7 +272,6 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y, F3DFloor Z -= back->GetPlaneTexZ(sector_t::ceiling); tex = wall->GetTexture(side_t::top); } -#ifdef _3DFLOORS else if (ffloor) // this is a 3d-floor segment - do this only if we know which one! { Sector=ffloor->model; @@ -295,7 +294,6 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y, F3DFloor tex = ffloor->master->sidedef[0]->GetTexture(side_t::mid); } } -#endif else return FNullTextureID(); CalcFracPos (wall, x, y); diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 8091ffb92..5b29959cb 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -44,8 +44,6 @@ #include "p_terrain.h" #include "r_data/colormaps.h" -#ifdef _3DFLOORS - //========================================================================== // // 3D Floors @@ -959,8 +957,6 @@ int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, b return -1; } -#endif - #include "c_dispatch.h" diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index 8d42560af..8abd23f03 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -4,8 +4,6 @@ #define CenterSpot(sec) (vertex_t*)&(sec)->soundorg[0] -#define _3DFLOORS - // 3D floor flags. Most are the same as in Legacy but I added some for EDGE's and Vavoom's features as well. typedef enum { @@ -60,8 +58,6 @@ enum VC_COLORMASK = 0x00FFFFFF, }; -#ifdef _3DFLOORS - struct secplane_t; struct FDynamicColormap; @@ -149,39 +145,5 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z); int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz); -#else - -// Dummy definitions for disabled 3D floor code - -struct F3DFloor -{ - int dummy; -}; - -struct lightlist_t -{ - int dummy; -}; - -class player_s; -inline void P_PlayerOnSpecial3DFloor(player_t* player) {} - -inline void P_Get3DFloorAndCeiling(AActor * thing, sector_t * sector, fixed_t * floorz, fixed_t * ceilingz, int * floorpic) {} -inline bool P_CheckFor3DFloorHit(AActor * mo) { return false; } -inline bool P_CheckFor3DCeilingHit(AActor * mo) { return false; } -inline void P_Recalculate3DFloors(sector_t *) {} -inline void P_RecalculateAttached3DFloors(sector_t * sec) {} -inline lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside) { return NULL; } -inline void P_Spawn3DFloors( void ) {} - -struct FLineOpening; - -inline void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef, - fixed_t x, fixed_t y, fixed_t refx, fixed_t refy, bool restrict) {} - -//secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z){return sector->floorplane;} - -#endif - #endif \ No newline at end of file diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3e17a85f3..10c4704d4 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2548,7 +2548,6 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if (abs(corpsehit->x - viletryx) > maxdist || abs(corpsehit->y - viletryy) > maxdist) continue; // not actually touching -#ifdef _3DFLOORS // Let's check if there are floors in between the archvile and its target sector_t *vilesec = self->Sector; sector_t *corpsec = corpsehit->Sector; @@ -2566,7 +2565,6 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) continue; } } -#endif corpsehit->velx = corpsehit->vely = 0; // [RH] Check against real height and radius diff --git a/src/p_map.cpp b/src/p_map.cpp index 3676225b1..197525aa4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -249,7 +249,6 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) sec = tmf.thing->Sector; } -#ifdef _3DFLOORS for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { F3DFloor* rover = sec->e->XFloor.ffloors[i]; @@ -273,7 +272,6 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) tmf.ceilingpic = *rover->bottom.texture; } } -#endif } //========================================================================== @@ -575,7 +573,6 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) friction = secfriction(mo->Sector); movefactor = secmovefac(mo->Sector) >> 1; -#ifdef _3DFLOORS // Check 3D floors -- might be the source of the waterlevel for (unsigned i = 0; i < mo->Sector->e->XFloor.ffloors.Size(); i++) { @@ -594,7 +591,6 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) movefactor = secmovefac(rover->model) >> 1; } } -#endif } else if (var_friction && !(mo->flags & (MF_NOCLIP | MF_NOGRAVITY))) { // When the object is straddling sectors with the same @@ -605,7 +601,6 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) { sec = m->m_sector; -#ifdef _3DFLOORS // 3D floors must be checked, too for (unsigned i = 0; i < sec->e->XFloor.ffloors.Size(); i++) { @@ -634,7 +629,6 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) movefactor = secmovefac(rover->model); } } -#endif if (!(sec->special & FRICTION_MASK) && Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0) @@ -789,14 +783,9 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) !(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) { secplane_t frontplane, backplane; -#ifdef _3DFLOORS // Check 3D floors as well frontplane = P_FindFloorPlane(ld->frontsector, tm.thing->x, tm.thing->y, tm.thing->floorz); backplane = P_FindFloorPlane(ld->backsector, tm.thing->x, tm.thing->y, tm.thing->floorz); -#else - frontplane = ld->frontsector->floorplane; - backplane = ld->backsector->floorplane; -#endif if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE) { const msecnode_t *node = tm.thing->touching_sectorlist; @@ -1457,7 +1446,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo //Added by MC: Fill the tmsector. tm.sector = newsec; -#ifdef _3DFLOORS //Check 3D floors if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size()) { @@ -1489,7 +1477,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo } } } -#endif validcount++; spechit.Clear(); @@ -1806,7 +1793,6 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo fzb <= mobj->z && bzb <= mobj->z) { // we must also check if some 3D floor in the backsector may be blocking -#ifdef _3DFLOORS for (unsigned int i = 0; ibacksector->e->XFloor.ffloors.Size(); i++) { F3DFloor* rover = line->backsector->e->XFloor.ffloors[i]; @@ -1821,7 +1807,6 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo goto isblocking; } } -#endif return; } } @@ -2746,7 +2731,6 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov const secplane_t *plane = &actor->floorsector->floorplane; fixed_t planezhere = plane->ZatPoint(actor->x, actor->y); -#ifdef _3DFLOORS for (unsigned int i = 0; ifloorsector->e->XFloor.ffloors.Size(); i++) { F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i]; @@ -2781,7 +2765,6 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov } } } -#endif if (actor->floorsector != actor->Sector) { @@ -3159,7 +3142,6 @@ struct aim_t AActor * thing_friend, *thing_other; angle_t pitch_friend, pitch_other; int flags; -#ifdef _3DFLOORS sector_t * lastsector; secplane_t * lastfloorplane; secplane_t * lastceilingplane; @@ -3167,13 +3149,11 @@ struct aim_t bool crossedffloors; bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in); -#endif void AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target = NULL); }; -#ifdef _3DFLOORS //============================================================================ // // AimTraverse3DFloors @@ -3275,7 +3255,6 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in) lastfloorplane = nextbottomplane; return true; } -#endif //============================================================================ // @@ -3328,9 +3307,7 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en if (toppitch >= bottompitch) return; // stop -#ifdef _3DFLOORS if (!AimTraverse3DFloors(it.Trace(), in)) return; -#endif continue; // shot continues } @@ -3369,7 +3346,6 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en continue; } -#ifdef _3DFLOORS // we must do one last check whether the trace has crossed a 3D floor if (lastsector == th->Sector && th->Sector->e->XFloor.ffloors.Size()) { @@ -3394,7 +3370,6 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en } } } -#endif // check angles to see if the thing can be aimed at @@ -3408,7 +3383,6 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en if (thingbottompitch < toppitch) continue; // shot under the thing -#ifdef _3DFLOORS if (crossedffloors) { // if 3D floors were in the way do an extra visibility check for safety @@ -3427,7 +3401,6 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en else return; } } -#endif // this thing can be hit! if (thingtoppitch < toppitch) @@ -3564,7 +3537,6 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL // Information for tracking crossed 3D floors aim.aimpitch = t1->pitch; -#ifdef _3DFLOORS aim.crossedffloors = t1->Sector->e->XFloor.ffloors.Size() != 0; aim.lastsector = t1->Sector; aim.lastfloorplane = aim.lastceilingplane = NULL; @@ -3580,7 +3552,6 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL bottomz = rover->top.plane->ZatPoint(t1->x, t1->y); if (bottomz <= t1->z) aim.lastfloorplane = rover->top.plane; } -#endif aim.AimTraverse(t1->x, t1->y, x2, y2, target); @@ -5456,7 +5427,6 @@ bool P_ChangeSector(sector_t *sector, int crunch, int amt, int floorOrCeil, bool cpos.movemidtex = false; cpos.sector = sector; -#ifdef _3DFLOORS // Also process all sectors that have 3D floors transferred from the // changed sector. if (sector->e->XFloor.attached.Size()) @@ -5504,8 +5474,6 @@ bool P_ChangeSector(sector_t *sector, int crunch, int amt, int floorOrCeil, bool } } P_Recalculate3DFloors(sector); // Must recalculate the 3d floor and light lists -#endif - // [RH] Use different functions for the four different types of sector // movement. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b0fc0d08e..267e71bb9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1316,7 +1316,6 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) z = mo->z; F3DFloor * ffloor=NULL; -#ifdef _3DFLOORS if (line->sidedef[side^1] != NULL) { sector_t * backsector = line->sidedef[side^1]->sector; @@ -1336,7 +1335,6 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) } } } -#endif DImpactDecal::StaticCreate (base->GetDecal (), x, y, z, line->sidedef[side], ffloor); @@ -2164,7 +2162,6 @@ explode: { if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded { -#ifdef _3DFLOORS unsigned i; for(i=0;iSector->e->XFloor.ffloors.Size();i++) { @@ -2175,7 +2172,6 @@ explode: if (rover->flags&FF_SOLID && rover->top.plane->ZatPoint(mo->x,mo->y)==mo->floorz) break; } if (i==mo->Sector->e->XFloor.ffloors.Size()) -#endif return oldfloorz; } } @@ -3567,12 +3563,8 @@ void AActor::Tick () { secplane_t floorplane; -#ifdef _3DFLOORS // Check 3D floors as well floorplane = P_FindFloorPlane(floorsector, x, y, floorz); -#else - floorplane = floorsector->floorplane; -#endif if (floorplane.c < STEEPSLOPE && floorplane.ZatPoint (x, y) <= floorz) @@ -3889,7 +3881,6 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) reset = true; } } -#ifdef _3DFLOORS else { // Check 3D floors as well! @@ -3923,7 +3914,6 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) break; } } -#endif } // some additional checks to make deep sectors like Boom's splash without setting @@ -5371,7 +5361,6 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z } #endif -#ifdef _3DFLOORS for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) { F3DFloor * rover = sec->e->XFloor.ffloors[i]; @@ -5388,7 +5377,6 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z planez = rover->bottom.plane->ZatPoint(x, y); if (planez < z && !(planez < thing->floorz)) return false; } -#endif hsec = sec->GetHeightSec(); if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) { @@ -5398,9 +5386,7 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z { terrainnum = TerrainTypes[hsec->GetTexture(sector_t::floor)]; } -#ifdef _3DFLOORS foundone: -#endif int splashnum = Terrains[terrainnum].Splash; bool smallsplash = false; @@ -5503,7 +5489,6 @@ bool P_HitFloor (AActor *thing) break; } -#ifdef _3DFLOORS // Check 3D floors for(unsigned int i=0;im_sector->e->XFloor.ffloors.Size();i++) { @@ -5517,7 +5502,6 @@ bool P_HitFloor (AActor *thing) } } } -#endif } if (m == NULL || m->m_sector->GetHeightSec() != NULL) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index fb6b34b53..14b19348e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2519,7 +2519,6 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmaps } break; -#ifdef _3DFLOORS case Sector_Set3DFloor: if (msd->toptexture[0]=='#') { @@ -2534,7 +2533,6 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmaps SetTexture(sd, side_t::mid, msd->midtexture, missingtex); SetTexture(sd, side_t::bottom, msd->bottomtexture, missingtex); break; -#endif case TranslucentLine: // killough 4/11/98: apply translucency to 2s normal texture if (checktranmap) diff --git a/src/p_sight.cpp b/src/p_sight.cpp index ef4dfacd0..135698b8b 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -127,7 +127,6 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) if (topslope <= bottomslope) return false; // stop -#ifdef _3DFLOORS // now handle 3D-floors if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size()) { @@ -219,7 +218,6 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) lastztop= FixedMul (topslope, in->frac) + sightzstart; lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart; -#endif return true; // keep going } @@ -401,7 +399,6 @@ bool SightCheck::P_SightTraverseIntercepts () } } -#ifdef _3DFLOORS if (lastsector==seeingthing->Sector && lastsector->e->XFloor.ffloors.Size()) { // we must do one last check whether the trace has crossed a 3D floor in the last sector @@ -424,7 +421,6 @@ bool SightCheck::P_SightTraverseIntercepts () } } -#endif return true; // everything was traversed } @@ -453,7 +449,6 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ validcount++; intercepts.Clear (); -#ifdef _3DFLOORS // for FF_SEETHROUGH the following rule applies: // If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag // If the viewer is in an area with FF_SEETHROUGH he can only see into areas with this flag @@ -472,7 +467,6 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ break; } } -#endif if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 26852269a..07d23294b 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -104,7 +104,6 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, res.Crossed3DWater = NULL; */ -#ifdef _3DFLOORS // Do a 3D floor check in the starting sector TDeletingArray &ff = sector->e->XFloor.ffloors; @@ -174,7 +173,6 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, } } } -#endif // check for overflows and clip if necessary SQWORD xd = (SQWORD)x + ( ( SQWORD(vx) * SQWORD(maxDist) )>>16); @@ -257,7 +255,6 @@ bool FTraceInfo::TraceTraverse (int ptflags) fixed_t dist; // Deal with splashes in 3D floors -#ifdef _3DFLOORS if (CurSector->e->XFloor.ffloors.Size()) { for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) @@ -274,7 +271,6 @@ bool FTraceInfo::TraceTraverse (int ptflags) } } } -#endif if (in->isaline) { @@ -381,7 +377,6 @@ bool FTraceInfo::TraceTraverse (int ptflags) } else { // made it past the wall -#ifdef _3DFLOORS // check for 3D floors first if (entersector->e->XFloor.ffloors.Size()) { @@ -435,9 +430,6 @@ bool FTraceInfo::TraceTraverse (int ptflags) } } } -#endif - - Results->HitType = TRACE_HitNone; if (TraceFlags & TRACE_PCross) @@ -450,9 +442,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); } } -#ifdef _3DFLOORS cont: -#endif if (Results->HitType != TRACE_HitNone) { From 22005697931c89ea3406999e87c2430ec7227b9c Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 7 Jun 2015 11:31:53 +0300 Subject: [PATCH 008/335] Fixed build on OS X without FMODEx --- src/CMakeLists.txt | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af1f04f49..782e4bac0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1242,18 +1242,20 @@ if( APPLE ) LINK_FLAGS "-framework Carbon -framework Cocoa -framework IOKit -framework OpenGL" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" ) - # Fix fmod link so that it can be found in the app bundle. - find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) - find_program( INSTALL_NAME_TOOL install_name_tool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) - execute_process( COMMAND "${OTOOL}" -L "${FMOD_LIBRARY}" - COMMAND grep "libfmodex.dylib (compat" - COMMAND head -n1 - COMMAND awk "{print $1}" - OUTPUT_VARIABLE FMOD_LINK - OUTPUT_STRIP_TRAILING_WHITESPACE ) - add_custom_command( TARGET zdoom POST_BUILD - COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/libfmodex.dylib "$" - COMMENT "Relinking FMOD Ex" ) + if( NOT NO_FMOD ) + # Fix fmod link so that it can be found in the app bundle. + find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) + find_program( INSTALL_NAME_TOOL install_name_tool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) + execute_process( COMMAND "${OTOOL}" -L "${FMOD_LIBRARY}" + COMMAND grep "libfmodex.dylib (compat" + COMMAND head -n1 + COMMAND awk "{print $1}" + OUTPUT_VARIABLE FMOD_LINK + OUTPUT_STRIP_TRAILING_WHITESPACE ) + add_custom_command( TARGET zdoom POST_BUILD + COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/libfmodex.dylib "$" + COMMENT "Relinking FMOD Ex" ) + endif( NOT NO_FMOD ) endif( APPLE ) source_group("Assembly Files\\ia32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_ia32/.+") From 3b2126ba951be310d9cdef2a6053a5d2a314784b Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Tue, 9 Jun 2015 13:20:10 -0700 Subject: [PATCH 009/335] Don't allow pressing a checkswitchrange switch that's in the floor. --- src/p_switch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 5aeff7b46..6ea04593f 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -181,7 +181,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) } else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) { - return (user->z <= open.bottom); + return (user->z < open.bottom); } else if ((flags & ML_3DMIDTEX) || (TexMan.FindSwitch(side->GetTexture(side_t::mid))) != NULL) { @@ -194,7 +194,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) else { // no switch found. Check whether the player can touch either top or bottom texture - return (user->z + user->height >= open.top) || (user->z <= open.bottom); + return (user->z + user->height >= open.top) || (user->z < open.bottom); } } From 911b35370e28af78002cd28268a24e793895ede8 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Tue, 9 Jun 2015 13:41:48 -0700 Subject: [PATCH 010/335] Let's go wild and do it for the ceiling, too. --- src/p_switch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 6ea04593f..1ca4654b5 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -177,7 +177,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) if ((TexMan.FindSwitch(side->GetTexture(side_t::top))) != NULL) { - return (user->z + user->height >= open.top); + return (user->z + user->height > open.top); } else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) { @@ -194,7 +194,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) else { // no switch found. Check whether the player can touch either top or bottom texture - return (user->z + user->height >= open.top) || (user->z < open.bottom); + return (user->z + user->height > open.top) || (user->z < open.bottom); } } From 76c401a41ec655e83f0b375b1c61787fa8b13446 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 18 Jun 2015 10:20:04 +0200 Subject: [PATCH 011/335] - added 'nopushwindowcheck' for Hexen's MAP30 which abuses a glitch with a 'projectile impact' line on a two-sided wall. --- wadsrc/static/compatibility.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 3a675f275..26f43bb25 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -386,6 +386,7 @@ D62DCA9EC226DE49108D5DD9271F7631 // Cheogsh 2 map04 setthingz 1649 528 } +E89CCC7E155F1032F693359CC219BE6C // hexen.wad map30 B9DFF13207EACAC675C71D82624D0007 // XtheaterIII map01 { DisablePushWindowCheck From 85449a6b8a330b48dfa088a93f4242987ade19fd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 Jun 2015 13:04:47 +0200 Subject: [PATCH 012/335] - fixed: A_BFGSpray checked the spray actor's class for MTHRUSPECIES, not the actual shooter. --- src/g_doom/a_doomweaps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 6dbf3d1ec..899f1f7d5 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -624,7 +624,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) if (spray != NULL) { - if (spray->flags6 & MF6_MTHRUSPECIES && spray->GetSpecies() == linetarget->GetSpecies()) + if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == linetarget->GetSpecies()) { spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. continue; From 8670b7ecf79a91cd4d64025bb11393b8b931afb1 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 25 Jun 2015 12:53:46 +1200 Subject: [PATCH 013/335] Use puff decal with MF7_FORCEDECAL --- src/p_map.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 197525aa4..26312d922 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4275,11 +4275,16 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i // Spawn a decal or puff at the point where the trace ended. if (trace.HitType == TRACE_HitWall) { - SpawnShootDecal(source, trace); + AActor* puff = NULL; + if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); } + if (puff != NULL && puffDefaults->flags7 & MF7_FORCEDECAL && puff->DecalGenerator) + SpawnShootDecal(puff, trace); + else + SpawnShootDecal(source, trace); } if (thepuff != NULL) From 2a69ae2a434e00c2c5543ecd9b37dd3b5cb04aba Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 25 Jun 2015 13:57:36 +1200 Subject: [PATCH 014/335] Change all float calcs in rails to doubles --- src/p_effect.cpp | 50 +++++++++++++++---------------- src/p_effect.h | 2 +- src/p_enemy.cpp | 2 +- src/p_local.h | 2 +- src/p_map.cpp | 10 +++---- src/thingdef/thingdef_codeptr.cpp | 14 ++++----- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 1b7ce0bc8..db3129521 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -586,12 +586,12 @@ void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, i } } -void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff, int flags, const PClass *spawnclass, angle_t angle, int duration, float sparsity, float drift, int SpiralOffset) +void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff, int flags, const PClass *spawnclass, angle_t angle, int duration, double sparsity, double drift, int SpiralOffset) { double length, lengthsquared; int steps, i; - FAngle deg; - FVector3 step, dir, pos, extend; + TAngle deg; + TVector3 step, dir, pos, extend; bool fullbright; dir = end - start; @@ -615,9 +615,9 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end // The railgun's sound is special. It gets played from the // point on the slug's trail that is closest to the hearing player. AActor *mo = players[consoleplayer].camera; - FVector3 point; + TVector3 point; double r; - float dirz; + double dirz; if (abs(mo->x - FLOAT2FIXED(start.X)) < 20 * FRACUNIT && (mo->y - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT) @@ -630,7 +630,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end // Only consider sound in 2D (for now, anyway) // [BB] You have to divide by lengthsquared here, not multiply with it. - r = ((start.Y - FIXED2FLOAT(mo->y)) * (-dir.Y) - (start.X - FIXED2FLOAT(mo->x)) * (dir.X)) / lengthsquared; + r = ((start.Y - FIXED2DBL(mo->y)) * (-dir.Y) - (start.X - FIXED2DBL(mo->x)) * (dir.X)) / lengthsquared; r = clamp(r, 0., 1.); dirz = dir.Z; @@ -662,7 +662,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end minelem = fabs(dir[i]); } } - FVector3 tempvec(0,0,0); + TVector3 tempvec(0, 0, 0); tempvec[epos] = 1; extend = tempvec - (dir | tempvec) * dir; // @@ -673,16 +673,16 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end // Create the outer spiral. if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL)) { - FVector3 spiral_step = step * r_rail_spiralsparsity * sparsity; + TVector3 spiral_step = step * r_rail_spiralsparsity * sparsity; int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity); color1 = color1 == 0 ? -1 : ParticleColor(color1); pos = start; - deg = FAngle(SpiralOffset); + deg = TAngle(SpiralOffset); for (i = spiral_steps; i; i--) { particle_t *p = NewParticle (); - FVector3 tempvec; + TVector3 tempvec; if (!p) return; @@ -695,7 +695,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end p->size = 3; p->bright = fullbright; - tempvec = FMatrix3x3(dir, deg) * extend; + tempvec = TMatrix3x3(dir, deg) * extend; p->velx = FLOAT2FIXED(tempvec.X * drift)>>4; p->vely = FLOAT2FIXED(tempvec.Y * drift)>>4; p->velz = FLOAT2FIXED(tempvec.Z * drift)>>4; @@ -704,7 +704,7 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end p->y = FLOAT2FIXED(tempvec.Y); p->z = FLOAT2FIXED(tempvec.Z); pos += spiral_step; - deg += FAngle(r_rail_spiralsparsity * 14); + deg += TAngle(r_rail_spiralsparsity * 14); if (color1 == -1) { @@ -729,18 +729,18 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end // Create the inner trail. if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL) { - FVector3 trail_step = step * r_rail_trailsparsity * sparsity; + TVector3 trail_step = step * r_rail_trailsparsity * sparsity; int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity); color2 = color2 == 0 ? -1 : ParticleColor(color2); - FVector3 diff(0, 0, 0); + TVector3 diff(0, 0, 0); pos = start; for (i = trail_steps; i; i--) { // [XA] inner trail uses a different default duration (33). int innerduration = (duration == 0) ? 33 : duration; - particle_t *p = JitterParticle (innerduration, drift); + particle_t *p = JitterParticle (innerduration, (float)drift); if (!p) return; @@ -749,14 +749,14 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end { int rnd = M_Random (); if (rnd & 1) - diff.X = clamp (diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff); + diff.X = clamp(diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff); if (rnd & 2) - diff.Y = clamp (diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff); + diff.Y = clamp(diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff); if (rnd & 4) - diff.Z = clamp (diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff); + diff.Z = clamp(diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff); } - FVector3 postmp = pos + diff; + TVector3 postmp = pos + diff; p->size = 2; p->x = FLOAT2FIXED(postmp.X); @@ -791,9 +791,9 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end if (sparsity < 1) sparsity = 32; - FVector3 trail_step = (step / 3) * sparsity; + TVector3 trail_step = (step / 3) * sparsity; int trail_steps = (int)((steps * 3) / sparsity); - FVector3 diff(0, 0, 0); + TVector3 diff(0, 0, 0); pos = start; for (i = trail_steps; i; i--) @@ -802,13 +802,13 @@ void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end { int rnd = pr_railtrail(); if (rnd & 1) - diff.X = clamp (diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff); + diff.X = clamp(diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff); if (rnd & 2) - diff.Y = clamp (diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff); + diff.Y = clamp(diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff); if (rnd & 4) - diff.Z = clamp (diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff); + diff.Z = clamp(diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff); } - FVector3 postmp = pos + diff; + TVector3 postmp = pos + diff; AActor *thing = Spawn (spawnclass, FLOAT2FIXED(postmp.X), FLOAT2FIXED(postmp.Y), FLOAT2FIXED(postmp.Z), ALLOW_REPLACE); if (thing) diff --git a/src/p_effect.h b/src/p_effect.h index 6ca9dfea9..11116e8a3 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -88,7 +88,7 @@ void P_RunEffects (void); void P_RunEffect (AActor *actor, int effects); -void P_DrawRailTrail (AActor *source, const FVector3 &start, const FVector3 &end, int color1, int color2, float maxdiff = 0, int flags = 0, const PClass *spawnclass = NULL, angle_t angle = 0, int duration = 35, float sparsity = 1.0, float drift = 1.0, int SpiralOffset = 270); +void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, const PClass *spawnclass = NULL, angle_t angle = 0, int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270); void P_DrawSplash (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int kind); void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind); void P_DisconnectEffect (AActor *actor); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 10c4704d4..5291101a5 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2931,7 +2931,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) if (linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. - FVector2 xydiff(self->target->x - self->x, self->target->y - self->y); + TVector2 xydiff(self->target->x - self->x, self->target->y - self->y); double zdiff = (self->target->z + (self->target->height>>1)) - (self->z + (self->height>>1) - self->floorclip); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); diff --git a/src/p_local.h b/src/p_local.h index b62836c17..686e0ee13 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -475,7 +475,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); void P_CheckSplash(AActor *self, fixed_t distance); -void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, float maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags { diff --git a/src/p_map.cpp b/src/p_map.cpp index 26312d922..d5745523c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4150,12 +4150,12 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) // // //========================================================================== -void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, float maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, float sparsity, float drift, const PClass *spawnclass, int SpiralOffset) +void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, const PClass *spawnclass, int SpiralOffset) { fixed_t vx, vy, vz; angle_t angle, pitch; fixed_t x1, y1; - FVector3 start, end; + TVector3 start, end; FTraceResults trace; fixed_t shootz; @@ -4304,9 +4304,9 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } // Draw the slug's trail. - end.X = FIXED2FLOAT(trace.X); - end.Y = FIXED2FLOAT(trace.Y); - end.Z = FIXED2FLOAT(trace.Z); + end.X = FIXED2DBL(trace.X); + end.Y = FIXED2DBL(trace.Y); + end.Z = FIXED2DBL(trace.Z); P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift, SpiralOffset); } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 15d8291fc..54bbe68d3 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1502,14 +1502,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) ACTION_PARAM_COLOR(Color1, 3); ACTION_PARAM_COLOR(Color2, 4); ACTION_PARAM_INT(Flags, 5); - ACTION_PARAM_FLOAT(MaxDiff, 6); + ACTION_PARAM_DOUBLE(MaxDiff, 6); ACTION_PARAM_CLASS(PuffType, 7); ACTION_PARAM_ANGLE(Spread_XY, 8); ACTION_PARAM_ANGLE(Spread_Z, 9); ACTION_PARAM_FIXED(Range, 10); ACTION_PARAM_INT(Duration, 11); - ACTION_PARAM_FLOAT(Sparsity, 12); - ACTION_PARAM_FLOAT(DriftSpeed, 13); + ACTION_PARAM_DOUBLE(Sparsity, 12); + ACTION_PARAM_DOUBLE(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); ACTION_PARAM_FIXED(Spawnofs_Z, 15); ACTION_PARAM_INT(SpiralOffset, 16); @@ -1566,14 +1566,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) ACTION_PARAM_COLOR(Color2, 3); ACTION_PARAM_INT(Flags, 4); ACTION_PARAM_INT(aim, 5); - ACTION_PARAM_FLOAT(MaxDiff, 6); + ACTION_PARAM_DOUBLE(MaxDiff, 6); ACTION_PARAM_CLASS(PuffType, 7); ACTION_PARAM_ANGLE(Spread_XY, 8); ACTION_PARAM_ANGLE(Spread_Z, 9); ACTION_PARAM_FIXED(Range, 10); ACTION_PARAM_INT(Duration, 11); - ACTION_PARAM_FLOAT(Sparsity, 12); - ACTION_PARAM_FLOAT(DriftSpeed, 13); + ACTION_PARAM_DOUBLE(Sparsity, 12); + ACTION_PARAM_DOUBLE(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); ACTION_PARAM_FIXED(Spawnofs_Z, 15); ACTION_PARAM_INT(SpiralOffset, 16); @@ -1612,7 +1612,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (linetarget == NULL && aim) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. - FVector2 xydiff(self->target->x - self->x, self->target->y - self->y); + TVector2 xydiff(self->target->x - self->x, self->target->y - self->y); double zdiff = (self->target->z + (self->target->height>>1)) - (self->z + (self->height>>1) - self->floorclip); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); From 0fa0dc5f9e81c1b9acf3a720cc6921e958584410 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Jun 2015 13:01:48 -0500 Subject: [PATCH 015/335] Add support for alias parameter substitution in quoted strings - For backward compatibility, you need to indicate that substitution is allowed in the string by prepending it with a % character: alias asay "say %\"%1\"" The above will substitute the alias parameter. alias asay "say \"%1\"" The above will not substitute the alias parameter but use the string literal "%1" directly. --- src/c_dispatch.cpp | 60 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index d72993cb7..8ddd022e9 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -1076,7 +1076,8 @@ FString BuildString (int argc, FString *argv) // %x or %{x} in the command line with argument x. If argument x does not // exist, then the empty string is substituted in its place. // -// Substitution is not done inside of quoted strings. +// Substitution is not done inside of quoted strings, unless that string is +// prepended with a % character. // // To avoid a substitution, use %%. The %% will be replaced by a single %. // @@ -1091,19 +1092,12 @@ FString SubstituteAliasParams (FString &command, FCommandLine &args) char *p = command.LockBuffer(), *start = p; unsigned long argnum; FString buf; + bool inquote = false; while (*p != '\0') { - if (*p == '%' && ((p[1] >= '0' && p[1] <= '9') || p[1] == '{' || p[1] == '%')) + if (p[0] == '%' && ((p[1] >= '0' && p[1] <= '9') || p[1] == '{')) { - if (p[1] == '%') - { - // Do not substitute. Just collapse to a single %. - buf.AppendCStrPart (start, p - start + 1); - start = p = p + 2; - continue; - } - // Do a substitution. Output what came before this. buf.AppendCStrPart (start, p - start); @@ -1115,14 +1109,50 @@ FString SubstituteAliasParams (FString &command, FCommandLine &args) } p = (start += (p[1] == '{' && *start == '}')); } - else if (*p == '"') + else if (p[0] == '%' && p[1] == '%') { - // Don't substitute inside quoted strings. - p++; - while (*p != '\0' && (*p != '"' || *(p-1) == '\\')) + // Do not substitute. Just collapse to a single %. + buf.AppendCStrPart (start, p - start + 1); + start = p = p + 2; + continue; + } + else if (p[0] == '%' && p[1] == '"') + { + // Collapse %" to " and remember that we're in a quote so when we + // see a " character again, we don't start skipping below. + if (!inquote) + { + inquote = true; + buf.AppendCStrPart(start, p - start); + start = p + 1; + } + else + { + inquote = false; + } + p += 2; + } + else if (p[0] == '\\' && p[1] == '"') + { + p += 2; + } + else if (p[0] == '"') + { + // Don't substitute inside quoted strings if it didn't start + // with a %" + if (!inquote) + { p++; - if (*p != '\0') + while (*p != '\0' && (*p != '"' || *(p-1) == '\\')) + p++; + if (*p != '\0') + p++; + } + else + { + inquote = false; p++; + } } else { From 9edf409ea21794195e223b6afbdf148c14395453 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Jun 2015 13:11:33 -0500 Subject: [PATCH 016/335] Add British English "translation", because u's matter --- wadsrc/static/language.eng | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 wadsrc/static/language.eng diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng new file mode 100644 index 000000000..172cd2b4f --- /dev/null +++ b/wadsrc/static/language.eng @@ -0,0 +1,25 @@ +/* British English */ + +[eng] + +GOTARMOR = "Picked up the armour."; +GOTMEGA = "Picked up the MegaArmour!"; +GOTARMBONUS = "Picked up an armour bonus."; + +SCORE_COLOR = "COLOUR"; + +TAG_SHADOWARMOR = "Shadow Armour"; +TAG_METALARMOR = "Metal Armour"; +TAG_LEATHER = "Leather Armour"; +TAG_ARMORER = "Armourer"; + +TXT_ARMOR1 = "MESH ARMOUR"; + +TXT_METALARMOR = "You picked up the Metal Armour."; +TXT_LEATHERARMOR = "You picked up the Leather Armour."; +TXT_SHADOWARMOR = "You picked up the Shadow armour."; + +GOTCHEXARMOR = "Picked up the Chex(R) Armour."; +GOTSUPERCHEXARMOR = "Picked up the Super Chex(R) Armour!"; + +OB_BIPEDICUS2 = "%o was slimed by an armoured bipedicus."; From 3adda344b6178f78e28df0eb35beb6601b08f7ce Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 6 Jul 2015 02:58:01 -0400 Subject: [PATCH 017/335] - Missing common resolution 1680x1050 added to resolution list of SDL and Cocoa. --- src/posix/cocoa/i_video.mm | 1 + src/posix/sdl/sdlvideo.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 29e6bf4d4..410a106f5 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -339,6 +339,7 @@ VideoModes[] = { 1600, 900 }, // 16:9 { 1600, 1000 }, // 16:10 { 1600, 1200 }, + { 1680, 1050 }, // 16:10 { 1920, 1080 }, { 1920, 1200 }, { 2048, 1536 }, diff --git a/src/posix/sdl/sdlvideo.cpp b/src/posix/sdl/sdlvideo.cpp index 76191e1a9..9da52c2dd 100644 --- a/src/posix/sdl/sdlvideo.cpp +++ b/src/posix/sdl/sdlvideo.cpp @@ -178,6 +178,7 @@ static MiniModeInfo WinModes[] = { 1600, 900 }, // 16:9 { 1600, 1000 }, // 16:10 { 1600, 1200 }, + { 1680, 1050 }, // 16:10 { 1920, 1080 }, { 1920, 1200 }, { 2048, 1536 }, From 9e1a82a83046178bc0509e07caf9667b3ad6e057 Mon Sep 17 00:00:00 2001 From: Marrub Date: Fri, 10 Jul 2015 08:45:15 +0000 Subject: [PATCH 018/335] fix menus muting themselves when the volume is changed --- src/sound/oalsound.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 447de49f9..662e426e6 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -924,6 +924,8 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) schan = schan->NextChan; } + alProcessUpdatesSOFT(); + getALError(); } From eeaea59828d4522b3e24272f5de0a0d1d2a34c12 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 13 Jul 2015 08:42:42 +0200 Subject: [PATCH 019/335] - fixed: FTagManager::RemoveSectorTags must check if the StartForSector array is large enough to contain the sector whose information is to be removed. --- src/p_tags.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tags.cpp b/src/p_tags.cpp index c08caec8f..99796e269 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -98,7 +98,7 @@ void FTagManager::AddSectorTag(int sector, int tag) void FTagManager::RemoveSectorTags(int sect) { - if (startForSector.Size() > 0) + if (startForSector.Size() > sect) { int start = startForSector[sect]; if (start >= 0) From fe2e293d026a2eafd9393ace445fdf1452cdbc44 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 13 Jul 2015 09:08:08 +0200 Subject: [PATCH 020/335] - added some error checks for trying to create unsupported animations for textures with full path names. --- src/textures/animations.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index 0290a293f..b9f4382a6 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -395,6 +395,11 @@ void FTextureManager::ParseAnim (FScanner &sc, int usetype) } else if (sc.Compare ("range")) { + if (picnum.Exists() && Texture(picnum)->Name.IsEmpty()) + { + // long texture name: We cannot do ranged anims on these because they have no defined order + sc.ScriptError ("You cannot use \"range\" for long texture names."); + } if (defined == 2) { sc.ScriptError ("You cannot use \"pic\" and \"range\" together in a single animation."); @@ -456,12 +461,20 @@ FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, int type = FAnimDef::ANIM_Forward; framenum = ParseFramenum (sc, picnum, usetype, missing); + ParseTime (sc, min, max); - if (framenum == picnum || !picnum.Exists()) + if (framenum == picnum || !picnum.Exists() || !framenum.Exists()) { return NULL; // Animation is only one frame or does not exist } + + if (Texture(framenum)->Name.IsEmpty()) + { + // long texture name: We cannot do ranged anims on these because they have no defined order + sc.ScriptError ("You cannot use \"range\" for long texture names."); + } + if (framenum < picnum) { type = FAnimDef::ANIM_Backward; @@ -570,7 +583,7 @@ void FTextureManager::ParseTime (FScanner &sc, DWORD &min, DWORD &max) void FTextureManager::ParseWarp(FScanner &sc) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny | TEXMAN_ShortNameOnly; + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; bool isflat = false; bool type2 = sc.Compare ("warp2"); // [GRB] sc.MustGetString (); @@ -591,8 +604,16 @@ void FTextureManager::ParseWarp(FScanner &sc) FTextureID picnum = CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); if (picnum.isValid()) { + FTexture *warper = Texture(picnum); + if (warper->Name.IsEmpty()) + { + // long texture name: We cannot do warps on these due to the way the texture manager implements warping as a texture replacement. + sc.ScriptError ("You cannot use \"warp\" for long texture names."); + } + + // don't warp a texture more than once if (!warper->bWarped) { From 585366f8720256019d8da801717e8e56f9de00d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 09:08:15 +0200 Subject: [PATCH 021/335] - fixed signedness warning. --- src/p_tags.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 99796e269..15528378b 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -98,7 +98,7 @@ void FTagManager::AddSectorTag(int sector, int tag) void FTagManager::RemoveSectorTags(int sect) { - if (startForSector.Size() > sect) + if (startForSector.Size() > (unsigned int)sect) { int start = startForSector[sect]; if (start >= 0) From b5033d29401d4f53d8ee5216d82ecec3c7b5d3a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 09:11:08 +0200 Subject: [PATCH 022/335] - fixed a bad check from pull request #325. --- src/g_mapinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 5a39d7dbb..49493667e 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -318,7 +318,7 @@ FString level_info_t::LookupLevelName() checkstring[0] = '\0'; } thename = strstr (lookedup, checkstring); - if (thename == NULL || thename == lookedup) + if (thename == NULL) { thename = lookedup; } From 19d15d7fc8c9b0aef52db971a24e421aebfd8e31 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 09:25:04 +0200 Subject: [PATCH 023/335] - fixed: Levels could be exited multiple times, triggering special exit actions for each one. --- src/g_level.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/g_level.cpp b/src/g_level.cpp index 713205f6f..899f96d4f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -533,6 +533,10 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill Printf (TEXTCOLOR_RED "Unloading scripts cannot exit the level again.\n"); return; } + if (gameaction == ga_completed) // do not exit multiple times. + { + return; + } if (levelname == NULL || *levelname == 0) { From 1e4bec25c530f197baa730046bb3e6a536bcaf4e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 10:15:12 +0200 Subject: [PATCH 024/335] - fixed the distance check for unblocking overlapping monsters. It tested for half the radius as distance threshold when it should have used the full radius --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index d5745523c..fca43c120 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1064,8 +1064,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { unblocking = true; } - else if (abs(thing->x - tm.thing->x) < (thing->radius+tm.thing->radius)/2 && - abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)/2) + else if (abs(thing->x - tm.thing->x) < (thing->radius+tm.thing->radius) && + abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)) { fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y); From c677dd37f5ee02d126244f1d15f5854b64edb885 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 12:53:58 +0200 Subject: [PATCH 025/335] - changed I_PrintStr so that it doesn't add everything to the RichEdit control right away. The RichEdit control can become quite slow with large amounts of text being added constantly. Since anything that gets added while the game is running can't be seen anyway unless a fatal error is produced, it buffers the text locally now, without any processing, and only adds it to the RichEdit control in case a fatal error causes the control to be displayed again. --- src/win32/i_main.cpp | 5 +++++ src/win32/i_system.cpp | 30 +++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index ea167428f..8b6521ad5 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -106,6 +106,7 @@ LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); void CreateCrashLog (char *custominfo, DWORD customsize, HWND richedit); void DisplayCrashLog (); extern BYTE *ST_Util_BitsForBitmap (BITMAPINFO *bitmap_info); +void I_FlushBufferedConsoleStuff(); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -128,6 +129,7 @@ HANDLE MainThread; DWORD MainThreadID; HANDLE StdOut; bool FancyStdOut, AttachedStdOut; +bool ConWindowHidden; // The main window HWND Window; @@ -644,6 +646,7 @@ void I_SetWndProc() SetWindowLongPtr (Window, GWLP_USERDATA, 1); SetWindowLongPtr (Window, GWLP_WNDPROC, (WLONG_PTR)WndProc); ShowWindow (ConWindow, SW_HIDE); + ConWindowHidden = true; ShowWindow (GameTitleWindow, SW_HIDE); I_InitInput (Window); } @@ -675,8 +678,10 @@ void RestoreConView() SetWindowLongPtr (Window, GWLP_WNDPROC, (WLONG_PTR)LConProc); ShowWindow (ConWindow, SW_SHOW); + ConWindowHidden = false; ShowWindow (GameTitleWindow, SW_SHOW); I_ShutdownInput (); // Make sure the mouse pointer is available. + I_FlushBufferedConsoleStuff(); // Make sure the progress bar isn't visible. if (StartScreen != NULL) { diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 1d2bae8e1..6d8fb8595 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -132,6 +132,7 @@ extern bool FancyStdOut; extern HINSTANCE g_hInst; extern FILE *Logfile; extern bool NativeMouse; +extern bool ConWindowHidden; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -912,12 +913,11 @@ void ToEditControl(HWND edit, const char *buf, wchar_t *wbuf, int bpos) // //========================================================================== -void I_PrintStr(const char *cp) +static void DoPrintStr(const char *cp, HWND edit, HANDLE StdOut) { - if (ConWindow == NULL && StdOut == NULL) + if (edit == NULL && StdOut == NULL) return; - HWND edit = ConWindow; char buf[256]; wchar_t wbuf[countof(buf)]; int bpos = 0; @@ -1049,6 +1049,30 @@ void I_PrintStr(const char *cp) } } +static TArray bufferedConsoleStuff; + +void I_PrintStr(const char *cp) +{ + if (ConWindowHidden) + { + bufferedConsoleStuff.Push(cp); + DoPrintStr(cp, NULL, StdOut); + } + else + { + DoPrintStr(cp, ConWindow, StdOut); + } +} + +void I_FlushBufferedConsoleStuff() +{ + for (unsigned i = 0; i < bufferedConsoleStuff.Size(); i++) + { + DoPrintStr(bufferedConsoleStuff[i], ConWindow, NULL); + } + bufferedConsoleStuff.Clear(); +} + //========================================================================== // // SetQueryIWAD From 47303b26c76fda45aa5b64b6594fda6b0d2950d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 14:09:21 +0200 Subject: [PATCH 026/335] - define GET_XBUTTON_WPARAM for MinGW in all file which need it. --- src/win32/i_input.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index a26ff320e..941fc15de 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -110,6 +110,11 @@ #include "rawinput.h" +// Compensate for w32api's lack +#ifndef GET_XBUTTON_WPARAM +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) +#endif + #ifdef _DEBUG #define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS From add52d48cdd194c8b2d89fc486bd0eb13e8ee0d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Jul 2015 14:44:37 +0200 Subject: [PATCH 027/335] - fixed: INPUT_XInput must also be available when compiling without XInput support so that the corresponding JoyDevice can be accessed. --- src/win32/i_input.h | 17 +++++++++-------- src/win32/i_xinput.cpp | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/win32/i_input.h b/src/win32/i_input.h index b0d409844..c0de97e63 100644 --- a/src/win32/i_input.h +++ b/src/win32/i_input.h @@ -47,6 +47,15 @@ FString I_GetFromClipboard (bool windows_has_no_selection_clipboard); void I_GetEvent(); +enum +{ + INPUT_DIJoy, + INPUT_XInput, + INPUT_RawPS2, + NUM_JOYDEVICES +}; + + #ifdef USE_WINDOWS_DWORD #include "m_joy.h" @@ -121,14 +130,6 @@ public: virtual IJoystickConfig *Rescan() = 0; }; -enum -{ - INPUT_DIJoy, - INPUT_XInput, - INPUT_RawPS2, - NUM_JOYDEVICES -}; - extern FJoystickCollection *JoyDevices[NUM_JOYDEVICES]; void I_StartupMouse(); diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index 5a02d7af4..3d85f48a0 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -789,6 +789,8 @@ void I_StartupXInput() #else // NO_XINPUT +#include "i_input.h" + void I_StartupXInput() { JoyDevices[INPUT_XInput] = NULL; From 99683f0e7d63700d7ee49c1a4140b4cca76a1d8d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 16 Jul 2015 19:43:30 +0200 Subject: [PATCH 028/335] - Fixed a KEYCONF parser issue with empty lines. The code attempted to access an array outside its bounds when it tried to parse empty lines. Discovered with the Address Sanitizer. --- src/keysections.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/keysections.cpp b/src/keysections.cpp index 8d23c9582..1ae87958c 100644 --- a/src/keysections.cpp +++ b/src/keysections.cpp @@ -177,6 +177,11 @@ void D_LoadWadSettings () { cmd[i] = conf[i]; } + if (i == 0) + { + conf++; + continue; + } cmd[i] = 0; conf += i; if (*conf == '\n') From 1bd23150aa4a50bde99298aa9669505ab1f974fc Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 16 Jul 2015 19:46:54 +0200 Subject: [PATCH 029/335] - Fixed an uninitialized variable in stairs code. 'floor->m_Hexencrush' was left uninitialized in all the floor movers after the first one. --- src/p_floor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 97e23571b..9e7806039 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -727,6 +727,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, floor->m_Type = DFloor::buildStair; //jff 3/31/98 do not leave uninited //jff 2/27/98 fix uninitialized crush field floor->m_Crush = (!usespecials && speed == 4*FRACUNIT) ? 10 : -1; + floor->m_Hexencrush = false; floor->m_ResetCount = reset; // [RH] Tics until reset (0 if never) floor->m_OrgDist = sec->floorplane.d; // [RH] Height to reset to } From f57e23989be272512a02ecfb1f027a5646184b42 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 16 Jul 2015 19:54:27 +0200 Subject: [PATCH 030/335] - Fixed a dangerous typo in xs_Float code. The function 'xs_CeilToUInt' would call itself, leading to infinite loop, due to a typo. It should call 'xs_CeilToInt' instead. --- src/xs_Float.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xs_Float.h b/src/xs_Float.h index 19300b2fc..1f57f9205 100644 --- a/src/xs_Float.h +++ b/src/xs_Float.h @@ -209,7 +209,7 @@ finline static uint32 xs_FloorToUInt(real64 val) finline static uint32 xs_CeilToUInt(real64 val) { - return (uint32)xs_CeilToUInt(val); + return (uint32)xs_CeilToInt(val); } finline static uint32 xs_RoundToUInt(real64 val) From b4f05ee89bab28a12dc5377a6702c5a059e068e3 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 22 Jul 2015 16:46:14 -0500 Subject: [PATCH 031/335] - Significant A_RadiusGive update. - Added filter and species parameter. - Added new flags: RGF_INCLUSIVE, RGF_ITEMS, RGF_KILLED, RGF_EXFILTER, RGF_EXSPECIES, and RGF_EITHER. - RGF_ITEMS: Items can receive inventory. - RGF_KILLED: Actors who are truly dead might not be corpses, and vice versa. - RGF_EXFILTER: Blacklists the specified actor filter. All but the filtered actor can receive the item. - RGF_EXSPECIES: Blacklists the specified species. All but the filtered species can receive the item. - RGF_EITHER: The actor can receive the item if it satisfies either the filter or the species. Only useful when both are used. - RGF_INCLUSIVE: An actor marked as more than one pointer to the calling actor can ignore the exclusion pointers, but only if at least one is missing. I.e. an actor who is a target and tracer of the calling actor can still receive the item, if the calling actor doesn't pass RGF_NOTARGET and NOTRACER at the same time. RGF_INCLUSIVE only works with the pointer filtering flags. By default, if not specified, the actor will not be loopholed the item if they are under any one of the three filters. - Fixed discrepancies and dependencies upon several flags and actor conditions which caused the function to fail. --- src/thingdef/thingdef_codeptr.cpp | 221 +++++++++++++++-------------- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 6 + 3 files changed, 121 insertions(+), 108 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 54bbe68d3..d124a507d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4948,12 +4948,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) } +static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude) +{ + FName actorSpecies = mo->GetSpecies(); + if (filterSpecies == NAME_None) return true; + return exclude ? (actorSpecies != filterSpecies) : (actorSpecies == filterSpecies); +} + +static bool DoCheckClass(AActor *mo, const PClass *filterClass, bool exclude) +{ + const PClass *actorClass = mo->GetClass(); + if (filterClass == NULL) return true; + return exclude ? (actorClass != filterClass) : (actorClass == filterClass); +} //========================================================================== // -// A_RadiusGive +// A_RadiusGive(item, distance, flags, amount, filter, species) // // Uses code roughly similar to A_Explode (but without all the compatibility -// baggage and damage computation code to give an item to all eligible mobjs +// baggage and damage computation code) to give an item to all eligible mobjs // in range. // //========================================================================== @@ -4972,21 +4985,30 @@ enum RadiusGiveFlags RGF_CUBE = 1 << 9, RGF_NOSIGHT = 1 << 10, RGF_MISSILES = 1 << 11, + RGF_INCLUSIVE = 1 << 12, + RGF_ITEMS = 1 << 13, + RGF_KILLED = 1 << 14, + RGF_EXFILTER = 1 << 15, + RGF_EXSPECIES = 1 << 16, + RGF_EITHER = 1 << 17, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { - ACTION_PARAM_START(7); + ACTION_PARAM_START(6); ACTION_PARAM_CLASS(item, 0); ACTION_PARAM_FIXED(distance, 1); ACTION_PARAM_INT(flags, 2); ACTION_PARAM_INT(amount, 3); + ACTION_PARAM_CLASS(filter, 4); + ACTION_PARAM_NAME(species, 5); // We need a valid item, valid targets, and a valid range - if (item == NULL || (flags & RGF_MASK) == 0 || distance <= 0) + if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0) { return; } + if (amount == 0) { amount = 1; @@ -4997,108 +5019,107 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) AActor *thing; while ((thing = it.Next())) { - // Don't give to inventory items - if (thing->flags & MF_SPECIAL) + //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). + bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), + speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); + + if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass))) { - continue; - } - // Avoid giving to self unless requested - if (thing == self && !(flags & RGF_GIVESELF)) - { - continue; - } - // Avoiding special pointers if requested - if (((thing == self->target) && (flags & RGF_NOTARGET)) || - ((thing == self->tracer) && (flags & RGF_NOTRACER)) || - ((thing == self->master) && (flags & RGF_NOMASTER))) - { - continue; - } - // Don't give to dead thing unless requested - if (thing->flags & MF_CORPSE) - { - if (!(flags & RGF_CORPSES)) - { + if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. continue; - } - } - else if (thing->health <= 0 || thing->flags6 & MF6_KILLED) - { - continue; - } - // Players, monsters, and other shootable objects - if (thing->player) - { - if ((thing->player->mo == thing) && !(flags & RGF_PLAYERS)) - { - continue; - } - if ((thing->player->mo != thing) && !(flags & RGF_VOODOO)) - { - continue; - } - } - else if (thing->flags3 & MF3_ISMONSTER) - { - if (!(flags & RGF_MONSTERS)) - { - continue; - } - } - else if (thing->flags & MF_SHOOTABLE || thing->flags6 & MF6_VULNERABLE) - { - if (!(flags & RGF_OBJECTS)) - { - continue; - } - } - else if (thing->flags & MF_MISSILE) - { - if (!(flags & RGF_MISSILES)) - { - continue; - } - } - else - { - continue; } - if (flags & RGF_CUBE) - { // check if inside a cube - if (fabs((double)thing->x - self->x) > (double)distance || - fabs((double)thing->y - self->y) > (double)distance || - fabs((double)(thing->z + thing->height/2) - (self->z + self->height/2)) > (double)distance) - { + if (thing == self) + { + if (!(flags & RGF_GIVESELF)) continue; - } } - else - { // check if inside a sphere - TVector3 tpos(thing->x, thing->y, thing->z + thing->height/2); - TVector3 spos(self->x, self->y, self->z + self->height/2); - if ((tpos - spos).LengthSquared() > distsquared) - { + + //Check for target, master, and tracer flagging. + bool targetPass = true; + bool masterPass = true; + bool tracerPass = true; + bool ptrPass = false; + if ((thing != self) && (flags & (RGF_NOTARGET | RGF_NOMASTER | RGF_NOTRACER))) + { + if ((thing == self->target) && (flags & RGF_NOTARGET)) + targetPass = false; + if ((thing == self->master) && (flags & RGF_NOMASTER)) + masterPass = false; + if ((thing == self->tracer) && (flags & RGF_NOTRACER)) + tracerPass = false; + + ptrPass = (flags & RGF_INCLUSIVE) ? (targetPass || masterPass || tracerPass) : (targetPass && masterPass && tracerPass); + + //We should not care about what the actor is here. It's safe to abort this actor. + if (!ptrPass) continue; + } + + //Next, actor flag checking. + bool selfPass = !!((flags & RGF_GIVESELF) && thing == self); + bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); + bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); + bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); + bool objectPass = !!((flags & RGF_OBJECTS) && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); + bool playerPass = !!((flags & RGF_PLAYERS) && thing->player->mo == thing); + bool voodooPass = !!((flags & RGF_VOODOO) && thing->player->mo != thing); + //Self calls priority over the rest of this. + if (!selfPass) + { + //If it's specifically a monster/object/player/voodoo... Can be either or... + if (monsterPass || objectPass || playerPass || voodooPass) + { + //...and is dead, without desire to give to the dead... + if (((thing->health <= 0) && !(corpsePass || killedPass))) + { + //Skip! + continue; + } } } - if ((flags & RGF_NOSIGHT) || P_CheckSight (thing, self, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) - { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. - AInventory *gift = static_cast(Spawn (item, 0, 0, 0, NO_REPLACE)); - if (gift->IsKindOf(RUNTIME_CLASS(AHealth))) - { - gift->Amount *= amount; + bool itemPass = !!((flags & RGF_ITEMS) && thing->flags & MF_SPECIAL); + bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); + + if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) + { + if (flags & RGF_CUBE) + { // check if inside a cube + if (fabs((double)thing->x - self->x) > (double)distance || + fabs((double)thing->y - self->y) > (double)distance || + fabs((double)(thing->z + thing->height / 2) - (self->z + self->height / 2)) > (double)distance) + { + continue; + } } else - { - gift->Amount = amount; + { // check if inside a sphere + TVector3 tpos(thing->x, thing->y, thing->z + thing->height / 2); + TVector3 spos(self->x, self->y, self->z + self->height / 2); + if ((tpos - spos).LengthSquared() > distsquared) + { + continue; + } } - gift->flags |= MF_DROPPED; - gift->ClearCounters(); - if (!gift->CallTryPickup (thing)) - { - gift->Destroy (); + + if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) + { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. + AInventory *gift = static_cast(Spawn(item, 0, 0, 0, NO_REPLACE)); + if (gift->IsKindOf(RUNTIME_CLASS(AHealth))) + { + gift->Amount *= amount; + } + else + { + gift->Amount = amount; + } + gift->flags |= MF_DROPPED; + gift->ClearCounters(); + if (!gift->CallTryPickup(thing)) + { + gift->Destroy(); + } } } } @@ -5184,20 +5205,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) ref->Speed = speed; } -static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude) -{ - FName actorSpecies = mo->GetSpecies(); - if (filterSpecies == NAME_None) return true; - return exclude ? (actorSpecies != filterSpecies) : (actorSpecies == filterSpecies); -} - -static bool DoCheckClass(AActor *mo, const PClass *filterClass, bool exclude) -{ - const PClass *actorClass = mo->GetClass(); - if (filterClass == NULL) return true; - return exclude ? (actorClass != filterClass) : (actorClass == filterClass); -} - //=========================================================================== // // Common A_Damage handler diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b7fea4189..6885ad2d6 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -257,7 +257,7 @@ ACTOR Actor native //: Thinker action native A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); action native A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); action native A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0); + action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0, class filter = "None", name species = "None"); action native A_CountdownArg(int argnum, state targstate = ""); action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); action native A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 6612dd9f8..7aa23716f 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -224,6 +224,12 @@ enum RGF_CUBE = 1 << 9, RGF_NOSIGHT = 1 << 10, RGF_MISSILES = 1 << 11, + RGF_INCLUSIVE = 1 << 12, + RGF_ITEMS = 1 << 13, + RGF_KILLED = 1 << 14, + RGF_EXFILTER = 1 << 15, + RGF_EXSPECIES = 1 << 16, + RGF_EITHER = 1 << 17, }; // Activation flags From 41b4df71c26bb9e0287519042685de15cc863bc3 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 22 Jul 2015 17:12:42 -0500 Subject: [PATCH 032/335] Use IsKindOf instead of MF_SPECIAL to check for an inventory item. --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d124a507d..570557be8 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5079,7 +5079,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) } } - bool itemPass = !!((flags & RGF_ITEMS) && thing->flags & MF_SPECIAL); + bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) From ce1037af9547a8511f7f59ffbbf74a2066cecde0 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Fri, 24 Jul 2015 13:48:46 -0500 Subject: [PATCH 033/335] - Missing check for RGF_PLAYERS/VOODOO. --- src/thingdef/thingdef_codeptr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 570557be8..77205ba13 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5062,8 +5062,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); bool objectPass = !!((flags & RGF_OBJECTS) && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); - bool playerPass = !!((flags & RGF_PLAYERS) && thing->player->mo == thing); - bool voodooPass = !!((flags & RGF_VOODOO) && thing->player->mo != thing); + bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing)); + bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (thing->player->mo != thing)); //Self calls priority over the rest of this. if (!selfPass) { From 9319854590f0a1fdeed4f146ac6ac404349acfed Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 27 Jul 2015 12:20:32 -0500 Subject: [PATCH 034/335] Small bugfixes - Fixed a couple tiny bugs with A_ScaleVelocity and A_ChangeVelocity using self instead of ref. --- src/thingdef/thingdef_codeptr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 77205ba13..7435bc6fe 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4039,7 +4039,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) return; } - INTBOOL was_moving = self->velx | self->vely | self->velz; + INTBOOL was_moving = ref->velx | ref->vely | ref->velz; ref->velx = FixedMul(ref->velx, scale); ref->vely = FixedMul(ref->vely, scale); @@ -4061,7 +4061,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) { - ACTION_PARAM_START(4); + ACTION_PARAM_START(5); ACTION_PARAM_FIXED(x, 0); ACTION_PARAM_FIXED(y, 1); ACTION_PARAM_FIXED(z, 2); @@ -4102,7 +4102,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) if (was_moving) { - CheckStopped(self); + CheckStopped(ref); } } From cf43bd969d25abe594798085ffaa882b4d49331d Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Thu, 30 Jul 2015 16:56:54 +0930 Subject: [PATCH 035/335] Added Warp to ACS --- src/p_acs.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2cc9f958f..e63cfb087 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -132,6 +132,28 @@ enum ARMORINFO_ACTUALSAVEAMOUNT, }; +// [ZK] Warp +enum +{ + WARPF_ABSOLUTEOFFSET = 0x1, + WARPF_ABSOLUTEANGLE = 0x2, + WARPF_USECALLERANGLE = 0x4, + + WARPF_NOCHECKPOSITION = 0x8, + + WARPF_INTERPOLATE = 0x10, + WARPF_WARPINTERPOLATION = 0x20, + WARPF_COPYINTERPOLATION = 0x40, + + WARPF_STOP = 0x80, + WARPF_TOFLOOR = 0x100, + WARPF_TESTONLY = 0x200, + WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, + WARPF_USEPTR = 0x2000, +}; + struct CallReturn { CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway) @@ -4431,6 +4453,9 @@ enum EACSFunctions -105 : SetPlayerLivesLeft(2), -106 : KickFromGame(2), */ + + // GLOOME + ACSF_Warp = 11201, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -5848,6 +5873,166 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_GetActorRoll: actor = SingleActorFromTID(args[0], activator); return actor != NULL? actor->roll >> 16 : 0; + + // [ZK] A_Warp in ACS + case ACSF_Warp: + { + int tid_dest = args[0]; + fixed_t xofs = args[1]; + fixed_t yofs = args[2]; + fixed_t zofs = args[3]; + angle_t angle = args[4]; + int flags = args[5]; + const char *statename = argCount > 6 ? FBehavior::StaticLookupString(args[6]) : ""; + bool exact = argCount > 7 ? !!args[7] : false; + + FState *state = argCount > 6 ? activator->GetClass()->ActorInfo->FindStateByString(statename, exact) : 0; + + AActor *reference; + if((flags & WARPF_USEPTR) && tid_dest != AAPTR_DEFAULT) + { + reference = COPY_AAPTR(activator, tid_dest); + } + else + { + reference = SingleActorFromTID(tid_dest, activator); + } + + // If there is no actor to warp to, fail. + if (!reference) + return false; + + AActor *caller = activator; + + if (flags & WARPF_MOVEPTR) + { + AActor *temp = reference; + reference = caller; + caller = temp; + } + + fixed_t oldx = caller->x; + fixed_t oldy = caller->y; + fixed_t oldz = caller->z; + + if (!(flags & WARPF_ABSOLUTEANGLE)) + { + angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; + } + if (!(flags & WARPF_ABSOLUTEPOSITION)) + { + if (!(flags & WARPF_ABSOLUTEOFFSET)) + { + angle_t fineangle = angle >> ANGLETOFINESHIFT; + fixed_t xofs1 = xofs; + + // (borrowed from A_SpawnItemEx, assumed workable) + // in relative mode negative y values mean 'left' and positive ones mean 'right' + // This is the inverse orientation of the absolute mode! + + xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); + yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); + } + + if (flags & WARPF_TOFLOOR) + { + // set correct xy + + caller->SetOrigin( + reference->x + xofs, + reference->y + yofs, + reference->z); + + // now the caller's floorz should be appropriate for the assigned xy-position + // assigning position again with + + if (zofs) + { + // extra unlink, link and environment calculation + caller->SetOrigin( + caller->x, + caller->y, + caller->floorz + zofs); + } + else + { + // if there is no offset, there should be no ill effect from moving down to the already defined floor + + // A_Teleport does the same thing anyway + caller->z = caller->floorz; + } + } + else + { + caller->SetOrigin( + reference->x + xofs, + reference->y + yofs, + reference->z + zofs); + } + } + else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. + { + if (flags & WARPF_TOFLOOR) + { + caller->SetOrigin(xofs, yofs, caller->floorz + zofs); + } + else + { + caller->SetOrigin(xofs, yofs, zofs); + } + } + + if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) + { + if (flags & WARPF_TESTONLY) + { + caller->SetOrigin(oldx, oldy, oldz); + } + else + { + caller->angle = angle; + + if (flags & WARPF_STOP) + { + caller->velx = 0; + caller->vely = 0; + caller->velz = 0; + } + + if (flags & WARPF_WARPINTERPOLATION) + { + caller->PrevX += caller->x - oldx; + caller->PrevY += caller->y - oldy; + caller->PrevZ += caller->z - oldz; + } + else if (flags & WARPF_COPYINTERPOLATION) + { + caller->PrevX = caller->x + reference->PrevX - reference->x; + caller->PrevY = caller->y + reference->PrevY - reference->y; + caller->PrevZ = caller->z + reference->PrevZ - reference->z; + } + else if (flags & WARPF_INTERPOLATE) + { + caller->PrevX = caller->x; + caller->PrevY = caller->y; + caller->PrevZ = caller->z; + } + } + + if (state && argCount > 7) + { + activator->SetState(state); + } + + return true; + } + else + { + caller->SetOrigin(oldx, oldy, oldz); + return false; + } + break; + } default: break; From 701fc374f720d95ef9b1809092a81959712ab43f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 31 Jul 2015 08:40:33 +0200 Subject: [PATCH 036/335] - consolidated A_Warp and ACS Warp code into a subfunction. --- src/p_acs.cpp | 149 +----------------------------- src/p_local.h | 24 +++++ src/p_things.cpp | 127 +++++++++++++++++++++++++ src/thingdef/thingdef_codeptr.cpp | 145 +---------------------------- 4 files changed, 155 insertions(+), 290 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e63cfb087..1f56607e5 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -132,28 +132,6 @@ enum ARMORINFO_ACTUALSAVEAMOUNT, }; -// [ZK] Warp -enum -{ - WARPF_ABSOLUTEOFFSET = 0x1, - WARPF_ABSOLUTEANGLE = 0x2, - WARPF_USECALLERANGLE = 0x4, - - WARPF_NOCHECKPOSITION = 0x8, - - WARPF_INTERPOLATE = 0x10, - WARPF_WARPINTERPOLATION = 0x20, - WARPF_COPYINTERPOLATION = 0x40, - - WARPF_STOP = 0x80, - WARPF_TOFLOOR = 0x100, - WARPF_TESTONLY = 0x200, - WARPF_ABSOLUTEPOSITION = 0x400, - WARPF_BOB = 0x800, - WARPF_MOVEPTR = 0x1000, - WARPF_USEPTR = 0x2000, -}; - struct CallReturn { CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway) @@ -5902,136 +5880,15 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (!reference) return false; - AActor *caller = activator; - - if (flags & WARPF_MOVEPTR) + if (P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags)) { - AActor *temp = reference; - reference = caller; - caller = temp; - } - - fixed_t oldx = caller->x; - fixed_t oldy = caller->y; - fixed_t oldz = caller->z; - - if (!(flags & WARPF_ABSOLUTEANGLE)) - { - angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; - } - if (!(flags & WARPF_ABSOLUTEPOSITION)) - { - if (!(flags & WARPF_ABSOLUTEOFFSET)) - { - angle_t fineangle = angle >> ANGLETOFINESHIFT; - fixed_t xofs1 = xofs; - - // (borrowed from A_SpawnItemEx, assumed workable) - // in relative mode negative y values mean 'left' and positive ones mean 'right' - // This is the inverse orientation of the absolute mode! - - xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); - yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); - } - - if (flags & WARPF_TOFLOOR) - { - // set correct xy - - caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->z); - - // now the caller's floorz should be appropriate for the assigned xy-position - // assigning position again with - - if (zofs) - { - // extra unlink, link and environment calculation - caller->SetOrigin( - caller->x, - caller->y, - caller->floorz + zofs); - } - else - { - // if there is no offset, there should be no ill effect from moving down to the already defined floor - - // A_Teleport does the same thing anyway - caller->z = caller->floorz; - } - } - else - { - caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->z + zofs); - } - } - else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. - { - if (flags & WARPF_TOFLOOR) - { - caller->SetOrigin(xofs, yofs, caller->floorz + zofs); - } - else - { - caller->SetOrigin(xofs, yofs, zofs); - } - } - - if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) - { - if (flags & WARPF_TESTONLY) - { - caller->SetOrigin(oldx, oldy, oldz); - } - else - { - caller->angle = angle; - - if (flags & WARPF_STOP) - { - caller->velx = 0; - caller->vely = 0; - caller->velz = 0; - } - - if (flags & WARPF_WARPINTERPOLATION) - { - caller->PrevX += caller->x - oldx; - caller->PrevY += caller->y - oldy; - caller->PrevZ += caller->z - oldz; - } - else if (flags & WARPF_COPYINTERPOLATION) - { - caller->PrevX = caller->x + reference->PrevX - reference->x; - caller->PrevY = caller->y + reference->PrevY - reference->y; - caller->PrevZ = caller->z + reference->PrevZ - reference->z; - } - else if (flags & WARPF_INTERPOLATE) - { - caller->PrevX = caller->x; - caller->PrevY = caller->y; - caller->PrevZ = caller->z; - } - } - - if (state && argCount > 7) + if (state && argCount > 6) { activator->SetState(state); } - return true; } - else - { - caller->SetOrigin(oldx, oldy, oldz); - return false; - } - break; + return false; } default: diff --git a/src/p_local.h b/src/p_local.h index 686e0ee13..691d66245 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,6 +176,30 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_CanRaise(AActor *thing); const PClass *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags); + +enum WARPF +{ + WARPF_ABSOLUTEOFFSET = 0x1, + WARPF_ABSOLUTEANGLE = 0x2, + WARPF_USECALLERANGLE = 0x4, + + WARPF_NOCHECKPOSITION = 0x8, + + WARPF_INTERPOLATE = 0x10, + WARPF_WARPINTERPOLATION = 0x20, + WARPF_COPYINTERPOLATION = 0x40, + + WARPF_STOP = 0x80, + WARPF_TOFLOOR = 0x100, + WARPF_TESTONLY = 0x200, + WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, + WARPF_USEPTR = 0x2000, +}; + + // // P_MAPUTL diff --git a/src/p_things.cpp b/src/p_things.cpp index 632f53bc3..799e72893 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -678,3 +678,130 @@ void InitSpawnablesFromMapinfo() InitClassMap(SpawnableThings, SpawnablesFromMapinfo); InitClassMap(StrifeTypes, ConversationIDsFromMapinfo); } + + +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags) +{ + if (flags & WARPF_MOVEPTR) + { + AActor *temp = reference; + reference = caller; + caller = temp; + } + + fixed_t oldx = caller->x; + fixed_t oldy = caller->y; + fixed_t oldz = caller->z; + + if (!(flags & WARPF_ABSOLUTEANGLE)) + { + angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; + } + if (!(flags & WARPF_ABSOLUTEPOSITION)) + { + if (!(flags & WARPF_ABSOLUTEOFFSET)) + { + angle_t fineangle = angle >> ANGLETOFINESHIFT; + fixed_t xofs1 = xofs; + + // (borrowed from A_SpawnItemEx, assumed workable) + // in relative mode negative y values mean 'left' and positive ones mean 'right' + // This is the inverse orientation of the absolute mode! + + xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); + yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); + } + + if (flags & WARPF_TOFLOOR) + { + // set correct xy + + caller->SetOrigin( + reference->x + xofs, + reference->y + yofs, + reference->z); + + // now the caller's floorz should be appropriate for the assigned xy-position + // assigning position again with + + if (zofs) + { + // extra unlink, link and environment calculation + caller->SetOrigin( + caller->x, + caller->y, + caller->floorz + zofs); + } + else + { + // if there is no offset, there should be no ill effect from moving down to the already defined floor + + // A_Teleport does the same thing anyway + caller->z = caller->floorz; + } + } + else + { + caller->SetOrigin( + reference->x + xofs, + reference->y + yofs, + reference->z + zofs); + } + } + else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. + { + if (flags & WARPF_TOFLOOR) + { + caller->SetOrigin(xofs, yofs, caller->floorz + zofs); + } + else + { + caller->SetOrigin(xofs, yofs, zofs); + } + } + + if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) + { + if (flags & WARPF_TESTONLY) + { + caller->SetOrigin(oldx, oldy, oldz); + } + else + { + caller->angle = angle; + + if (flags & WARPF_STOP) + { + caller->velx = 0; + caller->vely = 0; + caller->velz = 0; + } + + if (flags & WARPF_WARPINTERPOLATION) + { + caller->PrevX += caller->x - oldx; + caller->PrevY += caller->y - oldy; + caller->PrevZ += caller->z - oldz; + } + else if (flags & WARPF_COPYINTERPOLATION) + { + caller->PrevX = caller->x + reference->PrevX - reference->x; + caller->PrevY = caller->y + reference->PrevY - reference->y; + caller->PrevZ = caller->z + reference->PrevZ - reference->z; + } + else if (!(flags & WARPF_INTERPOLATE)) + { + caller->PrevX = caller->x; + caller->PrevY = caller->y; + caller->PrevZ = caller->z; + } + if ((flags & WARPF_BOB) && (reference->flags2 & MF2_FLOATBOB)) + { + caller->z += reference->GetBobOffset(); + } + } + return true; + } + caller->SetOrigin(oldx, oldy, oldz); + return false; +} \ No newline at end of file diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7435bc6fe..733572a04 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4653,26 +4653,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // //========================================================================== -enum WARPF -{ - WARPF_ABSOLUTEOFFSET = 0x1, - WARPF_ABSOLUTEANGLE = 0x2, - WARPF_USECALLERANGLE = 0x4, - - WARPF_NOCHECKPOSITION = 0x8, - - WARPF_INTERPOLATE = 0x10, - WARPF_WARPINTERPOLATION = 0x20, - WARPF_COPYINTERPOLATION = 0x40, - - WARPF_STOP = 0x80, - WARPF_TOFLOOR = 0x100, - WARPF_TESTONLY = 0x200, - WARPF_ABSOLUTEPOSITION = 0x400, - WARPF_BOB = 0x800, - WARPF_MOVEPTR = 0x1000, -}; - DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { ACTION_PARAM_START(7); @@ -4694,130 +4674,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) return; } - AActor *caller = self; - - if (flags & WARPF_MOVEPTR) + if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags)) { - AActor *temp = reference; - reference = caller; - caller = temp; - } - - fixed_t oldx = caller->x; - fixed_t oldy = caller->y; - fixed_t oldz = caller->z; - - if (!(flags & WARPF_ABSOLUTEANGLE)) - { - angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; - } - if (!(flags & WARPF_ABSOLUTEPOSITION)) - { - if (!(flags & WARPF_ABSOLUTEOFFSET)) - { - angle_t fineangle = angle >> ANGLETOFINESHIFT; - fixed_t xofs1 = xofs; - - // (borrowed from A_SpawnItemEx, assumed workable) - // in relative mode negative y values mean 'left' and positive ones mean 'right' - // This is the inverse orientation of the absolute mode! - - xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); - yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); - } - - if (flags & WARPF_TOFLOOR) - { - // set correct xy - - caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->z); - - // now the caller's floorz should be appropriate for the assigned xy-position - // assigning position again with - - if (zofs) - { - // extra unlink, link and environment calculation - caller->SetOrigin( - caller->x, - caller->y, - caller->floorz + zofs); - } - else - { - // if there is no offset, there should be no ill effect from moving down to the - // already identified floor - - // A_Teleport does the same thing anyway - caller->z = caller->floorz; - } - } - else - { - caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->z + zofs); - } - } - else //[MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. - { - if (flags & WARPF_TOFLOOR) - { - caller->SetOrigin(xofs, yofs, caller->floorz + zofs); - } - else - { - caller->SetOrigin(xofs, yofs, zofs); - } - } - - if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) - { - if (flags & WARPF_TESTONLY) - { - caller->SetOrigin(oldx, oldy, oldz); - } - else - { - caller->angle = angle; - - if (flags & WARPF_STOP) - { - caller->velx = 0; - caller->vely = 0; - caller->velz = 0; - } - - if (flags & WARPF_WARPINTERPOLATION) - { - caller->PrevX += caller->x - oldx; - caller->PrevY += caller->y - oldy; - caller->PrevZ += caller->z - oldz; - } - else if (flags & WARPF_COPYINTERPOLATION) - { - caller->PrevX = caller->x + reference->PrevX - reference->x; - caller->PrevY = caller->y + reference->PrevY - reference->y; - caller->PrevZ = caller->z + reference->PrevZ - reference->z; - } - else if (!(flags & WARPF_INTERPOLATE)) - { - caller->PrevX = caller->x; - caller->PrevY = caller->y; - caller->PrevZ = caller->z; - } - - if ((flags & WARPF_BOB) && (reference->flags2 & MF2_FLOATBOB)) - { - caller->z += reference->GetBobOffset(); - } - } - - if (success_state) { ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -4830,7 +4688,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) } else { - caller->SetOrigin(oldx, oldy, oldz); ACTION_SET_RESULT(false); } From efce2a200c17e6e41d3e43d6da2a1b4e4b138452 Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Fri, 31 Jul 2015 22:24:01 +0930 Subject: [PATCH 037/335] Added WARPF_USETID to A_Warp --- src/p_local.h | 1 + src/thingdef/thingdef_codeptr.cpp | 13 +++++++++++-- wadsrc/static/actors/constants.txt | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 691d66245..0b1c9c7a8 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -197,6 +197,7 @@ enum WARPF WARPF_BOB = 0x800, WARPF_MOVEPTR = 0x1000, WARPF_USEPTR = 0x2000, + WARPF_USETID = 0x2000, }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 733572a04..e47f4148f 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4664,8 +4664,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) ACTION_PARAM_ANGLE(angle, 4); ACTION_PARAM_INT(flags, 5); ACTION_PARAM_STATE(success_state, 6); - - AActor *reference = COPY_AAPTR(self, destination_selector); + + AActor *reference; + + if((flags & WARPF_USETID)) + { + reference = SingleActorFromTID(destination_selector, self); + } + else + { + reference = COPY_AAPTR(self, destination_selector); + } //If there is no actor to warp to, fail. if (!reference) diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 7aa23716f..1ee6c96c9 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -357,6 +357,7 @@ Const Int WAPRF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_BOB = 0x800; Const Int WARPF_MOVEPTR = 0x1000; +Const Int WARPF_USETID = 0x2000; // flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; From 7163aa96678cbe12b5a8c2a11f0856b2a2c114c6 Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Fri, 31 Jul 2015 22:28:10 +0930 Subject: [PATCH 038/335] Moved Warp to the ZDoom range --- src/p_acs.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1f56607e5..750b8f09d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4422,6 +4422,8 @@ enum EACSFunctions ACSF_ChangeActorRoll, ACSF_GetActorRoll, ACSF_QuakeEx, + ACSF_Warp, // 92 + /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), -101 : PlayerIsSpectator(1), @@ -4431,9 +4433,6 @@ enum EACSFunctions -105 : SetPlayerLivesLeft(2), -106 : KickFromGame(2), */ - - // GLOOME - ACSF_Warp = 11201, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) From 2be19a87ba697b8969b0f3e0b97c9fec6d8ce826 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 31 Jul 2015 15:47:47 +0200 Subject: [PATCH 039/335] - fixed some bad boolean logic in fly cheat command. --- src/m_cheat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 170c65021..fe759215c 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -149,7 +149,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_FLY: if (player->mo != NULL) { - if ((player->mo->flags7 ^= MF7_FLYCHEAT) != 0) + if ((player->mo->flags7 ^= MF7_FLYCHEAT) == MF7_FLYCHEAT) { player->mo->flags |= MF_NOGRAVITY; player->mo->flags2 |= MF2_FLY; From 78c21bfb056263338f30e80878f84850dbc0e104 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 31 Jul 2015 15:49:47 +0200 Subject: [PATCH 040/335] - last commit was wrong (forgot to save my second change before committing. --- src/m_cheat.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index fe759215c..ab9c0aee7 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -149,7 +149,8 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_FLY: if (player->mo != NULL) { - if ((player->mo->flags7 ^= MF7_FLYCHEAT) == MF7_FLYCHEAT) + player->mo->flags7 ^= MF7_FLYCHEAT; + if (player->mo->flags7 & MF7_FLYCHEAT) { player->mo->flags |= MF_NOGRAVITY; player->mo->flags2 |= MF2_FLY; From 57150c8718612e8215df61ebeaff39d6d37c6481 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 Aug 2015 11:56:44 +0200 Subject: [PATCH 041/335] - fixed incorrect Strife player death sound. --- wadsrc/static/filter/game-strife/sndinfo.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/filter/game-strife/sndinfo.txt b/wadsrc/static/filter/game-strife/sndinfo.txt index 22f9b8356..f602a969b 100644 --- a/wadsrc/static/filter/game-strife/sndinfo.txt +++ b/wadsrc/static/filter/game-strife/sndinfo.txt @@ -8,7 +8,7 @@ $rolloff * 200 1200 $playersound player male *death dspldeth -$playersound player male *xdeath dspdiehi +$playersound player male *xdeath dsplxdth $playersound player male *gibbed dsslop $playersound player male *pain100 dsplpain $playersounddup player male *pain75 *pain100 From 58870d48718a23952ec4aa7be020c86589549f66 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 Aug 2015 23:17:06 +0200 Subject: [PATCH 042/335] - fixed: SingleActorFromTid wasn't declared in thingdef_codeptr.cpp --- src/p_acs.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 750b8f09d..83a087d8f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3595,7 +3595,7 @@ int DoGetMasterTID (AActor *self) else return 0; } -static AActor *SingleActorFromTID (int tid, AActor *defactor) +AActor *SingleActorFromTID (int tid, AActor *defactor) { if (tid == 0) { diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e47f4148f..2ba5fa01a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -73,6 +73,7 @@ #include "p_setup.h" #include "gstrings.h" +AActor *SingleActorFromTID (int tid, AActor *defactor); static FRandom pr_camissile ("CustomActorfire"); static FRandom pr_camelee ("CustomMelee"); From 3efbf6c74e551551dd28b7430a5e60a2048c661c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 9 Aug 2015 09:03:12 +0200 Subject: [PATCH 043/335] - fixed: am_restorecolors did not work This CCMD tried to access the current menu to decide which colors to reset but that is not available at all when this function gets called. It now uses the automap's own CVAR arrays. --- src/am_map.cpp | 14 ++++++++++++++ src/menu/optionmenuitems.h | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index fdbacd34f..045d48589 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -360,6 +360,20 @@ static FColorCVar *cv_overlay[] = { &am_ovsecretsectorcolor }; +CCMD(am_restorecolors) +{ + for (unsigned i = 0; i < countof(cv_standard); i++) + { + cv_standard[i]->ResetToDefault(); + } + for (unsigned i = 0; i < countof(cv_overlay); i++) + { + cv_overlay[i]->ResetToDefault(); + } +} + + + #define NOT_USED 1,0,0 // use almost black as indicator for an unused color static unsigned char DoomColors[]= { diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 5bc015369..e87e78483 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -1145,18 +1145,3 @@ private: float mMaximum; float mStep; }; -#ifndef NO_IMP -CCMD(am_restorecolors) -{ - if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DOptionMenu))) - { - DOptionMenu *m = (DOptionMenu*)DMenu::CurrentMenu; - const FOptionMenuDescriptor *desc = m->GetDescriptor(); - // Find the color cvars by scanning the MapColors menu. - for (unsigned i = 0; i < desc->mItems.Size(); ++i) - { - desc->mItems[i]->SetValue(FOptionMenuItemColorPicker::CPF_RESET, 0); - } - } -} -#endif From fcf1d56b1a239700920cd90f3bd431beed03583b Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 9 Aug 2015 14:06:22 -0500 Subject: [PATCH 044/335] - Added SXF_IS. - The spawned actor becomes the calling actor's specified pointers respectively. --- src/thingdef/thingdef_codeptr.cpp | 15 +++++++++++++++ wadsrc/static/actors/constants.txt | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 2ba5fa01a..69dd89cd0 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1857,6 +1857,9 @@ enum SIX_Flags SIXF_ORIGINATOR = 0x00800000, SIXF_TRANSFERSPRITEFRAME = 0x01000000, SIXF_TRANSFERROLL = 0x02000000, + SIXF_ISTARGET = 0x04000000, + SIXF_ISMASTER = 0x08000000, + SIXF_ISTRACER = 0x10000000, }; static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) @@ -2014,6 +2017,18 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) mo->roll = self->roll; } + if (flags & SIXF_ISTARGET) + { + self->target = mo; + } + if (flags & SIXF_ISMASTER) + { + self->master = mo; + } + if (flags & SIXF_ISTRACER) + { + self->tracer = mo; + } return true; } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 1ee6c96c9..96877a266 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -74,6 +74,9 @@ const int SXF_NOPOINTERS = 1 << 22; const int SXF_ORIGINATOR = 1 << 23; const int SXF_TRANSFERSPRITEFRAME = 1 << 24; const int SXF_TRANSFERROLL = 1 << 25; +const int SXF_ISTARGET = 1 << 26, +const int SXF_ISMASTER = 1 << 27, +const int SXF_ISTRACER = 1 << 28, // Flags for A_Chase const int CHF_FASTCHASE = 1; From e7aa5c690a4c5c653c363e8a2a6891f953b599f3 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 06:48:24 -0500 Subject: [PATCH 045/335] Minor oversight... --- wadsrc/static/actors/constants.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 96877a266..04ed6f1fc 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -74,9 +74,9 @@ const int SXF_NOPOINTERS = 1 << 22; const int SXF_ORIGINATOR = 1 << 23; const int SXF_TRANSFERSPRITEFRAME = 1 << 24; const int SXF_TRANSFERROLL = 1 << 25; -const int SXF_ISTARGET = 1 << 26, -const int SXF_ISMASTER = 1 << 27, -const int SXF_ISTRACER = 1 << 28, +const int SXF_ISTARGET = 1 << 26; +const int SXF_ISMASTER = 1 << 27; +const int SXF_ISTRACER = 1 << 28; // Flags for A_Chase const int CHF_FASTCHASE = 1; From ad14caa80026a1713377c050d77b1e7ef08dd2d7 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 11:19:54 -0500 Subject: [PATCH 046/335] - Added A_Warp heightoffset property. Only has an effect by two flags. - WARPF_ADDHEIGHT adds the pointed actor's height to heightoffset, and adds to the pointed actor's z position. - WARPF_MULHEIGHT multiplies the pointed actor's height by heightoffset, and adds to the pointed actor's z position. Overridden by ADDHEIGHT. --- src/p_acs.cpp | 3 ++- src/p_local.h | 4 +++- src/p_things.cpp | 18 ++++++++++++------ src/thingdef/thingdef_codeptr.cpp | 5 +++-- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 2 ++ 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 83a087d8f..b703b87dd 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5862,6 +5862,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) int flags = args[5]; const char *statename = argCount > 6 ? FBehavior::StaticLookupString(args[6]) : ""; bool exact = argCount > 7 ? !!args[7] : false; + fixed_t heightoffset = argCount > 8 ? args[8] : 0; FState *state = argCount > 6 ? activator->GetClass()->ActorInfo->FindStateByString(statename, exact) : 0; @@ -5879,7 +5880,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (!reference) return false; - if (P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags)) + if (P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags, heightoffset)) { if (state && argCount > 6) { diff --git a/src/p_local.h b/src/p_local.h index 0b1c9c7a8..6022d8e8e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,7 +176,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_CanRaise(AActor *thing); const PClass *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags); +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset); enum WARPF { @@ -198,6 +198,8 @@ enum WARPF WARPF_MOVEPTR = 0x1000, WARPF_USEPTR = 0x2000, WARPF_USETID = 0x2000, + WARPF_ADDHEIGHT = 0x4000, + WARPF_MULHEIGHT = 0x8000, }; diff --git a/src/p_things.cpp b/src/p_things.cpp index 799e72893..db80e35ca 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -680,7 +680,7 @@ void InitSpawnablesFromMapinfo() } -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags) +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset) { if (flags & WARPF_MOVEPTR) { @@ -692,6 +692,12 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t oldx = caller->x; fixed_t oldy = caller->y; fixed_t oldz = caller->z; + fixed_t height = 0; + + if (flags & WARPF_ADDHEIGHT) + height = reference->height + heightoffset; + else if (flags & WARPF_MULHEIGHT) + height = FixedMul(reference->height, heightoffset); if (!(flags & WARPF_ABSOLUTEANGLE)) { @@ -719,7 +725,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, caller->SetOrigin( reference->x + xofs, reference->y + yofs, - reference->z); + reference->z + height); // now the caller's floorz should be appropriate for the assigned xy-position // assigning position again with @@ -730,7 +736,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, caller->SetOrigin( caller->x, caller->y, - caller->floorz + zofs); + caller->floorz + zofs + height); } else { @@ -745,18 +751,18 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, caller->SetOrigin( reference->x + xofs, reference->y + yofs, - reference->z + zofs); + reference->z + zofs + height); } } else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. { if (flags & WARPF_TOFLOOR) { - caller->SetOrigin(xofs, yofs, caller->floorz + zofs); + caller->SetOrigin(xofs, yofs, caller->floorz + zofs + height); } else { - caller->SetOrigin(xofs, yofs, zofs); + caller->SetOrigin(xofs, yofs, zofs + height); } } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 69dd89cd0..5f863e746 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4671,7 +4671,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { - ACTION_PARAM_START(7); + ACTION_PARAM_START(8); ACTION_PARAM_INT(destination_selector, 0); ACTION_PARAM_FIXED(xofs, 1); @@ -4680,6 +4680,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) ACTION_PARAM_ANGLE(angle, 4); ACTION_PARAM_INT(flags, 5); ACTION_PARAM_STATE(success_state, 6); + ACTION_PARAM_FIXED(heightoffset,7) AActor *reference; @@ -4699,7 +4700,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) return; } - if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags)) + if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags, heightoffset)) { if (success_state) { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 6885ad2d6..00476b502 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -249,7 +249,7 @@ ACTOR Actor native //: Thinker action native A_PlayerSkinCheck(state label); action native A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT); - action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = ""); + action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0); action native A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); action native A_Weave(int xspeed, int yspeed, float xdist, float ydist); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 04ed6f1fc..a0c6f1f98 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -361,6 +361,8 @@ Const Int WARPF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_BOB = 0x800; Const Int WARPF_MOVEPTR = 0x1000; Const Int WARPF_USETID = 0x2000; +Const Int WARPF_ADDHEIGHT = 0x4000; +Const Int WARPF_MULHEIGHT = 0x8000; // flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; From 9cf8a2a26ca137196874763965dedb9a19584ea4 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 12:20:42 -0500 Subject: [PATCH 047/335] - Missed a spot. --- src/p_things.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index db80e35ca..6c8349a72 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -743,7 +743,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, // if there is no offset, there should be no ill effect from moving down to the already defined floor // A_Teleport does the same thing anyway - caller->z = caller->floorz; + caller->z = caller->floorz + height; } } else From 7e661dfe573c6101f7b0d215f12f5cd6d64f5c43 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 12:41:40 -0500 Subject: [PATCH 048/335] - Clean up. --- src/p_things.cpp | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index 6c8349a72..1467935d7 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -692,12 +692,16 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t oldx = caller->x; fixed_t oldy = caller->y; fixed_t oldz = caller->z; - fixed_t height = 0; + if (flags & WARPF_ADDHEIGHT) - height = reference->height + heightoffset; + { + zofs += reference->height + heightoffset; + } else if (flags & WARPF_MULHEIGHT) - height = FixedMul(reference->height, heightoffset); + { + zofs += FixedMul(reference->height, heightoffset); + } if (!(flags & WARPF_ABSOLUTEANGLE)) { @@ -725,44 +729,33 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, caller->SetOrigin( reference->x + xofs, reference->y + yofs, - reference->z + height); + reference->z); // now the caller's floorz should be appropriate for the assigned xy-position - // assigning position again with - - if (zofs) - { - // extra unlink, link and environment calculation - caller->SetOrigin( - caller->x, - caller->y, - caller->floorz + zofs + height); - } - else - { - // if there is no offset, there should be no ill effect from moving down to the already defined floor - - // A_Teleport does the same thing anyway - caller->z = caller->floorz + height; - } + // assigning position again with. + // extra unlink, link and environment calculation + caller->SetOrigin( + caller->x, + caller->y, + caller->floorz + zofs); } else { caller->SetOrigin( reference->x + xofs, reference->y + yofs, - reference->z + zofs + height); + reference->z + zofs); } } else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. { if (flags & WARPF_TOFLOOR) { - caller->SetOrigin(xofs, yofs, caller->floorz + zofs + height); + caller->SetOrigin(xofs, yofs, caller->floorz + zofs); } else { - caller->SetOrigin(xofs, yofs, zofs + height); + caller->SetOrigin(xofs, yofs, zofs); } } From 54af1e379edcc6a2f58034c06d0e406710adb570 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 15:03:29 -0500 Subject: [PATCH 049/335] - Removed WARPF_MULHEIGHT. Enable its ability by default. - WARPF_ADDHEIGHT will simply change HeightOffset from multiplying to adding by default. --- src/p_local.h | 1 - src/p_things.cpp | 2 +- wadsrc/static/actors/constants.txt | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 6022d8e8e..a457cd877 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -199,7 +199,6 @@ enum WARPF WARPF_USEPTR = 0x2000, WARPF_USETID = 0x2000, WARPF_ADDHEIGHT = 0x4000, - WARPF_MULHEIGHT = 0x8000, }; diff --git a/src/p_things.cpp b/src/p_things.cpp index 1467935d7..678608dc6 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -698,7 +698,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, { zofs += reference->height + heightoffset; } - else if (flags & WARPF_MULHEIGHT) + else { zofs += FixedMul(reference->height, heightoffset); } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index a0c6f1f98..b7baca73a 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -362,7 +362,6 @@ Const Int WARPF_BOB = 0x800; Const Int WARPF_MOVEPTR = 0x1000; Const Int WARPF_USETID = 0x2000; Const Int WARPF_ADDHEIGHT = 0x4000; -Const Int WARPF_MULHEIGHT = 0x8000; // flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; From 87cc3f77f9c7eccd247448c131b57ad9871bab4f Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 16:05:44 -0500 Subject: [PATCH 050/335] - Removed WARPF_ADDHEIGHT. --- src/p_local.h | 1 - src/p_things.cpp | 9 +-------- wadsrc/static/actors/constants.txt | 1 - 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index a457cd877..a2fa00c71 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -198,7 +198,6 @@ enum WARPF WARPF_MOVEPTR = 0x1000, WARPF_USEPTR = 0x2000, WARPF_USETID = 0x2000, - WARPF_ADDHEIGHT = 0x4000, }; diff --git a/src/p_things.cpp b/src/p_things.cpp index 678608dc6..f9d85c43f 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -693,15 +693,8 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t oldy = caller->y; fixed_t oldz = caller->z; + zofs += FixedMul(reference->height, heightoffset); - if (flags & WARPF_ADDHEIGHT) - { - zofs += reference->height + heightoffset; - } - else - { - zofs += FixedMul(reference->height, heightoffset); - } if (!(flags & WARPF_ABSOLUTEANGLE)) { diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index b7baca73a..04ed6f1fc 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -361,7 +361,6 @@ Const Int WARPF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_BOB = 0x800; Const Int WARPF_MOVEPTR = 0x1000; Const Int WARPF_USETID = 0x2000; -Const Int WARPF_ADDHEIGHT = 0x4000; // flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; From cac600733f8383c521e78555e79d25c2042de20e Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 10 Aug 2015 20:45:18 -0500 Subject: [PATCH 051/335] - Added Remove console command. --- src/d_net.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ src/d_protocol.h | 1 + src/p_interaction.cpp | 19 +++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/d_net.cpp b/src/d_net.cpp index bc5ccdba9..66b8c5dc3 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2082,6 +2082,33 @@ static int KillAll(const PClass *cls) } return killcount; +} + +static int RemoveClass(const PClass *cls) +{ + AActor *actor; + int removecount = 0; + bool player = false; + TThinkerIterator iterator(cls); + while ((actor = iterator.Next())) + { + if (actor->IsA(cls)) + { + // [MC]Do not remove LIVE players. + if (actor->IsKindOf(RUNTIME_CLASS(APlayerPawn)) && actor->player != NULL) + { + player = true; + continue; + } + removecount++; + actor->ClearCounters(); + actor->Destroy(); + } + } + if (player) + Printf("Cannot remove live players!\n"); + return removecount; + } // [RH] Execute a special "ticcmd". The type byte should // have already been read, and the stream is positioned @@ -2555,6 +2582,27 @@ void Net_DoCommand (int type, BYTE **stream, int player) } break; + case DEM_REMOVE: + { + char *classname = ReadString(stream); + int removecount = 0; + const PClass *cls = PClass::FindClass(classname); + if (cls != NULL && cls->ActorInfo != NULL) + { + removecount = RemoveClass(cls); + const PClass *cls_rep = cls->GetReplacement(); + if (cls != cls_rep) + { + removecount += RemoveClass(cls_rep); + } + Printf("Removed %d actors of type %s.\n", removecount, classname); + } + else + { + Printf("%s is not an actor class.\n", classname); + } + } + break; case DEM_CONVREPLY: case DEM_CONVCLOSE: diff --git a/src/d_protocol.h b/src/d_protocol.h index 8b6e777d5..73b042470 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -164,6 +164,7 @@ enum EDemoCommand DEM_RUNNAMEDSCRIPT, // 65 String: Script name, Byte: Arg count + Always flag; each arg is a 4-byte int DEM_REVERTCAMERA, // 66 DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT + DEM_REMOVE, // 68 }; // The following are implemented by cht_DoCheat in m_cheat.cpp diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index cbbd87978..276a88c75 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1841,3 +1841,22 @@ CCMD (kill) } C_HideConsole (); } + +CCMD(remove) +{ + if (argv.argc() == 2) + { + if (CheckCheatmode()) + return; + + Net_WriteByte(DEM_REMOVE); + Net_WriteString(argv[1]); + C_HideConsole(); + } + else + { + Printf("Usage: remove \n"); + return; + } + +} \ No newline at end of file From 9c24e9ac71abeb892d5ca47fff9d2093757b5349 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 11 Aug 2015 06:53:28 -0500 Subject: [PATCH 052/335] - Removed the check for APlayerPawn and just went with player checking alone. - Updated the savever, demogameversion, and mindemoversion. --- src/d_net.cpp | 3 ++- src/version.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 66b8c5dc3..e6b5713f2 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2095,7 +2095,7 @@ static int RemoveClass(const PClass *cls) if (actor->IsA(cls)) { // [MC]Do not remove LIVE players. - if (actor->IsKindOf(RUNTIME_CLASS(APlayerPawn)) && actor->player != NULL) + if (actor->player != NULL) { player = true; continue; @@ -2728,6 +2728,7 @@ void Net_SkipCommand (int type, BYTE **stream) case DEM_SUMMONFRIEND: case DEM_SUMMONFOE: case DEM_SUMMONMBF: + case DEM_REMOVE: case DEM_SPRAY: case DEM_MORPHEX: case DEM_KILLCLASSCHEAT: diff --git a/src/version.h b/src/version.h index 3d28dd2ac..913c9bd18 100644 --- a/src/version.h +++ b/src/version.h @@ -61,11 +61,11 @@ const char *GetVersionString(); // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. // Otherwise, it should be safe to leave it alone. -#define DEMOGAMEVERSION 0x21B +#define DEMOGAMEVERSION 0x21C // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. -#define MINDEMOVERSION 0x21B +#define MINDEMOVERSION 0x21C // SAVEVER is the version of the information stored in level snapshots. // Note that SAVEVER is not directly comparable to VERSION. @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4523 +#define SAVEVER 4524 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From b06770cb92d16c3b7a9cacbeba11c20968e48f1c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Aug 2015 17:12:16 +0200 Subject: [PATCH 053/335] - fixed: A_Respawn did not reset the actor's radius. --- src/thingdef/thingdef_codeptr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 69dd89cd0..d09ad6d6e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3017,6 +3017,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) fixed_t oldz = self->z; self->flags |= MF_SOLID; self->height = self->GetDefault()->height; + self->radius = self->GetDefault()->radius; CALL_ACTION(A_RestoreSpecialPosition, self); if (flags & RSF_TELEFRAG) From 2ed3cec4db39dfb6762830a09d4224aaf9969edc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Aug 2015 22:30:29 +0200 Subject: [PATCH 054/335] - externalized strings from Raven intermission screen. --- src/wi_stuff.cpp | 8 ++++---- wadsrc/static/language.enu | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 02492f272..8119d3802 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1959,9 +1959,9 @@ void WI_drawStats (void) } else { - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, "KILLS", DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, "ITEMS", DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, "SECRETS", DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); int countpos = gameinfo.gametype==GAME_Strife? 285:270; if (sp_state >= 2) @@ -1978,7 +1978,7 @@ void WI_drawStats (void) } if (sp_state >= 8) { - screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, "TIME", + screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); WI_drawTime (249, 160, cnt_time); if (wi_showtotaltime) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index a01a03559..bdefa1b86 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1281,6 +1281,14 @@ TXT_LEADBOOTSOFF = "LEAD BOOTS OFF"; TXT_LIGHTER = "You feel lighter"; TXT_GRAVITY = "Gravity weighs you down"; +// Raven intermission + +TXT_IMKILLS = "KILLS"; +TXT_IMITEMS = "ITEMS"; +TXT_IMSECRETS = "SECRETS"; +TXT_IMTIME = "TIME"; + + RAVENQUITMSG = "ARE YOU SURE YOU WANT TO QUIT?"; // Hexen strings From 2d58a28cc3feb559b7989698d88144309da7bc6a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 16 Aug 2015 08:50:22 +0200 Subject: [PATCH 055/335] - fixed: In Heretic an active Tome of Power should not freeze a teleporting player. This was implemented by adding a new inventory flag INVENTORY.NOTELEPORTFREEZE so that the effect can both be activated for other items and deactivated for the two that currently have it. --- src/g_shared/a_artifacts.cpp | 14 +++++++++++++- src/g_shared/a_artifacts.h | 1 + src/g_shared/a_pickups.cpp | 19 +++++++++++++++++++ src/g_shared/a_pickups.h | 2 ++ src/p_teleport.cpp | 2 +- src/thingdef/thingdef_data.cpp | 4 +++- wadsrc/static/actors/shared/inventory.txt | 2 ++ 7 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index bc33eb19c..2be2e179d 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -72,7 +72,7 @@ bool APowerupGiver::Use (bool pickup) power->Strength = Strength; } - power->ItemFlags |= ItemFlags & (IF_ALWAYSPICKUP|IF_ADDITIVETIME); + power->ItemFlags |= ItemFlags & (IF_ALWAYSPICKUP|IF_ADDITIVETIME|IF_NOTELEPORTFREEZE); if (power->CallTryPickup (Owner)) { return true; @@ -342,6 +342,18 @@ void APowerup::OwnerDied () Destroy (); } +//=========================================================================== +// +// AInventory :: GetNoTeleportFreeze +// +//=========================================================================== + +bool APowerup::GetNoTeleportFreeze () +{ + if (ItemFlags & IF_NOTELEPORTFREEZE) return true; + return Super::GetNoTeleportFreeze(); +} + // Invulnerability Powerup --------------------------------------------------- IMPLEMENT_CLASS (APowerInvulnerable) diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 4e1823f5a..c16a7a0c1 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -18,6 +18,7 @@ public: virtual AInventory *CreateTossable (); virtual void Serialize (FArchive &arc); virtual void OwnerDied (); + virtual bool GetNoTeleportFreeze(); virtual PalEntry GetBlend (); virtual bool DrawPowerup (int x, int y); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 038b63029..5d494c935 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -850,6 +850,25 @@ fixed_t AInventory::GetSpeedFactor () } } +//=========================================================================== +// +// AInventory :: GetNoTeleportFreeze +// +//=========================================================================== + +bool AInventory::GetNoTeleportFreeze () +{ + // do not check the flag here because it's only active when used on PowerUps, not on PowerupGivers. + if (Inventory != NULL) + { + return Inventory->GetNoTeleportFreeze(); + } + else + { + return false; + } +} + //=========================================================================== // // AInventory :: AlterWeaponSprite diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 504a26c73..74b10206b 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -137,6 +137,7 @@ enum IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop) IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper + IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting. }; @@ -201,6 +202,7 @@ public: virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); virtual fixed_t GetSpeedFactor(); + virtual bool GetNoTeleportFreeze(); virtual int AlterWeaponSprite (visstyle_t *vis); virtual PalEntry GetBlend (); diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 82359f4e0..040aca9f4 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -211,7 +211,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, if (thing->player && (useFog || !keepOrientation) && bHaltVelocity) { // Freeze player for about .5 sec - if (thing->Inventory == NULL || thing->Inventory->GetSpeedFactor() <= FRACUNIT) + if (thing->Inventory == NULL || !thing->Inventory->GetNoTeleportFreeze()) thing->reactiontime = 18; } if (thing->flags & MF_MISSILE) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index b1387ba52..817afd0fa 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -331,9 +331,11 @@ static FFlagDef InventoryFlagDefs[] = DEFINE_FLAG(IF, TOSSED, AInventory, ItemFlags), DEFINE_FLAG(IF, ALWAYSRESPAWN, AInventory, ItemFlags), DEFINE_FLAG(IF, TRANSFER, AInventory, ItemFlags), + DEFINE_FLAG(IF, NOTELEPORTFREEZE, AInventory, ItemFlags), DEFINE_DEPRECATED_FLAG(PICKUPFLASH), - DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP),}; + DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), +}; static FFlagDef WeaponFlagDefs[] = { diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 0c106417b..541dd37ac 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -225,6 +225,7 @@ ACTOR PowerWeaponLevel2 : Powerup native { Powerup.Duration -40 Inventory.Icon "SPINBK0" + +INVENTORY.NOTELEPORTFREEZE } ACTOR PowerSpeed : Powerup native @@ -232,6 +233,7 @@ ACTOR PowerSpeed : Powerup native Powerup.Duration -45 Speed 1.5 Inventory.Icon "SPBOOT0" + +INVENTORY.NOTELEPORTFREEZE } // Player Speed Trail (used by the Speed Powerup) ---------------------------- From d786148ccfa7befdccc212fb03665d7fa56b2000 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 16 Aug 2015 20:33:34 +0200 Subject: [PATCH 056/335] - fixed: the 'gameversion' console output was missing a trailing linefeed. --- src/c_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index a40f1f1a2..0a9e4f0e3 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -422,7 +422,7 @@ CCMD (take) CCMD (gameversion) { - Printf ("%s @ %s\nCommit %s", GetVersionString(), GetGitTime(), GetGitHash()); + Printf ("%s @ %s\nCommit %s\n", GetVersionString(), GetGitTime(), GetGitHash()); } CCMD (print) From 86e9504d04eee25fa51dd08e8c195b8de98f66d9 Mon Sep 17 00:00:00 2001 From: Leonard Date: Wed, 19 Aug 2015 15:59:54 +0200 Subject: [PATCH 057/335] Added weapon interpolation. --- src/d_player.h | 1 + src/g_game.cpp | 9 ++ src/p_pspr.cpp | 21 ++++ src/p_pspr.h | 6 ++ src/p_saveg.cpp | 5 + src/p_user.cpp | 15 +++ src/r_data/r_interpolate.cpp | 199 ++++++++++++++++++++++++++++++++++- src/version.h | 2 +- 8 files changed, 254 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e27bf1087..2ac2ad0d5 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -427,6 +427,7 @@ public: short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedlightlevel; pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) + TObjPtr pspinterp[NUMPSPRITES]; // view sprite interpolations int morphTics; // player is a chicken/pig if > 0 const PClass *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed diff --git a/src/g_game.cpp b/src/g_game.cpp index 8101ca23d..f77949687 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1726,6 +1726,15 @@ void G_DoPlayerPop(int playernum) players[playernum].mo = NULL; players[playernum].camera = NULL; } + // Now's the ideal time to remove his psprite interpolations. + for (int ii = 0; ii < NUMPSPRITES; ii++) + { + if (players[playernum].psprites[ii].interpolation != NULL) + { + players[playernum].psprites[ii].StopInterpolation(); + players[playernum].pspinterp[ii] = NULL; + } + } // [RH] Let the scripts know the player left FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 63f3bc648..d2bf8cc87 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1104,11 +1104,32 @@ void P_MovePsprites (player_t *player) P_CheckWeaponZoom (player); } } + + psp = &player->psprites[0]; + for (i = 0; i < NUMPSPRITES; i++, psp++) + { + if (psp->state == NULL) + { + if (psp->interpolation != NULL) + { + player->pspinterp[i] = NULL; + psp->StopInterpolation(); + } + } + else if (psp->interpolation == NULL) + { + player->pspinterp[i] = psp->SetInterpolation(player - players, i); + } + } } FArchive &operator<< (FArchive &arc, pspdef_t &def) { arc << def.state << def.tics << def.sx << def.sy << def.sprite << def.frame; + + if (SaveVersion >= 4525) + arc << def.interpolation; + return arc; } diff --git a/src/p_pspr.h b/src/p_pspr.h index ca9b45ee8..62c2a6fe4 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -26,6 +26,7 @@ // Basic data types. // Needs fixed point, and BAM angles. #include "tables.h" +#include "r_data/r_interpolate.h" #include "thingdef/thingdef.h" #define WEAPONBOTTOM 128*FRACUNIT @@ -71,6 +72,11 @@ struct pspdef_t int sprite; int frame; bool processPending; // true: waiting for periodic processing on this tick + + TObjPtr interpolation; + DInterpolation *SetInterpolation(int player, int position); + void UpdateInterpolation(int player); + void StopInterpolation(); }; class FArchive; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 480494320..f16bdb0f9 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -297,6 +297,11 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name) { dst->mo->player = dst; } + // Fix the psprite interpolation pointers too. + for (int i = 0; i < NUMPSPRITES; i++) + { + dst->psprites[i].UpdateInterpolation(dst - players); + } // These 2 variables may not be overwritten. dst->attackdown = attackdown; dst->usedown = usedown; diff --git a/src/p_user.cpp b/src/p_user.cpp index 0617e5d6a..baea731e6 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -316,6 +316,7 @@ player_t::player_t() memset (&cmd, 0, sizeof(cmd)); memset (frags, 0, sizeof(frags)); memset (psprites, 0, sizeof(psprites)); + memset (pspinterp, 0, sizeof(pspinterp)); } player_t &player_t::operator=(const player_t &p) @@ -371,6 +372,7 @@ player_t &player_t::operator=(const player_t &p) fixedcolormap = p.fixedcolormap; fixedlightlevel = p.fixedlightlevel; memcpy(psprites, &p.psprites, sizeof(psprites)); + memcpy(pspinterp, &p.pspinterp, sizeof(pspinterp)); morphTics = p.morphTics; MorphedPlayerClass = p.MorphedPlayerClass; MorphStyle = p.MorphStyle; @@ -435,6 +437,10 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep) if (*&ConversationNPC == old) ConversationNPC = replacement, changed++; if (*&ConversationPC == old) ConversationPC = replacement, changed++; if (*&MUSINFOactor == old) MUSINFOactor = replacement, changed++; + + for (int i = 0; i < NUMPSPRITES; i++) + if (*&pspinterp[i] == old) pspinterp[i] = static_cast(rep), changed++; + return changed; } @@ -454,6 +460,11 @@ size_t player_t::PropagateMark() { GC::Mark(PendingWeapon); } + for (int i = 0; i < NUMPSPRITES; i++) + { + GC::Mark(pspinterp[i]); + } + return sizeof(*this); } @@ -3049,7 +3060,11 @@ void player_t::Serialize (FArchive &arc) for (i = 0; i < MAXPLAYERS; i++) arc << frags[i]; for (i = 0; i < NUMPSPRITES; i++) + { arc << psprites[i]; + if (SaveVersion >= 4525) + arc << pspinterp[i]; + } arc << CurrentPlayerClass; diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 3ca3b557c..2acbe2140 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -151,6 +151,35 @@ public: }; +//========================================================================== +// +// +// +//========================================================================== + +class DPSpriteInterpolation : public DInterpolation +{ + DECLARE_CLASS(DPSpriteInterpolation, DInterpolation) + + pspdef_t *psp; + int player, position; + fixed_t oldx, oldy; + fixed_t bakx, baky; + fixed_t ofsx, ofsy; + fixed_t nfsx, nfsy; + +public: + + DPSpriteInterpolation() {} + DPSpriteInterpolation(pspdef_t *psp, int player, int position); + void UpdatePointer(int player); + void Destroy(); + void UpdateInterpolation(); + void Restore(); + void Interpolate(fixed_t smoothratio); + void Serialize(FArchive &arc); +}; + //========================================================================== // // @@ -162,6 +191,7 @@ IMPLEMENT_CLASS(DSectorPlaneInterpolation) IMPLEMENT_CLASS(DSectorScrollInterpolation) IMPLEMENT_CLASS(DWallScrollInterpolation) IMPLEMENT_CLASS(DPolyobjInterpolation) +IMPLEMENT_CLASS(DPSpriteInterpolation) //========================================================================== // @@ -628,7 +658,6 @@ void DSectorScrollInterpolation::Serialize(FArchive &arc) arc << sector << ceiling << oldx << oldy; } - //========================================================================== // // @@ -824,6 +853,115 @@ void DPolyobjInterpolation::Serialize(FArchive &arc) if (arc.IsLoading()) bakverts.Resize(oldverts.Size()); } +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== + +DPSpriteInterpolation::DPSpriteInterpolation(pspdef_t *_psp, int _player, int _position) +: nfsx(0), nfsy(0), ofsx(0), ofsy(0) +{ + psp = _psp; + player = _player; + position = _position; + UpdateInterpolation (); + interpolator.AddInterpolation(this); +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::UpdatePointer(int _player) +{ + player = _player; + psp = &players[player].psprites[position]; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::Destroy() +{ + psp->interpolation = NULL; + Super::Destroy(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::UpdateInterpolation() +{ + if ( position == ps_weapon ) + P_BobWeapon( &players[player], psp, &ofsx, &ofsy ); + + oldx = psp->sx + ofsx; + oldy = psp->sy + ofsy; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::Restore() +{ + psp->sx = bakx - nfsx; + psp->sy = baky - nfsy; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::Interpolate(fixed_t smoothratio) +{ + if ( position == ps_weapon ) + P_BobWeapon( &players[player], psp, &nfsx, &nfsy ); + + bakx = psp->sx + nfsx; + baky = psp->sy + nfsy; + + psp->sx = oldx + FixedMul(bakx - oldx, smoothratio) - nfsx; + psp->sy = oldy + FixedMul(baky - oldy, smoothratio) - nfsy; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DPSpriteInterpolation::Serialize(FArchive &arc) +{ + Super::Serialize(arc); + arc << player << position << oldx << oldy << ofsx << ofsy; + UpdatePointer(player); +} + +//========================================================================== +// +// +// +//========================================================================== //========================================================================== // @@ -944,6 +1082,63 @@ void FPolyObj::StopInterpolation() } } +//========================================================================== +// +// +// +//========================================================================== + +DInterpolation *pspdef_t::SetInterpolation(int player, int position) +{ + if (interpolation == NULL) + { + interpolation = new DPSpriteInterpolation(this, player, position); + } + interpolation->AddRef(); + GC::WriteBarrier(interpolation); + return interpolation; +} + +//========================================================================== +// +// +// +//========================================================================== + +void pspdef_t::UpdateInterpolation(int player) +{ + if (interpolation != NULL) + { + DInterpolation *pointer = interpolation; + static_cast(pointer)->UpdatePointer(player); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void pspdef_t::StopInterpolation() +{ + if (interpolation != NULL) + { + interpolation->DelRef(); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +//========================================================================== +// +// +// +//========================================================================== ADD_STAT (interpolations) { @@ -951,5 +1146,3 @@ ADD_STAT (interpolations) out.Format ("%d interpolations", interpolator.CountInterpolations ()); return out; } - - diff --git a/src/version.h b/src/version.h index 913c9bd18..168cb7519 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4524 +#define SAVEVER 4525 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From f9e70a82c6216c19075adcd9f3d9826ba52ef5db Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 24 Aug 2015 12:45:10 -0500 Subject: [PATCH 058/335] - Added A_SetSpecies(,). --- src/thingdef/thingdef_codeptr.cpp | 22 ++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 2 files changed, 23 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d09ad6d6e..f6b724747 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5764,6 +5764,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) ACTION_JUMP(low); } +//=========================================================================== +// A_SetSpecies(str species, ptr) +// +// Sets the species of the calling actor('s pointer). +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_NAME(species, 0); + ACTION_PARAM_INT(ptr, 1); + AActor *mobj = COPY_AAPTR(self, ptr); + if (!mobj) + { + ACTION_SET_RESULT(false); + return; + } + + if (!stricmp(species, "None") || !stricmp(species, "")) + mobj->Species = NAME_None; + else + mobj->Species = species; +} //=========================================================================== // diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 6885ad2d6..5e79d6b82 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -331,6 +331,7 @@ ACTOR Actor native //: Thinker action native A_SetHealth(int health, int ptr = AAPTR_DEFAULT); action native A_ResetHealth(int ptr = AAPTR_DEFAULT); action native A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET); + action native A_SetSpecies(name species, int ptr = AAPTR_DEFAULT); action native A_SetRipperLevel(int level); action native A_SetRipMin(int min); action native A_SetRipMax(int max); From 27316432009ab2a09c494fd4d72287b215caf241 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 25 Aug 2015 08:15:23 -0500 Subject: [PATCH 059/335] Removed stricmp checks, as they're not needed. --- src/thingdef/thingdef_codeptr.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f6b724747..377c4915b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5781,10 +5781,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) return; } - if (!stricmp(species, "None") || !stricmp(species, "")) - mobj->Species = NAME_None; - else - mobj->Species = species; + mobj->Species = species; } //=========================================================================== From ebf515f8c76ca32d2fd5fe9b70783987af5c12ca Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 25 Aug 2015 20:18:06 -0500 Subject: [PATCH 060/335] - Fixed unneeded dual call to SetOrigin. --- src/p_things.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index f9d85c43f..b7e3f058b 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -718,19 +718,13 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, if (flags & WARPF_TOFLOOR) { // set correct xy - - caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->z); - // now the caller's floorz should be appropriate for the assigned xy-position // assigning position again with. // extra unlink, link and environment calculation caller->SetOrigin( - caller->x, - caller->y, - caller->floorz + zofs); + reference->x + xofs, + reference->y + yofs, + reference->floorz + zofs); } else { From 696c6af588a4b1f326a7257ca0cdc1073eaedbb2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 27 Aug 2015 12:48:43 +0200 Subject: [PATCH 061/335] - fixed: FString's 'Strip...' functions could crash on empty strings. --- src/zstring.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zstring.cpp b/src/zstring.cpp index 510ff19d7..1aa388da9 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -583,6 +583,7 @@ void FString::SwapCase () void FString::StripLeft () { size_t max = Len(), i, j; + if (max == 0) return; for (i = 0; i < max; ++i) { if (!isspace(Chars[i])) @@ -613,6 +614,7 @@ void FString::StripLeft (const FString &charset) void FString::StripLeft (const char *charset) { size_t max = Len(), i, j; + if (max == 0) return; for (i = 0; i < max; ++i) { if (!strchr (charset, Chars[i])) @@ -665,6 +667,7 @@ void FString::StripRight (const FString &charset) void FString::StripRight (const char *charset) { size_t max = Len(), i; + if (max == 0) return; for (i = max; i-- > 0; ) { if (!strchr (charset, Chars[i])) @@ -687,6 +690,7 @@ void FString::StripRight (const char *charset) void FString::StripLeftRight () { size_t max = Len(), i, j, k; + if (max == 0) return; for (i = 0; i < max; ++i) { if (!isspace(Chars[i])) @@ -723,6 +727,7 @@ void FString::StripLeftRight (const FString &charset) void FString::StripLeftRight (const char *charset) { size_t max = Len(), i, j, k; + if (max == 0) return; for (i = 0; i < max; ++i) { if (!strchr (charset, Chars[i])) From 98f214ee66fd5223c2d277fb982848e03e0200d2 Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Fri, 28 Aug 2015 19:14:25 +0200 Subject: [PATCH 062/335] Added support for GOG paths This works a bit differently from the Steam version, because each game has its own registry keys and its own independent path. --- src/d_iwad.cpp | 5 ++++ src/win32/i_system.cpp | 63 ++++++++++++++++++++++++++++++++++++++---- src/win32/i_system.h | 3 ++ 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 3fc365e8c..a8d60e1ce 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -435,6 +435,11 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } } } + TArray gog_paths = I_GetGogPaths(); + for (i = 0; i < gog_paths.Size(); ++i) + { + CheckIWAD (gog_paths[i], &wads[0]); + } TArray steam_path = I_GetSteamPath(); for (i = 0; i < steam_path.Size(); ++i) { diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 6d8fb8595..372da8685 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1504,30 +1504,83 @@ int I_FindClose(void *handle) static bool QueryPathKey(HKEY key, const char *keypath, const char *valname, FString &value) { - HKEY steamkey; + HKEY pathkey; DWORD pathtype; DWORD pathlen; LONG res; - if(ERROR_SUCCESS == RegOpenKeyEx(key, keypath, 0, KEY_QUERY_VALUE, &steamkey)) + if(ERROR_SUCCESS == RegOpenKeyEx(key, keypath, 0, KEY_QUERY_VALUE, &pathkey)) { - if (ERROR_SUCCESS == RegQueryValueEx(steamkey, valname, 0, &pathtype, NULL, &pathlen) && + if (ERROR_SUCCESS == RegQueryValueEx(pathkey, valname, 0, &pathtype, NULL, &pathlen) && pathtype == REG_SZ && pathlen != 0) { // Don't include terminating null in count char *chars = value.LockNewBuffer(pathlen - 1); - res = RegQueryValueEx(steamkey, valname, 0, NULL, (LPBYTE)chars, &pathlen); + res = RegQueryValueEx(pathkey, valname, 0, NULL, (LPBYTE)chars, &pathlen); value.UnlockBuffer(); if (res != ERROR_SUCCESS) { value = ""; } } - RegCloseKey(steamkey); + RegCloseKey(pathkey); } return value.IsNotEmpty(); } +//========================================================================== +// +// I_GetGogPaths +// +// Check the registry for GOG installation paths, so we can search for IWADs +// that were bought from GOG.com. This is a bit different from the Steam +// version because each game has its own independent installation path, no +// such thing as /SteamApps/common/. +// +//========================================================================== + +TArray I_GetGogPaths() +{ + TArray result; + FString path; + FString gamepath; + +#ifdef _WIN64 + FString gogregistrypath = "Software\\Wow6432Node\\GOG.com\\Games"; +#else + // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and + // automatically redirected to the Wow6432Node address instead, so this address + // should be safe to use in all cases. + FString gogregistrypath = "Software\\GOG.com\\Games"; +#endif + + // Look for Ultimate Doom + gamepath = gogregistrypath + "\\1435827232"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Doom II + gamepath = gogregistrypath + "\\1435848814"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + { + result.Push(path + "/doom2"); // in a subdirectory + // If direct support for the Master Levels is ever added, they are in path + /master/wads + } + + // Look for Final Doom + gamepath = gogregistrypath + "\\1435848742"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.GetChars(), "Path", path)) + { + // in subdirectories + result.Push(path + "/TNT"); + result.Push(path + "/Plutonia"); + } + + return result; +} + //========================================================================== // // I_GetSteamPath diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 566ca1977..03f4f3c0f 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -168,6 +168,9 @@ void I_SetWndProc(); // directories for IWADs if the user purchased any through Steam. TArray I_GetSteamPath(); +// [GZ] Same deal for GOG paths +TArray I_GetGogPaths(); + // Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of // giving them proper prototypes under Win32, they are just macros for // Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs. From 677dc8893ee53d36361dc40adc5347790b647a2f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 29 Aug 2015 14:55:10 +0300 Subject: [PATCH 063/335] Fixed compilation on non-Windows OSes --- src/posix/i_system.cpp | 6 ++++++ src/posix/i_system.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/posix/i_system.cpp b/src/posix/i_system.cpp index fd6bb4c0c..84b953717 100644 --- a/src/posix/i_system.cpp +++ b/src/posix/i_system.cpp @@ -758,3 +758,9 @@ unsigned int I_MakeRNGSeed() } return seed; } + +TArray I_GetGogPaths() +{ + // GOG's Doom games are Windows only at the moment + return TArray(); +} diff --git a/src/posix/i_system.h b/src/posix/i_system.h index abda490c4..391503602 100644 --- a/src/posix/i_system.h +++ b/src/posix/i_system.h @@ -124,6 +124,8 @@ int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); // directories for IWADs if the user purchased any through Steam. TArray I_GetSteamPath(); +TArray I_GetGogPaths(); + // The ini could not be saved at exit bool I_WriteIniFailed (); From 0ed4549683e608422aa1952b01225289e41b2c0b Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sun, 30 Aug 2015 02:47:45 +1200 Subject: [PATCH 064/335] Correct the mastermind's radius --- wadsrc/static/actors/doom/spidermaster.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/spidermaster.txt b/wadsrc/static/actors/doom/spidermaster.txt index 97ebbf143..c2a742f1e 100644 --- a/wadsrc/static/actors/doom/spidermaster.txt +++ b/wadsrc/static/actors/doom/spidermaster.txt @@ -6,7 +6,7 @@ ACTOR SpiderMastermind { Health 3000 - Radius 100 + Radius 128 Height 100 Mass 1000 Speed 12 From 389ff4fc98b6ad354418d9370a97b52dc9f49e0b Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sun, 30 Aug 2015 22:02:36 +1200 Subject: [PATCH 065/335] Shift self-clip to first check for performance --- src/p_map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index fca43c120..c9b2f14cf 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1013,6 +1013,10 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) bool solid; int damage; + // don't clip against self + if (thing == tm.thing) + return true; + if (!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY)) return true; // can't hit thing @@ -1020,10 +1024,6 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist) return true; - // don't clip against self - if (thing == tm.thing) - return true; - if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) return true; From b87435ac9d931d3bd053fd9084cb23d7d5457426 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sun, 30 Aug 2015 22:56:34 +1200 Subject: [PATCH 066/335] Remove unnecessary FriendlyFire global --- src/p_interaction.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 276a88c75..2947bf9c0 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -74,7 +74,6 @@ EXTERN_CVAR (Bool, show_obituaries) FName MeansOfDeath; -bool FriendlyFire; // // GET STUFF @@ -198,10 +197,8 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (inflictor && inflictor->player && inflictor->player->mo != inflictor) MeansOfDeath = NAME_None; - if (multiplayer && !deathmatch) - FriendlyFire = true; + friendly = (self->player != attacker->player && self->IsTeammate(attacker)); - friendly = FriendlyFire; mod = MeansOfDeath; message = NULL; messagename = NULL; @@ -1024,7 +1021,6 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } MeansOfDeath = mod; - FriendlyFire = false; // [RH] Andy Baker's Stealth monsters if (target->flags & MF_STEALTH) { @@ -1221,8 +1217,6 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, ((player && player != source->player) || (!player && target != source)) && target->IsTeammate (source)) { - if (player) - FriendlyFire = true; if (rawdamage < TELEFRAG_DAMAGE) //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. { // Still allow telefragging :-( damage = (int)((float)damage * level.teamdamage); From 02c562518ddf9657c0a353bd03a4caab424a214e Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sun, 30 Aug 2015 23:36:00 +1200 Subject: [PATCH 067/335] Fixed possible sync issue with frag counts --- src/p_interaction.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2947bf9c0..a0b1ddbc1 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -268,8 +268,6 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf { if (friendly) { - attacker->player->fragcount -= 2; - attacker->player->frags[attacker->player - players]++; self = attacker; gender = self->player->userinfo.GetGender(); mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3)); @@ -467,12 +465,21 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if ((dmflags2 & DF2_YES_LOSEFRAG) && deathmatch) player->fragcount--; - ++source->player->fragcount; - ++source->player->spreecount; + if (this->IsTeammate(source)) + { + source->player->fragcount--; + } + else + { + ++source->player->fragcount; + ++source->player->spreecount; + } + if (source->player->morphTics) { // Make a super chicken source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); } + if (deathmatch && cl_showsprees) { const char *spreemsg; From 0fa24ab82d069f5fd44a55d5d307ff36b8642720 Mon Sep 17 00:00:00 2001 From: Leonard Date: Mon, 31 Aug 2015 13:04:40 +0200 Subject: [PATCH 068/335] Use barrier_cast instead of static_cast --- src/r_data/r_interpolate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 2acbe2140..46ac30789 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -1109,8 +1109,7 @@ void pspdef_t::UpdateInterpolation(int player) { if (interpolation != NULL) { - DInterpolation *pointer = interpolation; - static_cast(pointer)->UpdatePointer(player); + barrier_cast(interpolation)->UpdatePointer(player); } } From 1a275a7e8eb91dfefa341b1745235759fd465cb2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 2 Sep 2015 23:15:41 +0200 Subject: [PATCH 069/335] - removed the initial extra state of Heretic's Mummy's projectile to restore the original sound behavior. --- wadsrc/static/actors/heretic/mummy.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wadsrc/static/actors/heretic/mummy.txt b/wadsrc/static/actors/heretic/mummy.txt index 46e9deaba..c06f519f6 100644 --- a/wadsrc/static/actors/heretic/mummy.txt +++ b/wadsrc/static/actors/heretic/mummy.txt @@ -121,12 +121,11 @@ ACTOR MummyFX1 States { Spawn: - FX15 A 1 Bright FX15 A 5 Bright A_PlaySound("mummy/head") FX15 B 5 Bright A_SeekerMissile(10,20) FX15 C 5 Bright FX15 B 5 Bright A_SeekerMissile(10,20) - Goto Spawn+1 + Loop Death: FX15 DEFG 5 Bright Stop From 8ec4d431cfcba1479d5631613a6c8b4ea20bf2a7 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 5 Sep 2015 14:12:52 +1200 Subject: [PATCH 070/335] Fixed memory leak in joystick menu --- src/menu/joystickmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index a7d950ed5..676bc1767 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -345,8 +345,8 @@ void UpdateJoystickMenu(IJoystickConfig *selected) for(unsigned i=0;imItems.Size();i++) { delete opt->mItems[i]; - opt->mItems.Clear(); } + opt->mItems.Clear(); int i; int itemnum = -1; From abb033d400eed5a5d3c2577b86764695c6d80cf6 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 5 Sep 2015 14:18:48 +1200 Subject: [PATCH 071/335] Fix deallocation of controllers with no axes --- src/win32/i_dijoy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/i_dijoy.cpp b/src/win32/i_dijoy.cpp index ccbc7ecdc..439e0fda7 100644 --- a/src/win32/i_dijoy.cpp +++ b/src/win32/i_dijoy.cpp @@ -309,7 +309,7 @@ FDInputJoystick::~FDInputJoystick() { Joy_GenerateButtonEvents(Axes[0].ButtonValue, 0, 2, KEY_JOYAXIS1PLUS); } - else + else if (Axes.Size() > 1) { Joy_GenerateButtonEvents(Axes[1].ButtonValue, 0, 4, KEY_JOYAXIS1PLUS); for (i = 2; i < Axes.Size(); ++i) From 9aabc852816921ed1c95e6bba094961fc8dbcaab Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 5 Sep 2015 17:13:54 +1200 Subject: [PATCH 072/335] Fixed loading default map saves - Just like normal maps, default map stores an FString as a map name. --- src/g_level.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 899f96d4f..15d88ccaf 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1791,8 +1791,14 @@ void G_ReadSnapshots (PNGHandle *png) DWORD snapver; arc << snapver; - arc << namelen; - arc.Read (mapname, namelen); + if (SaveVersion < 4508) + { + arc << namelen; + arc.Read(mapname, namelen); + mapname[namelen] = 0; + MapName = mapname; + } + else arc << MapName; TheDefaultLevelInfo.snapshotVer = snapver; TheDefaultLevelInfo.snapshot = new FCompressedMemFile; TheDefaultLevelInfo.snapshot->Serialize (arc); From e939d6885d293020469840eef43a0ad42f902a8e Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 5 Sep 2015 23:58:02 +0200 Subject: [PATCH 073/335] - Fixed a crash in ACS strlen parsing with invalid argument. --- src/p_acs.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b703b87dd..54f9fa658 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -8880,7 +8880,22 @@ scriptwait: break; case PCD_STRLEN: - STACK(1) = SDWORD(strlen(FBehavior::StaticLookupString (STACK(1)))); + { + const char *str = FBehavior::StaticLookupString(STACK(1)); + if (str != NULL) + { + STACK(1) = SDWORD(strlen(str)); + break; + } + + static bool StrlenInvalidPrintedAlready = false; + if (!StrlenInvalidPrintedAlready) + { + Printf(PRINT_BOLD, "Warning: ACS function strlen called with invalid string argument.\n"); + StrlenInvalidPrintedAlready = true; + } + STACK(1) = 0; + } break; case PCD_GETCVAR: From 99120d84420b01e6e03d0379682d966ef7907d9a Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 6 Sep 2015 12:12:57 +0100 Subject: [PATCH 074/335] - Fixed: A_SkullPop did not work with spy mode. --- src/p_user.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 0617e5d6a..0d5cdce20 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1562,12 +1562,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) if (player != NULL) { player->mo = mo; - if (player->camera == self) - { - player->camera = mo; - } player->damagecount = 32; } + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].camera == self) + { + players[i].camera = mo; + } + } } //---------------------------------------------------------------------------- From 68ea99016cdf1dfa649008c680924e9139671d87 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 6 Sep 2015 15:45:10 +0300 Subject: [PATCH 075/335] Compatibility fix for Whispers of Satan MAP29 Insta-death pit (sector 1497) is now working as intended independently from compatibility settings --- wadsrc/static/compatibility.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 26f43bb25..6cbe36af4 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -396,3 +396,8 @@ A53AE580A4AF2B5D0B0893F86914781E // TNT: Evilution map31 { setthingflags 470 2016 } + +D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29 +{ + nopassover +} From bca50c58b30d3041b8094659ab1f250fdffc0c40 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Sep 2015 16:00:47 +0200 Subject: [PATCH 076/335] - removed A_NoBlocking call from Commander Keen. --- wadsrc/static/actors/doom/keen.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/keen.txt b/wadsrc/static/actors/doom/keen.txt index 2c07e5b32..93d43764f 100644 --- a/wadsrc/static/actors/doom/keen.txt +++ b/wadsrc/static/actors/doom/keen.txt @@ -28,7 +28,7 @@ ACTOR CommanderKeen KEEN AB 6 KEEN C 6 A_Scream KEEN DEFGH 6 - KEEN I 6 A_NoBlocking + KEEN I 6 KEEN J 6 KEEN K 6 A_KeenDie KEEN L -1 From 213216368ab1988a93087827db2b074c7beadec9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Sep 2015 16:36:32 +0200 Subject: [PATCH 077/335] - more DECORATE fixing of Doom monsters, this time the Mancubus. It looks like the definitions that got added on November 4th, 2006 had some issues that mostly went unnoticed over time... --- wadsrc/static/actors/doom/fatso.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/actors/doom/fatso.txt b/wadsrc/static/actors/doom/fatso.txt index 1ad40fd93..0b3039325 100644 --- a/wadsrc/static/actors/doom/fatso.txt +++ b/wadsrc/static/actors/doom/fatso.txt @@ -30,9 +30,9 @@ ACTOR Fatso Missile: FATT G 20 A_FatRaise FATT H 10 BRIGHT A_FatAttack1 - FATT IG 5 + FATT IG 5 A_FaceTarget FATT H 10 BRIGHT A_FatAttack2 - FATT IG 5 + FATT IG 5 A_FaceTarget FATT H 10 BRIGHT A_FatAttack3 FATT IG 5 Goto See From 143a4c78a9dd630f9d9c2583e56da2b17f31bd21 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 6 Sep 2015 19:57:43 -0500 Subject: [PATCH 078/335] - Added A_SetFloatSpeed. - Sets the FloatSpeed of the actor/pointer. --- src/thingdef/thingdef_codeptr.cpp | 24 +++++++++++++++++++++++- wadsrc/static/actors/actor.txt | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 54b816ebb..62a22532c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5071,7 +5071,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) // A_SetSpeed // //========================================================================== - DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) { ACTION_PARAM_START(2); @@ -5089,6 +5088,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) ref->Speed = speed; } +//========================================================================== +// +// A_SetFloatSpeed +// +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_FIXED(speed, 0); + ACTION_PARAM_INT(ptr, 1); + + AActor *ref = COPY_AAPTR(self, ptr); + + if (!ref) + { + ACTION_SET_RESULT(false); + return; + } + + ref->FloatSpeed = speed; +} + //=========================================================================== // // Common A_Damage handler @@ -5823,3 +5844,4 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) ACTION_PARAM_INT(max, 0); self->RipLevelMax = max; } + diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index f231348d3..5877192ce 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -304,6 +304,7 @@ ACTOR Actor native //: Thinker action native A_SetDamageType(name damagetype); action native A_DropItem(class item, int dropamount = -1, int chance = 256); action native A_SetSpeed(float speed, int ptr = AAPTR_DEFAULT); + action native A_SetFloatSpeed(float speed, int ptr = AAPTR_DEFAULT); action native A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); action native A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); action native A_DamageMaster(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); From 8948f5dc2bcbcf95a207a5e2e695b0f2c8410e93 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Tue, 8 Sep 2015 10:40:21 -0500 Subject: [PATCH 079/335] Added FPF_NOAUTOAIM to A_FireCustomMissile --- src/p_local.h | 2 +- src/p_mobj.cpp | 4 ++-- src/thingdef/thingdef_codeptr.cpp | 3 ++- wadsrc/static/actors/constants.txt | 1 + wadsrc/static/actors/shared/inventory.txt | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index a2fa00c71..a8aaaeb0d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -153,7 +153,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, - AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false); + AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 267e71bb9..901372eef 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5923,7 +5923,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle) AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, - bool nofreeaim) + bool nofreeaim, bool noautoaim) { static const int angdiff[3] = { -1<<26, 1<<26, 0 }; angle_t an = angle; @@ -5936,7 +5936,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, { return NULL; } - if (source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM)) + if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim)) { // Keep exactly the same angle and pitch as the player's own aim an = angle; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 62a22532c..5cc54a247 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1320,6 +1320,7 @@ enum FP_Flags { FPF_AIMATANGLE = 1, FPF_TRANSFERTRANSLATION = 2, + FPF_NOAUTOAIM = 4, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) { @@ -1358,7 +1359,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) // Temporarily adjusts the pitch fixed_t SavedPlayerPitch = self->pitch; self->pitch -= pitch; - AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget); + AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, Flags & FPF_NOAUTOAIM); self->pitch = SavedPlayerPitch; // automatic handling of seeker missiles diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 04ed6f1fc..b5a8b8cd4 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -188,6 +188,7 @@ const int CPF_STEALARMOR = 32; // Flags for A_CustomMissile const int FPF_AIMATANGLE = 1; const int FPF_TRANSFERTRANSLATION = 2; +const int FPF_NOAUTOAIM = 4; // Flags for A_Teleport enum diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 541dd37ac..13ae00936 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -10,7 +10,7 @@ ACTOR Inventory native action native A_JumpIfNoAmmo(state label); action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); - action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); + action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_Light(int extralight); action native A_Light0(); From 19c702a60843c0c2dc41409ae0a9c92b31e30def Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 9 Sep 2015 21:26:44 +0200 Subject: [PATCH 080/335] - Fixed a crash when a player dies in damage floors. --- src/p_interaction.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index a0b1ddbc1..603535b7c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -184,7 +184,6 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf const char *message; const char *messagename; char gendermessage[1024]; - bool friendly; int gender; // No obituaries for non-players, voodoo dolls or when not wanted @@ -197,8 +196,6 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (inflictor && inflictor->player && inflictor->player->mo != inflictor) MeansOfDeath = NAME_None; - friendly = (self->player != attacker->player && self->IsTeammate(attacker)); - mod = MeansOfDeath; message = NULL; messagename = NULL; @@ -266,7 +263,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (message == NULL && attacker != NULL && attacker->player != NULL) { - if (friendly) + if (self->player != attacker->player && self->IsTeammate(attacker)) { self = attacker; gender = self->player->userinfo.GetGender(); From 5afbe8ca007093f7cb6525b5300e4a5436d596ef Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Wed, 9 Sep 2015 18:54:49 -0500 Subject: [PATCH 081/335] Fixed compiler warning for FPF_NOAUTOAIM flag check --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 5cc54a247..dab68867b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1359,7 +1359,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) // Temporarily adjusts the pitch fixed_t SavedPlayerPitch = self->pitch; self->pitch -= pitch; - AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, Flags & FPF_NOAUTOAIM); + AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, (Flags & FPF_NOAUTOAIM) != 0); self->pitch = SavedPlayerPitch; // automatic handling of seeker missiles From 2f027504b6716f35739038eb3073fedc9c1a86d1 Mon Sep 17 00:00:00 2001 From: Teemu Piippo Date: Sat, 12 Sep 2015 04:47:49 +0300 Subject: [PATCH 082/335] Show sector action boundaries on the automap like line specials are. --- src/am_map.cpp | 154 +++++++++++++++++++++++++------- src/g_shared/a_sectoraction.cpp | 23 ++++- src/r_defs.h | 5 ++ 3 files changed, 148 insertions(+), 34 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 045d48589..3430d3182 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2224,6 +2224,124 @@ bool AM_Check3DFloors(line_t *line) return false; } +// [TP] Check whether a sector can trigger a special that satisfies the provided function. +// If found, specialptr and argsptr will be filled by the special and the arguments +// If needUseActivated is true, the special must be activated by use. +bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated) +{ + for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast(action->tracer)) + { + if ((action->IsActivatedByUse() || false == needUseActivated) + && (*function)(action->special, action->args) + && action->CanTrigger (players[consoleplayer].mo)) + { + *specialptr = action->special; + *argsptr = action->args; + return true; + } + } + + return false; +} + +// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function. +// It's a boundary if the line can activate the special or the line's bordering sectors can activate it. +// If found, specialptr and argsptr will be filled with special and args if given. +bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *specialptr = NULL, int **argsptr = NULL) +{ + if (specialptr == NULL) + { + static int sink; + specialptr = &sink; + } + + if (argsptr == NULL) + { + static int* sink; + argsptr = &sink; + } + + // Check if the line special qualifies for this + if ((*function)(line.special, line.args) && (line.activation & SPAC_PlayerActivate)) + { + *specialptr = line.special; + *argsptr = line.args; + return true; + } + + // Check sector actions in the line's front sector -- the action has to be use-activated in order to + // show up if this is a one-sided line, because the player cannot trigger sector actions by crossing + // a one-sided line (since that's impossible, duh). + if (AM_checkSectorActions(line.frontsector, function, specialptr, argsptr, line.backsector == NULL)) + return true; + + // If it has a back sector, check sector actions in that. + return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); +} + +bool AM_isTeleportSpecial (int special, int*) +{ + return (special == Teleport || + special == Teleport_NoFog || + special == Teleport_ZombieChanger || + special == Teleport_Line); +} + +bool AM_isTeleportBoundary (line_t& line) +{ + return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); +} + +bool AM_isExitSpecial (int special, int*) +{ + return (special == Teleport_NewMap || + special == Teleport_EndGame || + special == Exit_Normal || + special == Exit_Secret); +} + +bool AM_isExitBoundary (line_t& line) +{ + return AM_checkSpecialBoundary(line, &AM_isExitSpecial); +} + +bool AM_isTriggerSpecial (int special, int*) +{ + return special != 0 + && special != Door_Open + && special != Door_Close + && special != Door_CloseWaitOpen + && special != Door_Raise + && special != Door_Animated + && special != Generic_Door; +} + +bool AM_isTriggerBoundary (line_t& line) +{ + return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); +} + +bool AM_isLockSpecial (int special, int* args) +{ + return special == Door_LockedRaise || + special == ACS_LockedExecute || + special == ACS_LockedExecuteDoor || + (special == Door_Animated && args[3] != 0) || + (special == Generic_Door && args[4] != 0); +} + +bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) +{ + int special; + int *args; + bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); + + if (lockptr && result) + *lockptr = (special==Door_LockedRaise || special==Door_Animated) ? args[3] : args[4]; + + return result; +} + //============================================================================= // // Determines visible lines, draws them. @@ -2283,37 +2401,18 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, c); } - else if ((lines[i].special == Teleport || - lines[i].special == Teleport_NoFog || - lines[i].special == Teleport_ZombieChanger || - lines[i].special == Teleport_Line) && - (lines[i].activation & SPAC_PlayerActivate) && - AMColors.isValid(AMColors.IntraTeleportColor)) + else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor)) { // intra-level teleporters AM_drawMline(&l, AMColors.IntraTeleportColor); } - else if ((lines[i].special == Teleport_NewMap || - lines[i].special == Teleport_EndGame || - lines[i].special == Exit_Normal || - lines[i].special == Exit_Secret) && - AMColors.isValid(AMColors.InterTeleportColor)) + else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor)) { // inter-level/game-ending teleporters AM_drawMline(&l, AMColors.InterTeleportColor); } - else if (lines[i].special == Door_LockedRaise || - lines[i].special == ACS_LockedExecute || - lines[i].special == ACS_LockedExecuteDoor || - (lines[i].special == Door_Animated && lines[i].args[3] != 0) || - (lines[i].special == Generic_Door && lines[i].args[4] != 0)) + else if (AM_isLockBoundary(lines[i], &lock)) { if (AMColors.displayLocks) { - int P_GetMapColorForLock(int lock); - - if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) - lock=lines[i].args[3]; - else lock=lines[i].args[4]; - color = P_GetMapColorForLock(lock); AMColor c; @@ -2328,14 +2427,9 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, AMColors.LockedColor); // locked special } } - else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) && lines[i].special != 0 - && lines[i].special != Door_Open - && lines[i].special != Door_Close - && lines[i].special != Door_CloseWaitOpen - && lines[i].special != Door_Raise - && lines[i].special != Door_Animated - && lines[i].special != Generic_Door - && (lines[i].activation & SPAC_PlayerActivate)) + else if (am_showtriggerlines + && AMColors.isValid(AMColors.SpecialWallColor) + && AM_isTriggerBoundary(lines[i])) { AM_drawMline(&l, AMColors.SpecialWallColor); // wall with special non-door action the player can do } diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp index 570818e19..bb582dd28 100644 --- a/src/g_shared/a_sectoraction.cpp +++ b/src/g_shared/a_sectoraction.cpp @@ -39,6 +39,14 @@ IMPLEMENT_CLASS (ASectorAction) +ASectorAction::ASectorAction (bool activatedByUse) : + ActivatedByUse (activatedByUse) {} + +bool ASectorAction::IsActivatedByUse() const +{ + return ActivatedByUse; +} + void ASectorAction::Destroy () { // Remove ourself from this sector's list of actions @@ -102,12 +110,17 @@ bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType) return false; } +bool ASectorAction::CanTrigger (AActor *triggerer) const +{ + return special && + ((triggerer->player && !(flags & MF_FRIENDLY)) || + ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || + ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS))); +} + bool ASectorAction::CheckTrigger (AActor *triggerer) const { - if (special && - ((triggerer->player && !(flags & MF_FRIENDLY)) || - ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || - ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)))) + if (CanTrigger(triggerer)) { bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1], args[2], args[3], args[4]); @@ -196,6 +209,7 @@ class ASecActUse : public ASectorAction { DECLARE_CLASS (ASecActUse, ASectorAction) public: + ASecActUse() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; @@ -214,6 +228,7 @@ class ASecActUseWall : public ASectorAction { DECLARE_CLASS (ASecActUseWall, ASectorAction) public: + ASecActUseWall() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; diff --git a/src/r_defs.h b/src/r_defs.h index afda92089..ff6957783 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -194,14 +194,19 @@ class ASectorAction : public AActor { DECLARE_CLASS (ASectorAction, AActor) public: + ASectorAction (bool activatedByUse = false); void Destroy (); void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); bool TriggerAction(AActor *triggerer, int activationType); + bool CanTrigger (AActor *triggerer) const; + bool IsActivatedByUse() const; protected: virtual bool DoTriggerAction(AActor *triggerer, int activationType); bool CheckTrigger(AActor *triggerer) const; +private: + bool ActivatedByUse; }; class ASkyViewpoint; From 67a7f48ca3cdd8c6e83a58c27dba6fd3f31fbbac Mon Sep 17 00:00:00 2001 From: Teemu Piippo Date: Sat, 12 Sep 2015 14:02:07 +0300 Subject: [PATCH 083/335] Handle locknumber in boundary checks, check for FS_Execute --- src/am_map.cpp | 56 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 3430d3182..279deb8a4 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2323,21 +2323,50 @@ bool AM_isTriggerBoundary (line_t& line) bool AM_isLockSpecial (int special, int* args) { - return special == Door_LockedRaise || - special == ACS_LockedExecute || - special == ACS_LockedExecuteDoor || - (special == Door_Animated && args[3] != 0) || - (special == Generic_Door && args[4] != 0); + return special == Door_LockedRaise + || special == ACS_LockedExecute + || special == ACS_LockedExecuteDoor + || (special == Door_Animated && args[3] != 0) + || (special == Generic_Door && args[4] != 0) + || (special == FS_Execute && args[2] != 0); } bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) { + if (lockptr == NULL) + { + static int sink; + lockptr = &sink; + } + + if (line.locknumber) + { + *lockptr = line.locknumber; + return true; + } + int special; int *args; bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); - if (lockptr && result) - *lockptr = (special==Door_LockedRaise || special==Door_Animated) ? args[3] : args[4]; + if (result) + { + switch (special) + { + case FS_Execute: + *lockptr = args[2]; + break; + + case Door_Animated: + case Door_LockedRaise: + *lockptr = args[3]; + break; + + default: + *lockptr = args[4]; + break; + } + } return result; } @@ -2389,18 +2418,7 @@ void AM_drawWalls (bool allmap) AM_drawMline(&l, AMColors.SecretWallColor); else AM_drawMline(&l, AMColors.WallColor); - } - else if (lines[i].locknumber > 0 && AMColors.displayLocks) - { // [Dusk] specials w/ locknumbers - lock = lines[i].locknumber; - color = P_GetMapColorForLock(lock); - - AMColor c; - if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); - else c = AMColors[AMColors.LockedColor]; - - AM_drawMline (&l, c); - } + } else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor)) { // intra-level teleporters AM_drawMline(&l, AMColors.IntraTeleportColor); From 69fd0e6eb484fddd4a55333b4fa74377c6e0e992 Mon Sep 17 00:00:00 2001 From: Teemu Piippo Date: Sat, 12 Sep 2015 14:07:40 +0300 Subject: [PATCH 084/335] Stylistical coherence.. --- src/am_map.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 279deb8a4..16fd67111 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2247,7 +2247,7 @@ bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int // [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function. // It's a boundary if the line can activate the special or the line's bordering sectors can activate it. // If found, specialptr and argsptr will be filled with special and args if given. -bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *specialptr = NULL, int **argsptr = NULL) +bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *specialptr = NULL, int **argsptr = NULL) { if (specialptr == NULL) { @@ -2257,7 +2257,7 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *sp if (argsptr == NULL) { - static int* sink; + static int *sink; argsptr = &sink; } @@ -2279,7 +2279,7 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *sp return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); } -bool AM_isTeleportSpecial (int special, int*) +bool AM_isTeleportSpecial (int special, int *) { return (special == Teleport || special == Teleport_NoFog || @@ -2287,12 +2287,12 @@ bool AM_isTeleportSpecial (int special, int*) special == Teleport_Line); } -bool AM_isTeleportBoundary (line_t& line) +bool AM_isTeleportBoundary (line_t &line) { return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); } -bool AM_isExitSpecial (int special, int*) +bool AM_isExitSpecial (int special, int *) { return (special == Teleport_NewMap || special == Teleport_EndGame || @@ -2305,7 +2305,7 @@ bool AM_isExitBoundary (line_t& line) return AM_checkSpecialBoundary(line, &AM_isExitSpecial); } -bool AM_isTriggerSpecial (int special, int*) +bool AM_isTriggerSpecial (int special, int *) { return special != 0 && special != Door_Open @@ -2316,7 +2316,7 @@ bool AM_isTriggerSpecial (int special, int*) && special != Generic_Door; } -bool AM_isTriggerBoundary (line_t& line) +bool AM_isTriggerBoundary (line_t &line) { return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); } From a90ea55e2c2edd328411a99326ef7c5937ae709f Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 12 Sep 2015 23:01:56 +0100 Subject: [PATCH 085/335] - Removed duplicate 'acceleratestage' check. --- src/wi_stuff.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 8119d3802..653f6b907 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1808,18 +1808,16 @@ void WI_updateStats () if (acceleratestage && sp_state != 10) { - if (acceleratestage) - { - acceleratestage = 0; - sp_state = 10; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - } + acceleratestage = 0; + sp_state = 10; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + cnt_kills[0] = plrs[me].skills; cnt_items[0] = plrs[me].sitems; cnt_secret[0] = plrs[me].ssecret; cnt_time = Tics2Seconds(plrs[me].stime); cnt_par = wbs->partime / TICRATE; - cnt_total_time = Tics2Seconds(wbs->totaltime); + cnt_total_time = Tics2Seconds(wbs->totaltime); } if (sp_state == 2) From 36c7002628cdd73ae09eb0368ab2a9756ebcb529 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sun, 13 Sep 2015 13:46:02 +1200 Subject: [PATCH 086/335] ACS module error was missing newline --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b703b87dd..5a25dd5cd 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1417,7 +1417,7 @@ FBehavior *FBehavior::StaticLoadModule (int lumpnum, FileReader *fr, int len) else { delete behavior; - Printf(TEXTCOLOR_RED "%s: invalid ACS module", Wads.GetLumpFullName(lumpnum)); + Printf(TEXTCOLOR_RED "%s: invalid ACS module\n", Wads.GetLumpFullName(lumpnum)); return NULL; } } From f02b52ef28549a4d35adb122384ca873bdda7e64 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 13 Sep 2015 20:56:20 -0400 Subject: [PATCH 087/335] - Fixed: Initialization ordering warning in DPSpriteInterpolation. --- src/r_data/r_interpolate.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 46ac30789..6c2221520 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -866,11 +866,9 @@ void DPolyobjInterpolation::Serialize(FArchive &arc) //========================================================================== DPSpriteInterpolation::DPSpriteInterpolation(pspdef_t *_psp, int _player, int _position) -: nfsx(0), nfsy(0), ofsx(0), ofsy(0) +: psp(_psp), player(_player), position(_position), + ofsx(0), ofsy(0), nfsx(0), nfsy(0) { - psp = _psp; - player = _player; - position = _position; UpdateInterpolation (); interpolator.AddInterpolation(this); } From d7a04b9e98a14f6e10793505cee877ebf080d081 Mon Sep 17 00:00:00 2001 From: Blue-Shadow Date: Mon, 14 Sep 2015 17:22:41 +0300 Subject: [PATCH 088/335] dumpmapthings CCMD: Missing line break after "none". --- src/g_doomedmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 45224329d..08d5aa2e2 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -135,7 +135,7 @@ CCMD (dumpmapthings) } else { - Printf("%6d none", infos[i]->Key); + Printf("%6d none\n", infos[i]->Key); } } From ee7eb3253a70933098cebc2054caea8c22eb02cb Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 15 Sep 2015 16:45:20 +0300 Subject: [PATCH 089/335] Added compatibility flag for point-on-line algorithm It's possible to use original but buggy implementations of P_PointOnLineSide() and P_PointOnDivlineSide() function See http://forum.zdoom.org/viewtopic.php?f=2&t=49544 --- src/compatibility.cpp | 1 + src/d_main.cpp | 4 +++- src/doomdef.h | 1 + src/g_mapinfo.cpp | 1 + src/p_local.h | 10 ++++++++-- wadsrc/static/menudef.txt | 1 + 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index d60677f64..498fefb2a 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -145,6 +145,7 @@ static FCompatOption Options[] = { "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 }, { "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 }, { "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 }, + { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index 98be13e33..3b3cce1f4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -561,7 +561,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN| COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS|COMPATF_HITSCAN| COMPATF_WALLRUN|COMPATF_NOTOSSDROPS|COMPATF_LIGHT|COMPATF_MASKEDMIDTEX; - w = COMPATF2_BADANGLES|COMPATF2_FLOORMOVE; + w = COMPATF2_BADANGLES|COMPATF2_FLOORMOVE|COMPATF2_POINTONLINE; break; case 3: // Boom compat mode @@ -580,6 +580,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 6: // Boom with some added settings to reenable some 'broken' behavior v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_NO_PASSMOBJ| COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS; + w = COMPATF2_POINTONLINE; break; } @@ -622,6 +623,7 @@ CVAR (Flag, compat_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX); CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES); CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE); CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); +CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index c8aa66c17..802591386 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -340,6 +340,7 @@ enum COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW. COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom. COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less + COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSide() }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 49493667e..ac938797d 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1333,6 +1333,7 @@ MapFlagHandlers[] = { "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES }, { "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE }, { "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF }, + { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/p_local.h b/src/p_local.h index a8aaaeb0d..0e06ad72b 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -240,7 +240,10 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) { - return DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; + const SDWORD result = DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy); + return (compatflags2 & COMPATF2_POINTONLINE) + ? result >= 0 + : result > 0; } //========================================================================== @@ -254,7 +257,10 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) { - return DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0; + const SDWORD result = DMulScale32 (y-line->y, line->dx, line->x-x, line->dy); + return (compatflags2 & COMPATF2_POINTONLINE) + ? result >= 0 + : result > 0; } //========================================================================== diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index f15f91dff..b1ca44de7 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1303,6 +1303,7 @@ OptionMenu "CompatibilityOptions" Option "Find shortest textures like Doom", "compat_SHORTTEX", "YesNo" Option "Use buggier stair building", "compat_stairs", "YesNo" Option "Use Doom's floor motion behavior", "compat_floormove", "YesNo" + Option "Use Doom's point-on-line algorithm", "compat_pointonline", "YesNo" StaticText " " StaticText "Physics Behavior",1 From 39b18a3447c3960c31043dd73ec5f2dbf5e2bcca Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 15 Sep 2015 18:21:05 +0300 Subject: [PATCH 090/335] Improved point-on-line compatibility feature P_PointOnLineSide() and P_PointOnDivlineSide() functions from the initial Doom source code release are used in compatibility mode --- src/p_local.h | 16 +++++---- src/p_maputl.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 0e06ad72b..cb404eb8c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -240,10 +240,11 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) { - const SDWORD result = DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy); - return (compatflags2 & COMPATF2_POINTONLINE) - ? result >= 0 - : result > 0; + extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); + + return compatflags2 & COMPATF2_POINTONLINE + ? P_VanillaPointOnLineSide(x, y, line) + : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; } //========================================================================== @@ -257,10 +258,11 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) { - const SDWORD result = DMulScale32 (y-line->y, line->dx, line->x-x, line->dy); + extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); + return (compatflags2 & COMPATF2_POINTONLINE) - ? result >= 0 - : result > 0; + ? P_VanillaPointOnDivlineSide(x, y, line) + : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); } //========================================================================== diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 3a4a4c6a0..0a39460e7 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1523,3 +1523,92 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) } return NULL; } + +//=========================================================================== +// +// P_VanillaPointOnLineSide +// P_PointOnLineSide() from the initial Doom source code release +// +//=========================================================================== + +int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line) +{ + fixed_t dx; + fixed_t dy; + fixed_t left; + fixed_t right; + + if (!line->dx) + { + if (x <= line->v1->x) + return line->dy > 0; + + return line->dy < 0; + } + if (!line->dy) + { + if (y <= line->v1->y) + return line->dx < 0; + + return line->dx > 0; + } + + dx = (x - line->v1->x); + dy = (y - line->v1->y); + + left = FixedMul ( line->dy>>FRACBITS , dx ); + right = FixedMul ( dy , line->dx>>FRACBITS ); + + if (right < left) + return 0; // front side + return 1; // back side +} + +//=========================================================================== +// +// P_VanillaPointOnDivlineSide +// P_PointOnDivlineSide() from the initial Doom source code release +// +//=========================================================================== + +int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line) +{ + fixed_t dx; + fixed_t dy; + fixed_t left; + fixed_t right; + + if (!line->dx) + { + if (x <= line->x) + return line->dy > 0; + + return line->dy < 0; + } + if (!line->dy) + { + if (y <= line->y) + return line->dx < 0; + + return line->dx > 0; + } + + dx = (x - line->x); + dy = (y - line->y); + + // try to quickly decide by looking at sign bits + if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 ) + { + if ( (line->dy ^ dx) & 0x80000000 ) + return 1; // (left is negative) + return 0; + } + + left = FixedMul ( line->dy>>8, dx>>8 ); + right = FixedMul ( dy>>8 , line->dx>>8 ); + + if (right < left) + return 0; // front side + return 1; // back side +} + From fea2cb38cc3caf4a71922faf658c3524a19beccc Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 15 Sep 2015 19:27:05 +0300 Subject: [PATCH 091/335] Fixed compatibility flags comparison for point-on-line Now it works in both cases: for compatibility mode set by user and for internal compatibility handler --- src/p_local.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index cb404eb8c..95d7541a8 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -242,7 +242,7 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) { extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); - return compatflags2 & COMPATF2_POINTONLINE + return i_compatflags2 & COMPATF2_POINTONLINE ? P_VanillaPointOnLineSide(x, y, line) : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; } @@ -260,7 +260,7 @@ inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) { extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); - return (compatflags2 & COMPATF2_POINTONLINE) + return (i_compatflags2 & COMPATF2_POINTONLINE) ? P_VanillaPointOnDivlineSide(x, y, line) : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); } From 66437e32f6dec75e5692475ed737547d626bf1e4 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 15 Sep 2015 19:29:43 +0300 Subject: [PATCH 092/335] Added compatibility setting for Return to Hadron E1M9 See http://forum.zdoom.org/viewtopic.php?f=2&t=49544 --- wadsrc/static/compatibility.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 6cbe36af4..799168f75 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -401,3 +401,8 @@ D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29 { nopassover } + +D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 +{ + pointonline +} From f4b637db626412dcc3890689fcedb9b2aaeef490 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 15 Sep 2015 19:30:32 +0300 Subject: [PATCH 093/335] Changed compatibility fix for Nuke Mine E1M2 http://forum.zdoom.org/viewtopic.php?f=7&t=34013 --- wadsrc/static/compatibility.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 799168f75..3c41f871f 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -320,8 +320,7 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 7C1913DEE396BA26CFF22A0E9369B7D2 // Nuke Mine, e1m2 { - clearlinespecial 1107 - clearlinespecial 1108 + pointonline } 5B862477519B21B30059A466F2FF6460 // Khorus, map08 From 6ee0672885b5856899efc6214d3ea203b28f7ac9 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 16 Sep 2015 13:36:18 +0300 Subject: [PATCH 094/335] Fixed missing hit sound for Heretic weapon Dragon Claw See http://forum.zdoom.org/viewtopic.php?f=2&t=49459 --- wadsrc/static/actors/heretic/hereticweaps.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/heretic/hereticweaps.txt b/wadsrc/static/actors/heretic/hereticweaps.txt index 711c3fd29..f0db7caf2 100644 --- a/wadsrc/static/actors/heretic/hereticweaps.txt +++ b/wadsrc/static/actors/heretic/hereticweaps.txt @@ -802,6 +802,7 @@ ACTOR BlasterPuff +NOGRAVITY +PUFFONACTORS RenderStyle Add + SeeSound "weapons/blasterhit" States { Crash: From b2fa4970fd57773f5f3353fa64af6a3480177009 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 16 Sep 2015 16:13:56 +0300 Subject: [PATCH 095/335] Fixed potential crash in ACS engine Unknown p-code in compiled script may lead to a crash if the current module was changed during script execution, e.g. by function call See http://forum.zdoom.org/viewtopic.php?f=2&t=48524 --- src/p_acs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b85ae28e1..f4d148d09 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6032,6 +6032,7 @@ int DLevelScript::RunScript () int sp = 0; int *pc = this->pc; ACSFormat fmt = activeBehavior->GetFormat(); + FBehavior* const savedActiveBehavior = activeBehavior; unsigned int runaway = 0; // used to prevent infinite loops int pcd; FString work; @@ -6065,6 +6066,7 @@ int DLevelScript::RunScript () { default: Printf ("Unknown P-Code %d in %s\n", pcd, ScriptPresentation(script).GetChars()); + activeBehavior = savedActiveBehavior; // fall through case PCD_TERMINATE: DPrintf ("%s finished\n", ScriptPresentation(script).GetChars()); From 924a2aaaa7e12bf1ddb3fa1991735a4fe1be1e96 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 16 Sep 2015 16:56:43 +0300 Subject: [PATCH 096/335] Added "support" for PCD_CONSOLECOMMAND in ACS Now attempt to execute a console command from a script will not terminate its execution An error message will be issued in the console on every such attempt --- src/p_acs.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f4d148d09..63ab71717 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -75,6 +75,7 @@ #include "actorptrselect.h" #include "farchive.h" #include "decallib.h" +#include "version.h" #include "g_shared/a_pickups.h" @@ -9357,6 +9358,10 @@ scriptwait: } break; + case PCD_CONSOLECOMMAND: + Printf (TEXTCOLOR_RED GAMENAME " doesn't support execution of console commands from scripts\n"); + sp -= 3; + break; } } From 4de57cd2967236a31b8206aec2a04c026a8c2b87 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 17 Sep 2015 10:14:54 +0300 Subject: [PATCH 097/335] Fixed compatibility issues on MAP25 of Eternal Doom See http://forum.zdoom.org/viewtopic.php?f=2&t=49577 --- wadsrc/static/compatibility.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 3c41f871f..1bd031ed8 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -55,6 +55,8 @@ A80E7EE40E0D0C76A6FBD242BE29FE27 // map15 { stairs maskedmidtex + corpsegibs + vileghosts } 10E1E2B36302D31AC4AE68C84B5DC457 // Eternal Doom MAP28 @@ -125,7 +127,6 @@ BA530202AF0BA0C6CBAE6A0C7076FB72 // Requiem map04 CBDFEFAC579A62DE8F1B48CA4A09D381 // gather2.wad map05 and darkside.wad map01 C7A2FAFB0AFB2632C50AD625CDB50E51 // Reverie map18 9E5724BC6135AA6F86EE54FD4D91F1E2 // Project X map14 -6DA6FCBA8089161BDEC6A1D3F6C8D60F // Eternal Doom map25 01899825FFEAE016D39C02A7DA4B218F // Archie map01 1D9F3AFDC2517C2E450491ED13896712 // Seej map01 0AE745A3AB86D15FB2FB74489962C421 // 6pack2 map02 From 67305258553c2c3b79de90bc7ea4ce4ebeb572c4 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 17 Sep 2015 09:07:13 -0500 Subject: [PATCH 098/335] - Added A_SetPainThreshold for the calling actor('s pointer). --- src/thingdef/thingdef_codeptr.cpp | 22 ++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 2 files changed, 23 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dab68867b..6dcadf0ea 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5111,6 +5111,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) ref->FloatSpeed = speed; } +//========================================================================== +// +// A_SetPainThreshold +// +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPainThreshold) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_INT(threshold, 0); + ACTION_PARAM_INT(ptr, 1); + + AActor *ref = COPY_AAPTR(self, ptr); + + if (!ref) + { + ACTION_SET_RESULT(false); + return; + } + + ref->PainThreshold = threshold; +} + //=========================================================================== // // Common A_Damage handler diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5877192ce..723e5bafd 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -305,6 +305,7 @@ ACTOR Actor native //: Thinker action native A_DropItem(class item, int dropamount = -1, int chance = 256); action native A_SetSpeed(float speed, int ptr = AAPTR_DEFAULT); action native A_SetFloatSpeed(float speed, int ptr = AAPTR_DEFAULT); + action native A_SetPainThreshold(int threshold, int ptr = AAPTR_DEFAULT); action native A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); action native A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); action native A_DamageMaster(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); From 621116a289d6066889eefd02693b60117795429d Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 18 Sep 2015 10:53:46 +0300 Subject: [PATCH 099/335] Disabled loading of SDL output plugin for FMOD Ex on OS X Long path to executable file corrupts stack inside FMOD library This plugin is not being built for OS X, output through CoreAudio works just fine --- src/sound/fmodsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 8433b301b..33ca0495d 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -771,7 +771,7 @@ bool FMODSoundRenderer::Init() } #endif -#ifndef _WIN32 +#if !defined _WIN32 && !defined __APPLE__ // Try to load SDL output plugin result = Sys->setPluginPath(progdir); // Should we really look for it in the program directory? result = Sys->loadPlugin("liboutput_sdl.so", &OutputPlugin); From b613db4ae5c05655a93792671b50b41d4b4c80d4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Sep 2015 17:41:16 +0200 Subject: [PATCH 100/335] Revert "Merge pull request #359 from Leonard2/master" This reverts commit 364ca11b43d8f4cd736506918f5c1fdb63721235, reversing changes made to dae0e217d1f16260c6e94a3d5db5a8dfcf117ecb. Conflicts: src/r_data/r_interpolate.cpp --- src/d_player.h | 1 - src/g_game.cpp | 9 -- src/p_pspr.cpp | 21 ---- src/p_pspr.h | 6 -- src/p_saveg.cpp | 5 - src/p_user.cpp | 15 --- src/r_data/r_interpolate.cpp | 196 +---------------------------------- src/version.h | 2 +- 8 files changed, 4 insertions(+), 251 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 2ac2ad0d5..e27bf1087 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -427,7 +427,6 @@ public: short fixedcolormap; // can be set to REDCOLORMAP, etc. short fixedlightlevel; pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) - TObjPtr pspinterp[NUMPSPRITES]; // view sprite interpolations int morphTics; // player is a chicken/pig if > 0 const PClass *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed diff --git a/src/g_game.cpp b/src/g_game.cpp index f77949687..8101ca23d 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1726,15 +1726,6 @@ void G_DoPlayerPop(int playernum) players[playernum].mo = NULL; players[playernum].camera = NULL; } - // Now's the ideal time to remove his psprite interpolations. - for (int ii = 0; ii < NUMPSPRITES; ii++) - { - if (players[playernum].psprites[ii].interpolation != NULL) - { - players[playernum].psprites[ii].StopInterpolation(); - players[playernum].pspinterp[ii] = NULL; - } - } // [RH] Let the scripts know the player left FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index d2bf8cc87..63f3bc648 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1104,32 +1104,11 @@ void P_MovePsprites (player_t *player) P_CheckWeaponZoom (player); } } - - psp = &player->psprites[0]; - for (i = 0; i < NUMPSPRITES; i++, psp++) - { - if (psp->state == NULL) - { - if (psp->interpolation != NULL) - { - player->pspinterp[i] = NULL; - psp->StopInterpolation(); - } - } - else if (psp->interpolation == NULL) - { - player->pspinterp[i] = psp->SetInterpolation(player - players, i); - } - } } FArchive &operator<< (FArchive &arc, pspdef_t &def) { arc << def.state << def.tics << def.sx << def.sy << def.sprite << def.frame; - - if (SaveVersion >= 4525) - arc << def.interpolation; - return arc; } diff --git a/src/p_pspr.h b/src/p_pspr.h index 62c2a6fe4..ca9b45ee8 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -26,7 +26,6 @@ // Basic data types. // Needs fixed point, and BAM angles. #include "tables.h" -#include "r_data/r_interpolate.h" #include "thingdef/thingdef.h" #define WEAPONBOTTOM 128*FRACUNIT @@ -72,11 +71,6 @@ struct pspdef_t int sprite; int frame; bool processPending; // true: waiting for periodic processing on this tick - - TObjPtr interpolation; - DInterpolation *SetInterpolation(int player, int position); - void UpdateInterpolation(int player); - void StopInterpolation(); }; class FArchive; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index f16bdb0f9..480494320 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -297,11 +297,6 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name) { dst->mo->player = dst; } - // Fix the psprite interpolation pointers too. - for (int i = 0; i < NUMPSPRITES; i++) - { - dst->psprites[i].UpdateInterpolation(dst - players); - } // These 2 variables may not be overwritten. dst->attackdown = attackdown; dst->usedown = usedown; diff --git a/src/p_user.cpp b/src/p_user.cpp index ced6732a3..0d5cdce20 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -316,7 +316,6 @@ player_t::player_t() memset (&cmd, 0, sizeof(cmd)); memset (frags, 0, sizeof(frags)); memset (psprites, 0, sizeof(psprites)); - memset (pspinterp, 0, sizeof(pspinterp)); } player_t &player_t::operator=(const player_t &p) @@ -372,7 +371,6 @@ player_t &player_t::operator=(const player_t &p) fixedcolormap = p.fixedcolormap; fixedlightlevel = p.fixedlightlevel; memcpy(psprites, &p.psprites, sizeof(psprites)); - memcpy(pspinterp, &p.pspinterp, sizeof(pspinterp)); morphTics = p.morphTics; MorphedPlayerClass = p.MorphedPlayerClass; MorphStyle = p.MorphStyle; @@ -437,10 +435,6 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep) if (*&ConversationNPC == old) ConversationNPC = replacement, changed++; if (*&ConversationPC == old) ConversationPC = replacement, changed++; if (*&MUSINFOactor == old) MUSINFOactor = replacement, changed++; - - for (int i = 0; i < NUMPSPRITES; i++) - if (*&pspinterp[i] == old) pspinterp[i] = static_cast(rep), changed++; - return changed; } @@ -460,11 +454,6 @@ size_t player_t::PropagateMark() { GC::Mark(PendingWeapon); } - for (int i = 0; i < NUMPSPRITES; i++) - { - GC::Mark(pspinterp[i]); - } - return sizeof(*this); } @@ -3063,11 +3052,7 @@ void player_t::Serialize (FArchive &arc) for (i = 0; i < MAXPLAYERS; i++) arc << frags[i]; for (i = 0; i < NUMPSPRITES; i++) - { arc << psprites[i]; - if (SaveVersion >= 4525) - arc << pspinterp[i]; - } arc << CurrentPlayerClass; diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 6c2221520..3ca3b557c 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -151,35 +151,6 @@ public: }; -//========================================================================== -// -// -// -//========================================================================== - -class DPSpriteInterpolation : public DInterpolation -{ - DECLARE_CLASS(DPSpriteInterpolation, DInterpolation) - - pspdef_t *psp; - int player, position; - fixed_t oldx, oldy; - fixed_t bakx, baky; - fixed_t ofsx, ofsy; - fixed_t nfsx, nfsy; - -public: - - DPSpriteInterpolation() {} - DPSpriteInterpolation(pspdef_t *psp, int player, int position); - void UpdatePointer(int player); - void Destroy(); - void UpdateInterpolation(); - void Restore(); - void Interpolate(fixed_t smoothratio); - void Serialize(FArchive &arc); -}; - //========================================================================== // // @@ -191,7 +162,6 @@ IMPLEMENT_CLASS(DSectorPlaneInterpolation) IMPLEMENT_CLASS(DSectorScrollInterpolation) IMPLEMENT_CLASS(DWallScrollInterpolation) IMPLEMENT_CLASS(DPolyobjInterpolation) -IMPLEMENT_CLASS(DPSpriteInterpolation) //========================================================================== // @@ -658,6 +628,7 @@ void DSectorScrollInterpolation::Serialize(FArchive &arc) arc << sector << ceiling << oldx << oldy; } + //========================================================================== // // @@ -853,113 +824,6 @@ void DPolyobjInterpolation::Serialize(FArchive &arc) if (arc.IsLoading()) bakverts.Resize(oldverts.Size()); } -//========================================================================== -// -// -// -//========================================================================== - -//========================================================================== -// -// -// -//========================================================================== - -DPSpriteInterpolation::DPSpriteInterpolation(pspdef_t *_psp, int _player, int _position) -: psp(_psp), player(_player), position(_position), - ofsx(0), ofsy(0), nfsx(0), nfsy(0) -{ - UpdateInterpolation (); - interpolator.AddInterpolation(this); -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::UpdatePointer(int _player) -{ - player = _player; - psp = &players[player].psprites[position]; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::Destroy() -{ - psp->interpolation = NULL; - Super::Destroy(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::UpdateInterpolation() -{ - if ( position == ps_weapon ) - P_BobWeapon( &players[player], psp, &ofsx, &ofsy ); - - oldx = psp->sx + ofsx; - oldy = psp->sy + ofsy; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::Restore() -{ - psp->sx = bakx - nfsx; - psp->sy = baky - nfsy; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::Interpolate(fixed_t smoothratio) -{ - if ( position == ps_weapon ) - P_BobWeapon( &players[player], psp, &nfsx, &nfsy ); - - bakx = psp->sx + nfsx; - baky = psp->sy + nfsy; - - psp->sx = oldx + FixedMul(bakx - oldx, smoothratio) - nfsx; - psp->sy = oldy + FixedMul(baky - oldy, smoothratio) - nfsy; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DPSpriteInterpolation::Serialize(FArchive &arc) -{ - Super::Serialize(arc); - arc << player << position << oldx << oldy << ofsx << ofsy; - UpdatePointer(player); -} - -//========================================================================== -// -// -// -//========================================================================== //========================================================================== // @@ -1080,62 +944,6 @@ void FPolyObj::StopInterpolation() } } -//========================================================================== -// -// -// -//========================================================================== - -DInterpolation *pspdef_t::SetInterpolation(int player, int position) -{ - if (interpolation == NULL) - { - interpolation = new DPSpriteInterpolation(this, player, position); - } - interpolation->AddRef(); - GC::WriteBarrier(interpolation); - return interpolation; -} - -//========================================================================== -// -// -// -//========================================================================== - -void pspdef_t::UpdateInterpolation(int player) -{ - if (interpolation != NULL) - { - barrier_cast(interpolation)->UpdatePointer(player); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void pspdef_t::StopInterpolation() -{ - if (interpolation != NULL) - { - interpolation->DelRef(); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -//========================================================================== -// -// -// -//========================================================================== ADD_STAT (interpolations) { @@ -1143,3 +951,5 @@ ADD_STAT (interpolations) out.Format ("%d interpolations", interpolator.CountInterpolations ()); return out; } + + diff --git a/src/version.h b/src/version.h index 168cb7519..913c9bd18 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4525 +#define SAVEVER 4524 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 98bdbb1ad8c9d7e06a5a7d2ed2e64779b12c097d Mon Sep 17 00:00:00 2001 From: ZzZombo Date: Sat, 19 Sep 2015 09:40:19 +0800 Subject: [PATCH 101/335] -Fixed PCD_DROP affecting script result value. --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 63ab71717..4e5875836 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7274,9 +7274,9 @@ int DLevelScript::RunScript () sp--; break; - case PCD_DROP: case PCD_SETRESULTVALUE: resultValue = STACK(1); + case PCD_DROP: //fall through. sp--; break; From 49519db257d1c717e6d0cf36bb8dfc5086e79064 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Sep 2015 18:29:07 +0300 Subject: [PATCH 102/335] Fixed crash in RandomSpawner with -nomonsters See http://forum.zdoom.org/viewtopic.php?f=2&t=49520 --- src/g_shared/a_randomspawner.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index adfc09b6e..e8650c07f 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -19,6 +19,18 @@ #define MAX_RANDOMSPAWNERS_RECURSION 32 // Should be largely more than enough, honestly. static FRandom pr_randomspawn("RandomSpawn"); +static bool IsMonster(const FDropItem *di) +{ + const PClass *pclass = PClass::FindClass(di->Name); + + if (NULL == pclass) + { + return false; + } + + return GetDefaultByType(pclass)->flags3 & MF3_ISMONSTER; +} + class ARandomSpawner : public AActor { DECLARE_CLASS (ARandomSpawner, AActor) @@ -41,7 +53,7 @@ class ARandomSpawner : public AActor { if (di->Name != NAME_None) { - if (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER)) + if (!nomonsters || !IsMonster(di)) { if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value. n += di->amount; // this is how we can weight the list. @@ -62,7 +74,7 @@ class ARandomSpawner : public AActor while (n > -1 && di != NULL) { if (di->Name != NAME_None && - (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER))) + (!nomonsters || !IsMonster(di))) { n -= di->amount; if ((di->Next != NULL) && (n > -1)) From 96ff7160463b93fb9d9401274b16f81dfaf097eb Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Sep 2015 18:29:59 +0300 Subject: [PATCH 103/335] Added error message about missing class to drop from RandomSpawner --- src/g_shared/a_randomspawner.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index e8650c07f..160766fa7 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -15,6 +15,7 @@ #include "gstrings.h" #include "a_action.h" #include "thingdef/thingdef.h" +#include "v_text.h" #define MAX_RANDOMSPAWNERS_RECURSION 32 // Should be largely more than enough, honestly. static FRandom pr_randomspawn("RandomSpawn"); @@ -118,6 +119,7 @@ class ARandomSpawner : public AActor } else { + Printf(TEXTCOLOR_RED "Unknown item class %s to drop from a random spawner\n", di->Name.GetChars()); Species = NAME_None; } } From 23577f4be8c3cf4cdd9dbf73043bb3702cb77116 Mon Sep 17 00:00:00 2001 From: khokh2001 Date: Sun, 20 Sep 2015 02:11:03 +0900 Subject: [PATCH 104/335] nuked opl emulator update --- src/oplsynth/nukedopl3.cpp | 433 ++++++++++++++++++++----------------- src/oplsynth/nukedopl3.h | 15 +- 2 files changed, 248 insertions(+), 200 deletions(-) diff --git a/src/oplsynth/nukedopl3.cpp b/src/oplsynth/nukedopl3.cpp index 4d143f4a5..0baa67bda 100644 --- a/src/oplsynth/nukedopl3.cpp +++ b/src/oplsynth/nukedopl3.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2014 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,53 +27,31 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 /* Changelog: v1.1: - Vibrato's sign fix + Vibrato's sign fix. v1.2: - Operator key fix - Corrected 4-operator mode - Corrected rhythm mode - Some small fixes - v1.2.1: - Small envelope generator fix - Removed EX_Get function(not used) - v1.3: - Complete rewrite - (Not released) - v1.4: - New envelope and waveform generator + Operator key fix. + Corrected 4-operator mode. + Corrected rhythm mode. + Some small fixes. + v1.2.1: + Small envelope generator fix. + v1.3: + Complete rewrite. + v1.4: + New envelope and waveform generator. Some small fixes. - (Not released) v1.4.1: - Envelope generator rate calculation fix - (Not released) + Envelope generator rate calculation fix. v1.4.2: Version for ZDoom. v1.5: - Optimizations -*/ - - -/* Verified: - Noise generator. - Waveform generator. - Envelope generator increase table. - Tremolo. -*/ - -/* TODO: - Verify: - kslrom[15] value(is it 128?). - Sustain level = 15. - Vibrato, Phase generator. - Rhythm part. - Envelope generator state switching(decay->sustain when egt = 1 and decay->release). - Feedback. - Register write. - 4-operator. + Optimizations. + v1.6: + Improved emulation output. */ #include @@ -216,19 +194,17 @@ envelope_sinfunc envelope_sin[8] = { }; void envelope_gen_off(opl_slot *slott); -void envelope_gen_change(opl_slot *slott); void envelope_gen_attack(opl_slot *slott); void envelope_gen_decay(opl_slot *slott); void envelope_gen_sustain(opl_slot *slott); void envelope_gen_release(opl_slot *slott); -envelope_genfunc envelope_gen[6] = { +envelope_genfunc envelope_gen[5] = { envelope_gen_off, envelope_gen_attack, envelope_gen_decay, envelope_gen_sustain, - envelope_gen_release, - envelope_gen_change + envelope_gen_release }; enum envelope_gen_num { @@ -252,7 +228,7 @@ Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { } void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20; + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } @@ -281,28 +257,25 @@ void envelope_gen_off(opl_slot *slot) { slot->eg_rout = 0x1ff; } -void envelope_gen_change(opl_slot *slot) { - slot->eg_gen = slot->eg_gennext; - envelope_update_rate(slot); -} - void envelope_gen_attack(opl_slot *slot) { + if (slot->eg_rout == 0x00) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + return; + } slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; if (slot->eg_rout < 0x00) { slot->eg_rout = 0x00; } - if (!slot->eg_rout) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_decay; - } } void envelope_gen_decay(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_sustain; + slot->eg_gen = envelope_gen_num_sustain; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_gen_sustain(opl_slot *slot) { @@ -312,11 +285,13 @@ void envelope_gen_sustain(opl_slot *slot) { } void envelope_gen_release(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_off; + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_calc(opl_slot *slot) { @@ -324,10 +299,7 @@ void envelope_calc(opl_slot *slot) { rate_h = slot->eg_rate >> 2; rate_l = slot->eg_rate & 3; Bit8u inc = 0; - if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { - inc = 8; - } - else if (eg_incsh[rate_h] > 0) { + if (eg_incsh[rate_h] > 0) { if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; } @@ -336,14 +308,19 @@ void envelope_calc(opl_slot *slot) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); } slot->eg_inc = inc; - envelope_gen[slot->eg_gen](slot); slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); } void eg_keyon(opl_slot *slot, Bit8u type) { if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_attack; + slot->eg_gen = envelope_gen_num_attack; + envelope_update_rate(slot); + if ((slot->eg_rate >> 2) == 0x0f) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + slot->eg_rout = 0x00; + } slot->pg_phase = 0x00; } slot->key |= type; @@ -353,8 +330,8 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { if (slot->key) { slot->key &= (~type); if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_release; + slot->eg_gen = envelope_gen_num_release; + envelope_update_rate(slot); } } } @@ -366,7 +343,7 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { void pg_generate(opl_slot *slot) { Bit16u f_num = slot->channel->f_num; if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb)); + Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; } slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; @@ -387,7 +364,7 @@ void n_generate(opl_chip *chip) { // Slot // -void slot_write20(opl_slot *slot,Bit8u data) { +void slot_write20(opl_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { slot->trem = &slot->chip->tremval; } @@ -434,14 +411,14 @@ void slot_generatephase(opl_slot *slot, Bit16u phase) { } void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); } void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); } -void slot_calgfb(opl_slot *slot) { +void slot_calcfb(opl_slot *slot) { slot->prout[1] = slot->prout[0]; slot->prout[0] = slot->out; if (slot->channel->fb != 0x00) { @@ -461,57 +438,61 @@ void chan_setupalg(opl_channel *channel); void chan_updaterhythm(opl_chip *chip, Bit8u data) { chip->rhy = data & 0x3f; if (chip->rhy & 0x20) { - chip->channel[6].out[0] = &chip->slot[13].out; - chip->channel[6].out[1] = &chip->slot[13].out; - chip->channel[6].out[2] = &chip->zeromod; - chip->channel[6].out[3] = &chip->zeromod; - chip->channel[7].out[0] = &chip->slot[14].out; - chip->channel[7].out[1] = &chip->slot[14].out; - chip->channel[7].out[2] = &chip->slot[15].out; - chip->channel[7].out[3] = &chip->slot[15].out; - chip->channel[8].out[0] = &chip->slot[16].out; - chip->channel[8].out[1] = &chip->slot[16].out; - chip->channel[8].out[2] = &chip->slot[17].out; - chip->channel[8].out[3] = &chip->slot[17].out; + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + channel6->out[0] = &channel6->slots[1]->out; + channel6->out[1] = &channel6->slots[1]->out; + channel6->out[2] = &chip->zeromod; + channel6->out[3] = &chip->zeromod; + channel7->out[0] = &channel7->slots[0]->out; + channel7->out[1] = &channel7->slots[0]->out; + channel7->out[2] = &channel7->slots[1]->out; + channel7->out[3] = &channel7->slots[1]->out; + channel8->out[0] = &channel8->slots[0]->out; + channel8->out[1] = &channel8->slots[0]->out; + channel8->out[2] = &channel8->slots[1]->out; + channel8->out[3] = &channel8->slots[1]->out; for (Bit8u chnum = 6; chnum < 9; chnum++) { chip->channel[chnum].chtype = ch_drum; } + chan_setupalg(channel6); //hh if (chip->rhy & 0x01) { - eg_keyon(&chip->slot[14], egk_drum); + eg_keyon(channel7->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[14], egk_drum); + eg_keyoff(channel7->slots[0], egk_drum); } //tc if (chip->rhy & 0x02) { - eg_keyon(&chip->slot[17], egk_drum); + eg_keyon(channel8->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[17], egk_drum); + eg_keyoff(channel8->slots[1], egk_drum); } //tom if (chip->rhy & 0x04) { - eg_keyon(&chip->slot[16], egk_drum); + eg_keyon(channel8->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[16], egk_drum); + eg_keyoff(channel8->slots[0], egk_drum); } //sd if (chip->rhy & 0x08) { - eg_keyon(&chip->slot[15], egk_drum); + eg_keyon(channel7->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[15], egk_drum); + eg_keyoff(channel7->slots[1], egk_drum); } //bd if (chip->rhy & 0x10) { - eg_keyon(&chip->slot[12], egk_drum); - eg_keyon(&chip->slot[13], egk_drum); + eg_keyon(channel6->slots[0], egk_drum); + eg_keyon(channel6->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[12], egk_drum); - eg_keyoff(&chip->slot[13], egk_drum); + eg_keyoff(channel6->slots[0], egk_drum); + eg_keyoff(channel6->slots[1], egk_drum); } } else { @@ -566,6 +547,16 @@ void chan_writeb0(opl_channel *channel, Bit8u data) { void chan_setupalg(opl_channel *channel) { if (channel->chtype == ch_drum) { + switch (channel->alg & 0x01) { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } return; } if (channel->alg & 0x08) { @@ -672,49 +663,39 @@ void chan_writec0(opl_channel *channel, Bit8u data) { } } -void chan_generaterhythm(opl_chip *chip) { - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - slot_generate(channel6->slots[1]); - Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff; - Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tt - slot_generatezm(channel8->slots[0]); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); - } +void chan_generaterhythm1(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[0]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + slot_generatephase(channel7->slots[0], phase); + //tt + slot_generatezm(channel8->slots[0]); } -void chan_generate(opl_channel *channel) { - if (channel->chtype == ch_drum) { - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - slot_generate(channel->pair->slots[0]); - slot_generate(channel->pair->slots[1]); - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } - else { - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } +void chan_generaterhythm2(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[1]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + slot_generatephase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + slot_generatephase(channel8->slots[1], phase); } void chan_enable(opl_channel *channel) { @@ -782,21 +763,132 @@ Bit16s limshort(Bit32s a) { return (Bit16s)a; } +void chip_generate(opl_chip *chip, Bit16s *buff) { + buff[1] = limshort(chip->mixbuff[1]); + + for (Bit8u ii = 0; ii < 12; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + for (Bit8u ii = 12; ii < 15; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm1(chip); + } + else { + slot_generate(&chip->slot[12]); + slot_generate(&chip->slot[13]); + slot_generate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); + } + else { + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + } + + for (Bit8u ii = 15; ii < 18; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm2(chip); + } + else { + slot_generate(&chip->slot[15]); + slot_generate(&chip->slot[16]); + slot_generate(&chip->slot[17]); + } + + buff[0] = limshort(chip->mixbuff[0]); + + for (Bit8u ii = 18; ii < 33; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); + } + else { + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + } + + for (Bit8u ii = 33; ii < 36; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + n_generate(chip); + + if ((chip->timer & 0x3f) == 0x3f) { + if (!chip->tremdir) { + if (chip->tremtval == 105) { + chip->tremtval--; + chip->tremdir = 1; + } + else { + chip->tremtval++; + } + } + else { + if (chip->tremtval == 0) { + chip->tremtval++; + chip->tremdir = 0; + } + else { + chip->tremtval--; + } + } + chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); + } + + chip->timer++; +} + void NukedOPL3::Reset() { memset(&opl3, 0, sizeof(opl_chip)); for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2]; opl3.slot[slotnum].chip = &opl3; opl3.slot[slotnum].mod = &opl3.zeromod; opl3.slot[slotnum].eg_rout = 0x1ff; opl3.slot[slotnum].eg_out = 0x1ff; opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].eg_gennext = envelope_gen_num_off; opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; } for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[2 * channum]; - opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1]; + opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; + opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; + opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; + opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; if ((channum % 9) < 3) { opl3.channel[channum].pair = &opl3.channel[channum + 3]; } @@ -816,6 +908,8 @@ void NukedOPL3::Reset() { chan_setupalg(&opl3.channel[channum]); } opl3.noise = 0x306600; + opl3.timer = 0; + opl3.FullPan = FullPan; } void NukedOPL3::WriteReg(int reg, int v) { @@ -903,58 +997,11 @@ void NukedOPL3::WriteReg(int reg, int v) { } void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit32s outa, outb; + Bit16s buffer[2]; for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - outa = 0; - outb = 0; - for (Bit8u ii = 0; ii < 36; ii++) { - slot_calgfb(&opl3.slot[ii]); - } - chan_generaterhythm(&opl3); - for (Bit8u ii = 0; ii < 18; ii++) { - chan_generate(&opl3.channel[ii]); - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *opl3.channel[ii].out[jj]; - } - if (FullPan) { - outa += (Bit16s)(accm * opl3.channel[ii].fcha); - outb += (Bit16s)(accm * opl3.channel[ii].fchb); - } - else { - outa += (Bit16s)(accm & opl3.channel[ii].cha); - outb += (Bit16s)(accm & opl3.channel[ii].chb); - } - } - for (Bit8u ii = 0; ii < 36; ii++) { - envelope_calc(&opl3.slot[ii]); - pg_generate(&opl3.slot[ii]); - } - n_generate(&opl3); - opl3.timer++; - if (!(opl3.timer & 0x3f)) { - if (!opl3.tremdir) { - if (opl3.tremtval == 105) { - opl3.tremtval--; - opl3.tremdir = 1; - } - else { - opl3.tremtval++; - } - } - else { - if (opl3.tremtval == 0) { - opl3.tremtval++; - opl3.tremdir = 0; - } - else { - opl3.tremtval--; - } - } - opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1); - } - *sndptr++ += (float)(outa / 10240.0); - *sndptr++ += (float)(outb / 10240.0); + chip_generate(&opl3, buffer); + *sndptr++ += (float)(buffer[0] / 10240.0); + *sndptr++ += (float)(buffer[1] / 10240.0); } } diff --git a/src/oplsynth/nukedopl3.h b/src/oplsynth/nukedopl3.h index ccf37fe14..849646f5f 100644 --- a/src/oplsynth/nukedopl3.h +++ b/src/oplsynth/nukedopl3.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 #include "opl.h" #include "muslib.h" @@ -116,7 +116,7 @@ static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, // ksl table // -static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; +static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; @@ -133,7 +133,7 @@ static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; static const Bit8u eg_incstep[3][4][8] = { { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, + { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } }, { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } }; @@ -149,8 +149,8 @@ static const Bit8s eg_incsh[16] = { // address decoding // -static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - +static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; struct opl_chip; struct opl_slot; @@ -167,7 +167,6 @@ struct opl_slot { Bit16s eg_out; Bit8u eg_inc; Bit8u eg_gen; - Bit8u eg_gennext; Bit8u eg_rate; Bit8u eg_ksl; Bit8u *trem; @@ -217,6 +216,8 @@ struct opl_chip { Bit8u tremdir; Bit32u noise; Bit16s zeromod; + Bit32s mixbuff[2]; + Bit8u FullPan; }; From b1b17beaf6b027ef061b3da6683dcf8b351d323a Mon Sep 17 00:00:00 2001 From: khokh2001 Date: Sun, 20 Sep 2015 02:11:03 +0900 Subject: [PATCH 105/335] nuked opl emulator update --- src/oplsynth/nukedopl3.cpp | 433 ++++++++++++++++++++----------------- src/oplsynth/nukedopl3.h | 15 +- 2 files changed, 248 insertions(+), 200 deletions(-) diff --git a/src/oplsynth/nukedopl3.cpp b/src/oplsynth/nukedopl3.cpp index 4d143f4a5..c99c5c55b 100644 --- a/src/oplsynth/nukedopl3.cpp +++ b/src/oplsynth/nukedopl3.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,53 +27,31 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 /* Changelog: v1.1: - Vibrato's sign fix + Vibrato's sign fix. v1.2: - Operator key fix - Corrected 4-operator mode - Corrected rhythm mode - Some small fixes - v1.2.1: - Small envelope generator fix - Removed EX_Get function(not used) - v1.3: - Complete rewrite - (Not released) - v1.4: - New envelope and waveform generator + Operator key fix. + Corrected 4-operator mode. + Corrected rhythm mode. + Some small fixes. + v1.2.1: + Small envelope generator fix. + v1.3: + Complete rewrite. + v1.4: + New envelope and waveform generator. Some small fixes. - (Not released) v1.4.1: - Envelope generator rate calculation fix - (Not released) + Envelope generator rate calculation fix. v1.4.2: Version for ZDoom. v1.5: - Optimizations -*/ - - -/* Verified: - Noise generator. - Waveform generator. - Envelope generator increase table. - Tremolo. -*/ - -/* TODO: - Verify: - kslrom[15] value(is it 128?). - Sustain level = 15. - Vibrato, Phase generator. - Rhythm part. - Envelope generator state switching(decay->sustain when egt = 1 and decay->release). - Feedback. - Register write. - 4-operator. + Optimizations. + v1.6: + Improved emulation output. */ #include @@ -216,19 +194,17 @@ envelope_sinfunc envelope_sin[8] = { }; void envelope_gen_off(opl_slot *slott); -void envelope_gen_change(opl_slot *slott); void envelope_gen_attack(opl_slot *slott); void envelope_gen_decay(opl_slot *slott); void envelope_gen_sustain(opl_slot *slott); void envelope_gen_release(opl_slot *slott); -envelope_genfunc envelope_gen[6] = { +envelope_genfunc envelope_gen[5] = { envelope_gen_off, envelope_gen_attack, envelope_gen_decay, envelope_gen_sustain, - envelope_gen_release, - envelope_gen_change + envelope_gen_release }; enum envelope_gen_num { @@ -252,7 +228,7 @@ Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { } void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20; + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } @@ -281,28 +257,25 @@ void envelope_gen_off(opl_slot *slot) { slot->eg_rout = 0x1ff; } -void envelope_gen_change(opl_slot *slot) { - slot->eg_gen = slot->eg_gennext; - envelope_update_rate(slot); -} - void envelope_gen_attack(opl_slot *slot) { + if (slot->eg_rout == 0x00) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + return; + } slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; if (slot->eg_rout < 0x00) { slot->eg_rout = 0x00; } - if (!slot->eg_rout) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_decay; - } } void envelope_gen_decay(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_sustain; + slot->eg_gen = envelope_gen_num_sustain; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_gen_sustain(opl_slot *slot) { @@ -312,11 +285,13 @@ void envelope_gen_sustain(opl_slot *slot) { } void envelope_gen_release(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_off; + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_calc(opl_slot *slot) { @@ -324,10 +299,7 @@ void envelope_calc(opl_slot *slot) { rate_h = slot->eg_rate >> 2; rate_l = slot->eg_rate & 3; Bit8u inc = 0; - if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { - inc = 8; - } - else if (eg_incsh[rate_h] > 0) { + if (eg_incsh[rate_h] > 0) { if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; } @@ -336,14 +308,19 @@ void envelope_calc(opl_slot *slot) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); } slot->eg_inc = inc; - envelope_gen[slot->eg_gen](slot); slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); } void eg_keyon(opl_slot *slot, Bit8u type) { if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_attack; + slot->eg_gen = envelope_gen_num_attack; + envelope_update_rate(slot); + if ((slot->eg_rate >> 2) == 0x0f) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + slot->eg_rout = 0x00; + } slot->pg_phase = 0x00; } slot->key |= type; @@ -353,8 +330,8 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { if (slot->key) { slot->key &= (~type); if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_release; + slot->eg_gen = envelope_gen_num_release; + envelope_update_rate(slot); } } } @@ -366,7 +343,7 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { void pg_generate(opl_slot *slot) { Bit16u f_num = slot->channel->f_num; if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb)); + Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; } slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; @@ -387,7 +364,7 @@ void n_generate(opl_chip *chip) { // Slot // -void slot_write20(opl_slot *slot,Bit8u data) { +void slot_write20(opl_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { slot->trem = &slot->chip->tremval; } @@ -434,14 +411,14 @@ void slot_generatephase(opl_slot *slot, Bit16u phase) { } void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); } void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); } -void slot_calgfb(opl_slot *slot) { +void slot_calcfb(opl_slot *slot) { slot->prout[1] = slot->prout[0]; slot->prout[0] = slot->out; if (slot->channel->fb != 0x00) { @@ -461,57 +438,61 @@ void chan_setupalg(opl_channel *channel); void chan_updaterhythm(opl_chip *chip, Bit8u data) { chip->rhy = data & 0x3f; if (chip->rhy & 0x20) { - chip->channel[6].out[0] = &chip->slot[13].out; - chip->channel[6].out[1] = &chip->slot[13].out; - chip->channel[6].out[2] = &chip->zeromod; - chip->channel[6].out[3] = &chip->zeromod; - chip->channel[7].out[0] = &chip->slot[14].out; - chip->channel[7].out[1] = &chip->slot[14].out; - chip->channel[7].out[2] = &chip->slot[15].out; - chip->channel[7].out[3] = &chip->slot[15].out; - chip->channel[8].out[0] = &chip->slot[16].out; - chip->channel[8].out[1] = &chip->slot[16].out; - chip->channel[8].out[2] = &chip->slot[17].out; - chip->channel[8].out[3] = &chip->slot[17].out; + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + channel6->out[0] = &channel6->slots[1]->out; + channel6->out[1] = &channel6->slots[1]->out; + channel6->out[2] = &chip->zeromod; + channel6->out[3] = &chip->zeromod; + channel7->out[0] = &channel7->slots[0]->out; + channel7->out[1] = &channel7->slots[0]->out; + channel7->out[2] = &channel7->slots[1]->out; + channel7->out[3] = &channel7->slots[1]->out; + channel8->out[0] = &channel8->slots[0]->out; + channel8->out[1] = &channel8->slots[0]->out; + channel8->out[2] = &channel8->slots[1]->out; + channel8->out[3] = &channel8->slots[1]->out; for (Bit8u chnum = 6; chnum < 9; chnum++) { chip->channel[chnum].chtype = ch_drum; } + chan_setupalg(channel6); //hh if (chip->rhy & 0x01) { - eg_keyon(&chip->slot[14], egk_drum); + eg_keyon(channel7->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[14], egk_drum); + eg_keyoff(channel7->slots[0], egk_drum); } //tc if (chip->rhy & 0x02) { - eg_keyon(&chip->slot[17], egk_drum); + eg_keyon(channel8->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[17], egk_drum); + eg_keyoff(channel8->slots[1], egk_drum); } //tom if (chip->rhy & 0x04) { - eg_keyon(&chip->slot[16], egk_drum); + eg_keyon(channel8->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[16], egk_drum); + eg_keyoff(channel8->slots[0], egk_drum); } //sd if (chip->rhy & 0x08) { - eg_keyon(&chip->slot[15], egk_drum); + eg_keyon(channel7->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[15], egk_drum); + eg_keyoff(channel7->slots[1], egk_drum); } //bd if (chip->rhy & 0x10) { - eg_keyon(&chip->slot[12], egk_drum); - eg_keyon(&chip->slot[13], egk_drum); + eg_keyon(channel6->slots[0], egk_drum); + eg_keyon(channel6->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[12], egk_drum); - eg_keyoff(&chip->slot[13], egk_drum); + eg_keyoff(channel6->slots[0], egk_drum); + eg_keyoff(channel6->slots[1], egk_drum); } } else { @@ -566,6 +547,16 @@ void chan_writeb0(opl_channel *channel, Bit8u data) { void chan_setupalg(opl_channel *channel) { if (channel->chtype == ch_drum) { + switch (channel->alg & 0x01) { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } return; } if (channel->alg & 0x08) { @@ -672,49 +663,39 @@ void chan_writec0(opl_channel *channel, Bit8u data) { } } -void chan_generaterhythm(opl_chip *chip) { - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - slot_generate(channel6->slots[1]); - Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff; - Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tt - slot_generatezm(channel8->slots[0]); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); - } +void chan_generaterhythm1(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[0]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + slot_generatephase(channel7->slots[0], phase); + //tt + slot_generatezm(channel8->slots[0]); } -void chan_generate(opl_channel *channel) { - if (channel->chtype == ch_drum) { - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - slot_generate(channel->pair->slots[0]); - slot_generate(channel->pair->slots[1]); - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } - else { - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } +void chan_generaterhythm2(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[1]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + slot_generatephase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + slot_generatephase(channel8->slots[1], phase); } void chan_enable(opl_channel *channel) { @@ -782,21 +763,132 @@ Bit16s limshort(Bit32s a) { return (Bit16s)a; } +void chip_generate(opl_chip *chip, Bit16s *buff) { + buff[1] = limshort(chip->mixbuff[1]); + + for (Bit8u ii = 0; ii < 12; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + for (Bit8u ii = 12; ii < 15; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm1(chip); + } + else { + slot_generate(&chip->slot[12]); + slot_generate(&chip->slot[13]); + slot_generate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); + } + else { + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + } + + for (Bit8u ii = 15; ii < 18; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm2(chip); + } + else { + slot_generate(&chip->slot[15]); + slot_generate(&chip->slot[16]); + slot_generate(&chip->slot[17]); + } + + buff[0] = limshort(chip->mixbuff[0]); + + for (Bit8u ii = 18; ii < 33; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); + } + else { + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + } + + for (Bit8u ii = 33; ii < 36; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + n_generate(chip); + + if ((chip->timer & 0x3f) == 0x3f) { + if (!chip->tremdir) { + if (chip->tremtval == 105) { + chip->tremtval--; + chip->tremdir = 1; + } + else { + chip->tremtval++; + } + } + else { + if (chip->tremtval == 0) { + chip->tremtval++; + chip->tremdir = 0; + } + else { + chip->tremtval--; + } + } + chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); + } + + chip->timer++; +} + void NukedOPL3::Reset() { memset(&opl3, 0, sizeof(opl_chip)); for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2]; opl3.slot[slotnum].chip = &opl3; opl3.slot[slotnum].mod = &opl3.zeromod; opl3.slot[slotnum].eg_rout = 0x1ff; opl3.slot[slotnum].eg_out = 0x1ff; opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].eg_gennext = envelope_gen_num_off; opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; } for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[2 * channum]; - opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1]; + opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; + opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; + opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; + opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; if ((channum % 9) < 3) { opl3.channel[channum].pair = &opl3.channel[channum + 3]; } @@ -816,6 +908,8 @@ void NukedOPL3::Reset() { chan_setupalg(&opl3.channel[channum]); } opl3.noise = 0x306600; + opl3.timer = 0; + opl3.FullPan = FullPan; } void NukedOPL3::WriteReg(int reg, int v) { @@ -903,58 +997,11 @@ void NukedOPL3::WriteReg(int reg, int v) { } void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit32s outa, outb; + Bit16s buffer[2]; for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - outa = 0; - outb = 0; - for (Bit8u ii = 0; ii < 36; ii++) { - slot_calgfb(&opl3.slot[ii]); - } - chan_generaterhythm(&opl3); - for (Bit8u ii = 0; ii < 18; ii++) { - chan_generate(&opl3.channel[ii]); - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *opl3.channel[ii].out[jj]; - } - if (FullPan) { - outa += (Bit16s)(accm * opl3.channel[ii].fcha); - outb += (Bit16s)(accm * opl3.channel[ii].fchb); - } - else { - outa += (Bit16s)(accm & opl3.channel[ii].cha); - outb += (Bit16s)(accm & opl3.channel[ii].chb); - } - } - for (Bit8u ii = 0; ii < 36; ii++) { - envelope_calc(&opl3.slot[ii]); - pg_generate(&opl3.slot[ii]); - } - n_generate(&opl3); - opl3.timer++; - if (!(opl3.timer & 0x3f)) { - if (!opl3.tremdir) { - if (opl3.tremtval == 105) { - opl3.tremtval--; - opl3.tremdir = 1; - } - else { - opl3.tremtval++; - } - } - else { - if (opl3.tremtval == 0) { - opl3.tremtval++; - opl3.tremdir = 0; - } - else { - opl3.tremtval--; - } - } - opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1); - } - *sndptr++ += (float)(outa / 10240.0); - *sndptr++ += (float)(outb / 10240.0); + chip_generate(&opl3, buffer); + *sndptr++ += (float)(buffer[0] / 10240.0); + *sndptr++ += (float)(buffer[1] / 10240.0); } } diff --git a/src/oplsynth/nukedopl3.h b/src/oplsynth/nukedopl3.h index ccf37fe14..849646f5f 100644 --- a/src/oplsynth/nukedopl3.h +++ b/src/oplsynth/nukedopl3.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 #include "opl.h" #include "muslib.h" @@ -116,7 +116,7 @@ static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, // ksl table // -static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; +static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; @@ -133,7 +133,7 @@ static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; static const Bit8u eg_incstep[3][4][8] = { { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, + { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } }, { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } }; @@ -149,8 +149,8 @@ static const Bit8s eg_incsh[16] = { // address decoding // -static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - +static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; struct opl_chip; struct opl_slot; @@ -167,7 +167,6 @@ struct opl_slot { Bit16s eg_out; Bit8u eg_inc; Bit8u eg_gen; - Bit8u eg_gennext; Bit8u eg_rate; Bit8u eg_ksl; Bit8u *trem; @@ -217,6 +216,8 @@ struct opl_chip { Bit8u tremdir; Bit32u noise; Bit16s zeromod; + Bit32s mixbuff[2]; + Bit8u FullPan; }; From c743b19e6d784a9cff45c144c643ee072947ee9e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 22 Sep 2015 15:19:44 +0300 Subject: [PATCH 106/335] Make console text to appear in Windows debug output This works in Debug configuration only Color escape sequences are stripped from text before output --- src/win32/i_system.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 372da8685..c21768f1f 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1053,6 +1053,30 @@ static TArray bufferedConsoleStuff; void I_PrintStr(const char *cp) { +#ifdef _DEBUG + // Strip out any color escape sequences before writing to debug output + char * copy = new char[strlen(cp)+1]; + const char * srcp = cp; + char * dstp = copy; + + while (*srcp != 0) + { + if (*srcp!=0x1c && *srcp!=0x1d && *srcp!=0x1e && *srcp!=0x1f) + { + *dstp++=*srcp++; + } + else + { + if (srcp[1]!=0) srcp+=2; + else break; + } + } + *dstp=0; + + OutputDebugStringA(copy); + delete [] copy; +#endif // _DEBUG + if (ConWindowHidden) { bufferedConsoleStuff.Push(cp); From 37dde2e77d91bcaf257e8c4f4c64fa6fe2607e5f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 23 Sep 2015 10:18:57 +0300 Subject: [PATCH 107/335] Make console to Windows debug output controlled by CVAR DebugView can be used to view output without debugger attached --- src/win32/i_system.cpp | 44 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index c21768f1f..ef56c7050 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -137,6 +137,7 @@ extern bool ConWindowHidden; // PUBLIC DATA DEFINITIONS ------------------------------------------------- CVAR (String, queryiwad_key, "shift", CVAR_GLOBALCONFIG|CVAR_ARCHIVE); +CVAR (Bool, con_debugoutput, false, 0); double PerfToSec, PerfToMillisec; UINT TimerPeriod; @@ -1053,29 +1054,30 @@ static TArray bufferedConsoleStuff; void I_PrintStr(const char *cp) { -#ifdef _DEBUG - // Strip out any color escape sequences before writing to debug output - char * copy = new char[strlen(cp)+1]; - const char * srcp = cp; - char * dstp = copy; - - while (*srcp != 0) + if (con_debugoutput) { - if (*srcp!=0x1c && *srcp!=0x1d && *srcp!=0x1e && *srcp!=0x1f) - { - *dstp++=*srcp++; - } - else - { - if (srcp[1]!=0) srcp+=2; - else break; - } - } - *dstp=0; + // Strip out any color escape sequences before writing to debug output + char * copy = new char[strlen(cp)+1]; + const char * srcp = cp; + char * dstp = copy; - OutputDebugStringA(copy); - delete [] copy; -#endif // _DEBUG + while (*srcp != 0) + { + if (*srcp!=0x1c && *srcp!=0x1d && *srcp!=0x1e && *srcp!=0x1f) + { + *dstp++=*srcp++; + } + else + { + if (srcp[1]!=0) srcp+=2; + else break; + } + } + *dstp=0; + + OutputDebugStringA(copy); + delete [] copy; + } if (ConWindowHidden) { From f58b67b11db520a982ce56bd5855440bb6769297 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Sep 2015 09:09:52 +0200 Subject: [PATCH 108/335] . added MBF dog sounds to Dehacked sound table. --- wadsrc/static/dehsupp.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/dehsupp.txt b/wadsrc/static/dehsupp.txt index 51db22e91..ae31f6830 100644 --- a/wadsrc/static/dehsupp.txt +++ b/wadsrc/static/dehsupp.txt @@ -534,7 +534,13 @@ SoundMap "skeleton/active", "skeleton/sight", "skeleton/attack", - "misc/chat" + "misc/chat", + "dog/sight", + "dog/attack", + "dog/active", + "dog/death", + "dog/pain", + }; // Names of different actor types, in original Doom 2 order From 28622cecaf16cc4a95f90e89d4cd1b55757ace42 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 29 Sep 2015 11:40:44 -0500 Subject: [PATCH 109/335] - Added mindist parameter to A_RadiusGive. - Actors must be this far away to receive items. Mindist must be less than distance. - Fixed RGF_OBJECTS not discriminating players and monsters from shootable or vulnerable actors. --- src/thingdef/thingdef_codeptr.cpp | 30 ++++++++++++++++++++++-------- wadsrc/static/actors/actor.txt | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dab68867b..9333a09d4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4880,17 +4880,19 @@ enum RadiusGiveFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { - ACTION_PARAM_START(6); + ACTION_PARAM_START(7); ACTION_PARAM_CLASS(item, 0); ACTION_PARAM_FIXED(distance, 1); ACTION_PARAM_INT(flags, 2); ACTION_PARAM_INT(amount, 3); ACTION_PARAM_CLASS(filter, 4); ACTION_PARAM_NAME(species, 5); + ACTION_PARAM_FIXED(mindist, 6); // We need a valid item, valid targets, and a valid range - if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0) + if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0 || mindist >= distance) { + ACTION_SET_RESULT(false); return; } @@ -4899,9 +4901,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) amount = 1; } FBlockThingsIterator it(FBoundingBox(self->x, self->y, distance)); - double distsquared = double(distance) * double(distance); AActor *thing; + bool given = false; while ((thing = it.Next())) { //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). @@ -4946,7 +4948,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); - bool objectPass = !!((flags & RGF_OBJECTS) && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); + bool objectPass = !!((flags & RGF_OBJECTS) && (thing->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER)) + && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing)); bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (thing->player->mo != thing)); //Self calls priority over the rest of this. @@ -4969,20 +4972,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) { + if (flags & RGF_CUBE) { // check if inside a cube - if (fabs((double)thing->x - self->x) > (double)distance || - fabs((double)thing->y - self->y) > (double)distance || - fabs((double)(thing->z + thing->height / 2) - (self->z + self->height / 2)) > (double)distance) + double dx = fabs((double)(thing->x - self->x)); + double dy = fabs((double)(thing->y - self->y)); + double dz = fabs((double)(thing->z + thing->height / 2) - (self->z + self->height / 2)); + double dist = (double)distance; + double min = (double)mindist; + if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min))) { continue; } } else { // check if inside a sphere + double distsquared = double(distance) * double(distance); + double minsquared = double(mindist) * double(mindist); TVector3 tpos(thing->x, thing->y, thing->z + thing->height / 2); TVector3 spos(self->x, self->y, self->z + self->height / 2); - if ((tpos - spos).LengthSquared() > distsquared) + if ((tpos - spos).LengthSquared() > distsquared || (minsquared && ((tpos - spos).LengthSquared() < minsquared))) { continue; } @@ -5005,9 +5014,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { gift->Destroy(); } + else + { + given = true; + } } } } + ACTION_SET_RESULT(given); } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5877192ce..4832865c7 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -257,7 +257,7 @@ ACTOR Actor native //: Thinker action native A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); action native A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); action native A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0, class filter = "None", name species = "None"); + action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0, class filter = "None", name species = "None", int mindist = 0); action native A_CountdownArg(int argnum, state targstate = ""); action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); action native A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); From af9478f818e940164ec8f00d396d8c4e700ff673 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 3 Oct 2015 17:28:54 -0500 Subject: [PATCH 110/335] - Added Warp properties RadiusOffset and Pitch. - RadiusOffset is a multiplier of the target actor's radius added onto the offsets x and y. - Pitch is added to the warping actor's current pitch, provided WARPF_USEPITCH is supplied. - Fixed WARPF_TOFLOOR not working as intended. --- src/p_acs.cpp | 4 +++- src/p_local.h | 4 +++- src/p_things.cpp | 38 ++++++++++++++++++++---------- src/thingdef/thingdef_codeptr.cpp | 8 ++++--- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 2 ++ 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4e5875836..ca0f62576 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5864,6 +5864,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) const char *statename = argCount > 6 ? FBehavior::StaticLookupString(args[6]) : ""; bool exact = argCount > 7 ? !!args[7] : false; fixed_t heightoffset = argCount > 8 ? args[8] : 0; + fixed_t radiusoffset = argCount > 9 ? args[9] : 0; + fixed_t pitch = argCount > 10 ? args[10] : 0; FState *state = argCount > 6 ? activator->GetClass()->ActorInfo->FindStateByString(statename, exact) : 0; @@ -5881,7 +5883,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (!reference) return false; - if (P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags, heightoffset)) + if (P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags, heightoffset, radiusoffset, pitch)) { if (state && argCount > 6) { diff --git a/src/p_local.h b/src/p_local.h index 95d7541a8..0ac70ce16 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,7 +176,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_CanRaise(AActor *thing); const PClass *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset); +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); enum WARPF { @@ -198,6 +198,8 @@ enum WARPF WARPF_MOVEPTR = 0x1000, WARPF_USEPTR = 0x2000, WARPF_USETID = 0x2000, + WARPF_COPYVELOCITY = 0x4000, + WARPF_COPYPITCH = 0x8000, }; diff --git a/src/p_things.cpp b/src/p_things.cpp index b7e3f058b..edd7777b4 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -680,7 +680,7 @@ void InitSpawnablesFromMapinfo() } -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset) +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch) { if (flags & WARPF_MOVEPTR) { @@ -692,9 +692,10 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t oldx = caller->x; fixed_t oldy = caller->y; fixed_t oldz = caller->z; - zofs += FixedMul(reference->height, heightoffset); - + + const fixed_t rad = FixedMul(radiusoffset, reference->radius); + const angle_t fineangle = angle >> ANGLETOFINESHIFT; if (!(flags & WARPF_ABSOLUTEANGLE)) { @@ -704,13 +705,12 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, { if (!(flags & WARPF_ABSOLUTEOFFSET)) { - angle_t fineangle = angle >> ANGLETOFINESHIFT; fixed_t xofs1 = xofs; // (borrowed from A_SpawnItemEx, assumed workable) // in relative mode negative y values mean 'left' and positive ones mean 'right' // This is the inverse orientation of the absolute mode! - + xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); } @@ -722,15 +722,16 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, // assigning position again with. // extra unlink, link and environment calculation caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, - reference->floorz + zofs); + reference->x + xofs + FixedMul(rad, finecosine[fineangle]), + reference->y + yofs + FixedMul(rad, finesine[fineangle]), + reference->z); + caller->z = caller->floorz + zofs; } else { caller->SetOrigin( - reference->x + xofs, - reference->y + yofs, + reference->x + xofs + FixedMul(rad, finecosine[fineangle]), + reference->y + yofs + FixedMul(rad, finesine[fineangle]), reference->z + zofs); } } @@ -738,11 +739,12 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, { if (flags & WARPF_TOFLOOR) { - caller->SetOrigin(xofs, yofs, caller->floorz + zofs); + caller->SetOrigin(xofs + FixedMul(rad, finecosine[fineangle]), yofs + FixedMul(rad, finesine[fineangle]), zofs); + caller->z = caller->floorz + zofs; } else { - caller->SetOrigin(xofs, yofs, zofs); + caller->SetOrigin(xofs + FixedMul(rad, finecosine[fineangle]), yofs + FixedMul(rad, finesine[fineangle]), zofs); } } @@ -756,6 +758,18 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, { caller->angle = angle; + if (flags & WARPF_COPYPITCH) + caller->SetPitch(reference->pitch, false); + + if (pitch) + caller->SetPitch(caller->pitch + pitch, false); + + if (flags & WARPF_COPYVELOCITY) + { + caller->velx = reference->velx; + caller->vely = reference->vely; + caller->velz = reference->velz; + } if (flags & WARPF_STOP) { caller->velx = 0; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dab68867b..bf4536360 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4673,7 +4673,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { - ACTION_PARAM_START(8); + ACTION_PARAM_START(10); ACTION_PARAM_INT(destination_selector, 0); ACTION_PARAM_FIXED(xofs, 1); @@ -4682,7 +4682,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) ACTION_PARAM_ANGLE(angle, 4); ACTION_PARAM_INT(flags, 5); ACTION_PARAM_STATE(success_state, 6); - ACTION_PARAM_FIXED(heightoffset,7) + ACTION_PARAM_FIXED(heightoffset, 7); + ACTION_PARAM_FIXED(radiusoffset, 8); + ACTION_PARAM_ANGLE(pitch, 9); AActor *reference; @@ -4702,7 +4704,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) return; } - if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags, heightoffset)) + if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags, heightoffset, radiusoffset, pitch)) { if (success_state) { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5877192ce..2f8167eb8 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -249,7 +249,7 @@ ACTOR Actor native //: Thinker action native A_PlayerSkinCheck(state label); action native A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT); - action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0); + action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0, float radiusoffset = 0, float pitch = 0); action native A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); action native A_Weave(int xspeed, int yspeed, float xdist, float ydist); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index b5a8b8cd4..f125a37e7 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -362,6 +362,8 @@ Const Int WARPF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_BOB = 0x800; Const Int WARPF_MOVEPTR = 0x1000; Const Int WARPF_USETID = 0x2000; +Const Int WARPF_COPYVELOCITY = 0x4000; +Const Int WARPF_COPYPITCH = 0x8000; // flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; From e2d874e343da34df6edfad0bb47370cbe10f4bae Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 4 Oct 2015 12:37:49 -0500 Subject: [PATCH 111/335] Applied _mental_'s suggestion --- src/p_things.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index edd7777b4..7e38a3c68 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -694,13 +694,15 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t oldz = caller->z; zofs += FixedMul(reference->height, heightoffset); - const fixed_t rad = FixedMul(radiusoffset, reference->radius); - const angle_t fineangle = angle >> ANGLETOFINESHIFT; if (!(flags & WARPF_ABSOLUTEANGLE)) { angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; } + + const fixed_t rad = FixedMul(radiusoffset, reference->radius); + const angle_t fineangle = angle >> ANGLETOFINESHIFT; + if (!(flags & WARPF_ABSOLUTEPOSITION)) { if (!(flags & WARPF_ABSOLUTEOFFSET)) From 154e02380081fb0badbce7e8172c1e72325b7ab8 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 4 Oct 2015 16:00:40 -0500 Subject: [PATCH 112/335] - Added A_CheckBlock(state block, int flags, int ptr). - Performs a jump if an actor or a line is in the way. - Can be used without a jump state if the desire is only to have a pointer change. - CBF_NOLINES disables jumping if a line is involved. - CBF_SET* flags set the target, master or tracer to whoever is blocking, for the actor calling the function. - CBF_SETONPTR causes the pointer changing flags to apply to the pointed actor instead of itself. --- src/thingdef/thingdef_codeptr.cpp | 61 ++++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 12 ++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dab68867b..7dceb2923 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5846,3 +5846,64 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) self->RipLevelMax = max; } +/*=========================================================================== +A_CheckBlock +(state block, int flags, int ptr) + +Checks if something is blocking the actor('s pointer) 'ptr'. + +The SET pointer flags only affect the caller, not the pointer. +===========================================================================*/ +enum CBF +{ + CBF_NOLINES = 1 << 0, //Don't check actors. + CBF_SETTARGET = 1 << 1, //Sets the caller/pointer's target to the actor blocking it. Actors only. + CBF_SETMASTER = 1 << 2, //^ but with master. + CBF_SETTRACER = 1 << 3, //^ but with tracer. + CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. +}; + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) +{ + ACTION_PARAM_START(3); + ACTION_PARAM_STATE(block, 0); + ACTION_PARAM_INT(flags, 1); + ACTION_PARAM_INT(ptr, 2); + + AActor *mobj = COPY_AAPTR(self, ptr); + + ACTION_SET_RESULT(false); + //Needs at least one state jump to work. + if (!mobj) + { + return; + } + + bool blockTest = P_TestMobjLocation(mobj); + + //Nothing to block it so skip the rest. + if (blockTest) return; + + if (mobj->BlockingMobj) + { + AActor *setter = (flags & CBF_SETONPTR) ? mobj : self; + if (setter) + { + if (flags & CBF_SETTARGET) setter->target = mobj->BlockingMobj; + if (flags & CBF_SETMASTER) setter->master = mobj->BlockingMobj; + if (flags & CBF_SETTRACER) setter->tracer = mobj->BlockingMobj; + } + } + + //[MC] If modders don't want jumping, but just getting the pointer, only abort at + //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. + //It gets the mobj blocking, if any, and doesn't jump at all. + if (!block) + return; + + //[MC] Easiest way to tell if an actor is blocking it, use the pointers. + if (!blockTest && (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL))) + { + ACTION_JUMP(block); + } +} \ No newline at end of file diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5877192ce..8969486be 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -336,7 +336,7 @@ ACTOR Actor native //: Thinker action native A_SetRipperLevel(int level); action native A_SetRipMin(int min); action native A_SetRipMax(int max); - + action native A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false); action native A_CheckRange(float distance, state label, bool two_dimension = false); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index b5a8b8cd4..31014eb1e 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -482,5 +482,17 @@ enum QF_WAVE = 1 << 5, }; +// Flags for A_CheckBlock +// These flags only affect the calling actor('s pointer), not the ones being searched. +enum +{ + CBF_NOLINES = 1 << 0, //Don't check actors. + CBF_SETTARGET = 1 << 1, //Sets the caller/pointer's target to the actor blocking it. Actors only. + CBF_SETMASTER = 1 << 2, //^ but with master. + CBF_SETTRACER = 1 << 3, //^ but with tracer. + CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. +}; + // This is only here to provide one global variable for testing. native int testglobalvar; + From 2f3b69e77022a74731f536bcf63aa73daa48ba2d Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 4 Oct 2015 16:12:35 -0500 Subject: [PATCH 113/335] Optimize a little more... --- src/thingdef/thingdef_codeptr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7dceb2923..7ba70c2ea 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5879,10 +5879,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) return; } - bool blockTest = P_TestMobjLocation(mobj); - //Nothing to block it so skip the rest. - if (blockTest) return; + if (P_TestMobjLocation(mobj)) return; if (mobj->BlockingMobj) { @@ -5902,7 +5900,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) return; //[MC] Easiest way to tell if an actor is blocking it, use the pointers. - if (!blockTest && (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL))) + if (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL)) { ACTION_JUMP(block); } From 005e468fa98578277c0c14923c7aae7193e9685f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 7 Oct 2015 12:11:27 +0300 Subject: [PATCH 114/335] Fixed crash when menu item uses non-existent texture See http://forum.zdoom.org/viewtopic.php?t=49696 --- src/menu/listmenu.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 402c1d5e9..8c63eb35b 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -385,6 +385,11 @@ FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FTextureID patc void FListMenuItemStaticPatch::Drawer(bool selected) { + if (!mTexture.Exists()) + { + return; + } + int x = mXpos; FTexture *tex = TexMan(mTexture); if (mYpos >= 0) From 99dd664029153eaf09ef8b2fa34e5a8b41c8a8f8 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 7 Oct 2015 12:13:11 +0300 Subject: [PATCH 115/335] Print warning to console if unknown texture found in menu definition --- src/menu/menudef.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 73101a76e..04c10760e 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -95,6 +95,18 @@ static void DeinitMenus() ClearSaveGames(); } +static FTextureID GetMenuTexture(const char* const name) +{ + const FTextureID texture = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch); + + if (!texture.Exists()) + { + Printf("Missing menu texture: \"%s\"\n", name); + } + + return texture; +} + //============================================================================= // // @@ -235,7 +247,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) else if (sc.Compare("Selector")) { sc.MustGetString(); - desc->mSelector = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); + desc->mSelector = GetMenuTexture(sc.String); sc.MustGetStringName(","); sc.MustGetNumber(); desc->mSelectOfsX = sc.Number; @@ -278,7 +290,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); - FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); + FTextureID tex = GetMenuTexture(sc.String); FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered); desc->mItems.Push(it); @@ -299,7 +311,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) else if (sc.Compare("PatchItem")) { sc.MustGetString(); - FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); + FTextureID tex = GetMenuTexture(sc.String); sc.MustGetStringName(","); sc.MustGetString(); int hotkey = sc.String[0]; @@ -1045,7 +1057,7 @@ static void BuildEpisodeMenu() FListMenuItem *it; if (AllEpisodes[i].mPicName.IsNotEmpty()) { - FTextureID tex = TexMan.CheckForTexture(AllEpisodes[i].mPicName, FTexture::TEX_MiscPatch); + FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName); it = new FListMenuItemPatch(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut, tex, NAME_Skillmenu, i); } @@ -1442,7 +1454,7 @@ void M_StartupSkillMenu(FGameStartup *gs) if (skill.PicName.Len() != 0 && pItemText == NULL) { - FTextureID tex = TexMan.CheckForTexture(skill.PicName, FTexture::TEX_MiscPatch); + FTextureID tex = GetMenuTexture(skill.PicName); li = new FListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, i); } else From bad99613760763e588f685fb168b2dbfb10a2aa2 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 10 Oct 2015 15:03:14 +0300 Subject: [PATCH 116/335] Fixed crash when clicking on back button in main menu If menu item selection overlaps back button in main menu, clicking on back button with mouse caused a crash See http://forum.zdoom.org/viewtopic.php?t=49711 --- src/menu/listmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 8c63eb35b..0f50d1e00 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -491,7 +491,7 @@ bool FListMenuItemSelectable::MouseEvent(int type, int x, int y) { if (type == DMenu::MOUSE_Release) { - if (DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true)) + if (NULL != DMenu::CurrentMenu && DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true)) { return true; } From 455b70630dac9187469df823c2725de136959f5a Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 10 Oct 2015 10:11:59 -0500 Subject: [PATCH 117/335] - Added A_JumpIfCloser NoZ boolean. Disables Z distance checking if true. --- src/thingdef/thingdef_codeptr.cpp | 12 +++++++----- wadsrc/static/actors/actor.txt | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7ba70c2ea..ae9223319 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -663,15 +663,17 @@ void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) ACTION_PARAM_START(2); ACTION_PARAM_FIXED(dist, 0); ACTION_PARAM_STATE(jump, 1); + ACTION_PARAM_BOOL(noz, 2); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // No target - no jump - if (target != NULL && P_AproxDistance(self->x-target->x, self->y-target->y) < dist && - ( (self->z > target->z && self->z - (target->z + target->height) < dist) || - (self->z <=target->z && target->z - (self->z + self->height) < dist) - ) - ) + if (!target) + return; + if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + (noz || + ((self->z > target->z && self->z - (target->z + target->height) < dist) || + (self->z <= target->z && target->z - (self->z + self->height) < dist)))) { ACTION_JUMP(jump); } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8969486be..18911be33 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -212,9 +212,9 @@ ACTOR Actor native //: Thinker action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET); action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); - action native A_JumpIfCloser(float distance, state label); - action native A_JumpIfTracerCloser(float distance, state label); - action native A_JumpIfMasterCloser(float distance, state label); + action native A_JumpIfCloser(float distance, state label, bool noz = false); + action native A_JumpIfTracerCloser(float distance, state label, bool noz = false); + action native A_JumpIfMasterCloser(float distance, state label, bool noz = false); action native A_JumpIfTargetOutsideMeleeRange(state label); action native A_JumpIfTargetInsideMeleeRange(state label); action native A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); From 21dc45bdecd811983c4ee94549b698fc290fc20b Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 10 Oct 2015 15:30:18 -0500 Subject: [PATCH 118/335] This did not save out properly... --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ae9223319..9c86e43e6 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -660,7 +660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange) //========================================================================== void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) { - ACTION_PARAM_START(2); + ACTION_PARAM_START(3); ACTION_PARAM_FIXED(dist, 0); ACTION_PARAM_STATE(jump, 1); ACTION_PARAM_BOOL(noz, 2); From fe61b8064adf5f42575d4c57056466d49878b9d1 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 11 Oct 2015 09:28:38 +0300 Subject: [PATCH 119/335] Fixed MSVC warning in a_randomspawner.cpp ...\src\g_shared\a_randomspawner.cpp(32): warning C4800: 'DWORD' : forcing value to bool 'true' or 'false' (performance warning) See http://forum.zdoom.org/viewtopic.php?t=49737 --- src/g_shared/a_randomspawner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 160766fa7..7d000f3d4 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -29,7 +29,7 @@ static bool IsMonster(const FDropItem *di) return false; } - return GetDefaultByType(pclass)->flags3 & MF3_ISMONSTER; + return 0 != (GetDefaultByType(pclass)->flags3 & MF3_ISMONSTER); } class ARandomSpawner : public AActor From 380b5c1eb79e747a3f404e8ec746aa9a0d819f34 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 11 Oct 2015 09:10:33 -0500 Subject: [PATCH 120/335] - Added ICESHATTER flag. - Any inflictor with this flag can break ice corpses --- src/actor.h | 1 + src/p_interaction.cpp | 2 +- src/thingdef/thingdef_data.cpp | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/actor.h b/src/actor.h index 52c88e901..468dcc0c6 100644 --- a/src/actor.h +++ b/src/actor.h @@ -373,6 +373,7 @@ enum ActorFlag7 MF7_NODECAL = 0x00040000, // [ZK] Forces puff to have no impact decal MF7_FORCEDECAL = 0x00080000, // [ZK] Forces puff's decal to override the weapon's. MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. + MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. }; // --- mobj.renderflags --- diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 603535b7c..25724172c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -970,7 +970,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } if (target->health <= 0) { - if (inflictor && mod == NAME_Ice) + if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER)) { return -1; } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 817afd0fa..f9a282c76 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -253,12 +253,10 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, HITTARGET, AActor, flags7), DEFINE_FLAG(MF7, HITMASTER, AActor, flags7), DEFINE_FLAG(MF7, HITTRACER, AActor, flags7), - - // [ZK] Decal flags - DEFINE_FLAG(MF7, NODECAL, AActor, flags7), + DEFINE_FLAG(MF7, NODECAL, AActor, flags7), // [ZK] Decal flags DEFINE_FLAG(MF7, FORCEDECAL, AActor, flags7), - DEFINE_FLAG(MF7, LAXTELEFRAGDMG, AActor, flags7), + DEFINE_FLAG(MF7, ICESHATTER, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From 6678c3550ea3ce88e4541afbce3fca1f1e6d33a4 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 13 Oct 2015 00:30:06 +0200 Subject: [PATCH 121/335] - Improve the TFlags code and fix the new errors. The previous version didn't detect some real mistakes in code which used operator& with the wrong flagset (for now 'converted' to the correcly equivalent counterpart, waiting for the proper fix). --- src/d_dehacked.cpp | 20 ++++++++++---------- src/fragglescript/t_func.cpp | 2 +- src/g_hexen/a_clericstaff.cpp | 2 +- src/p_acs.cpp | 4 ++-- src/p_local.h | 2 +- src/p_map.cpp | 2 +- src/p_mobj.cpp | 14 +++++++------- src/p_trace.cpp | 5 +++-- src/p_trace.h | 3 ++- src/tflags.h | 4 ++++ src/thingdef/thingdef_codeptr.cpp | 4 ++-- 11 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index a994f7603..bc0acc666 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -784,7 +784,7 @@ static int PatchThing (int thingy) bool hadStyle = false; FStateDefinitions statedef; bool patchedStates = false; - int oldflags; + ActorFlags oldflags; const PClass *type; SWORD *ednum, dummyed; @@ -1139,28 +1139,28 @@ static int PatchThing (int thingy) } if (vchanged[1]) { - info->flags2 = ActorFlags2::FromInt (value[1]); - if (info->flags2 & 0x00000004) // old BOUNCE1 + if (value[1] & 0x00000004) // old BOUNCE1 { - info->flags2 &= ActorFlags2::FromInt (~4); + value[1] &= ~0x00000004; info->BounceFlags = BOUNCE_DoomCompat; } // Damage types that once were flags but now are not - if (info->flags2 & 0x20000000) + if (value[1] & 0x20000000) { info->DamageType = NAME_Ice; - info->flags2 &= ActorFlags2::FromInt (~0x20000000); + value[1] &= ~0x20000000; } - if (info->flags2 & 0x10000) + if (value[1] & 0x10000000) { info->DamageType = NAME_Fire; - info->flags2 &= ActorFlags2::FromInt (~0x10000); + value[1] &= ~0x10000000; } - if (info->flags2 & 1) + if (value[1] & 0x00000001) { info->gravity = FRACUNIT/4; - info->flags2 &= ActorFlags2::FromInt (~1); + value[1] &= ~0x00000001; } + info->flags2 = ActorFlags2::FromInt (value[1]); } if (vchanged[2]) { diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 6fcd50341..7e05be8da 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -1236,7 +1236,7 @@ void FParser::SF_ObjFlag(void) t_return.type = svt_int; if (mo && flagnum<26) { - t_return.value.i = !!(mo->flags & (1 << flagnum)); + t_return.value.i = !!(mo->flags & ActorFlags::FromInt(1 << flagnum)); } else t_return.value.i = 0; } diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 45551f55f..b397fc12b 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -75,7 +75,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) { pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) - && (!(linetarget->flags2&(MF2_DORMANT+MF2_INVULNERABLE)))) + && (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE)))) { newLife = player->health+(damage>>3); newLife = newLife > max ? max : newLife; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4e5875836..e61f962ca 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5761,9 +5761,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return 0; } - DWORD actorMask = MF_SHOOTABLE; + ActorFlags actorMask = MF_SHOOTABLE; if (argCount >= 6) { - actorMask = args[5]; + actorMask = ActorFlags::FromInt(args[5]); } DWORD wallMask = ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN; diff --git a/src/p_local.h b/src/p_local.h index 95d7541a8..a3df41f21 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -500,7 +500,7 @@ enum // P_LineAttack flags AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, DWORD actorMask, DWORD wallMask); +AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version diff --git a/src/p_map.cpp b/src/p_map.cpp index c9b2f14cf..e8e5d6c84 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3912,7 +3912,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, //========================================================================== AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, - DWORD actorMask, DWORD wallMask) + ActorFlags actorMask, DWORD wallMask) { fixed_t vx, vy, vz, shootz; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 901372eef..d5c5eb5d9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6467,25 +6467,25 @@ void PrintMiscActorInfo(AActor *query) Printf("%s @ %p has the following flags:\n flags: %x", query->GetTag(), query, query->flags.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags & 1<flags & ActorFlags::FromInt(1<flags2.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags2 & 1<flags2 & ActorFlags2::FromInt(1<flags3.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags3 & 1<flags3 & ActorFlags3::FromInt(1<flags4.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags4 & 1<flags4 & ActorFlags4::FromInt(1<flags5.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags5 & 1<flags5 & ActorFlags5::FromInt(1<flags6.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags6 & 1<flags6 & ActorFlags6::FromInt(1<flags7.GetValue()); for (flagi = 0; flagi <= 31; flagi++) - if (query->flags7 & 1<flags7 & ActorFlags7::FromInt(1<BounceFlags.GetValue(), FIXED2FLOAT(query->bouncefactor), FIXED2FLOAT(query->wallbouncefactor)); diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 07d23294b..4b4683be5 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -42,7 +42,8 @@ struct FTraceInfo { fixed_t StartX, StartY, StartZ; fixed_t Vx, Vy, Vz; - DWORD ActorMask, WallMask; + ActorFlags ActorMask; + DWORD WallMask; AActor *IgnoreThis; FTraceResults *Results; sector_t *CurSector; @@ -70,7 +71,7 @@ static bool EditTraceResult (DWORD flags, FTraceResults &res); 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, - DWORD actorMask, DWORD wallMask, AActor *ignore, + ActorFlags actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, DWORD flags, ETraceStatus (*callback)(FTraceResults &res, void *), void *callbackdata) { diff --git a/src/p_trace.h b/src/p_trace.h index 403b1f9cf..ecf37e01e 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -35,6 +35,7 @@ #define __P_TRACE_H__ #include +#include "actor.h" #include "textures/textures.h" struct sector_t; @@ -96,7 +97,7 @@ enum ETraceStatus 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, - DWORD ActorMask, DWORD WallMask, AActor *ignore, + ActorFlags ActorMask, DWORD WallMask, AActor *ignore, FTraceResults &res, DWORD traceFlags=0, ETraceStatus (*callback)(FTraceResults &res, void *)=NULL, void *callbackdata=NULL); diff --git a/src/tflags.h b/src/tflags.h index 6c549a860..48866c828 100644 --- a/src/tflags.h +++ b/src/tflags.h @@ -94,6 +94,10 @@ public: static Self FromInt (TT value) { return Self (static_cast (value)); } private: + template Self operator| (X value) const { return Self::FromInt (Value | value); } + template Self operator& (X value) const { return Self::FromInt (Value & value); } + template Self operator^ (X value) const { return Self::FromInt (Value ^ value); } + TT Value; }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f56fa6633..bf05ed298 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1014,7 +1014,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) targ=owner; missile->target=owner; // automatic handling of seeker missiles - if (self->flags & missile->flags2 & MF2_SEEKERMISSILE) + if ((self->flags & MF_STEALTH) && (missile->flags2 & MF2_SEEKERMISSILE)) { missile->tracer=self->tracer; } @@ -3414,7 +3414,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) lof_data.Flags = flags; lof_data.BadActor = false; - Trace(x1, y1, z1, sec, vx, vy, vz, range, 0xFFFFFFFF, ML_BLOCKEVERYTHING, self, trace, 0, + Trace(x1, y1, z1, sec, vx, vy, vz, range, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, self, trace, 0, CheckLOFTraceFunc, &lof_data); if (trace.HitType == TRACE_HitActor || From 4cd793ca2f57231d578b9f0631fc606023fd57e9 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 13 Oct 2015 09:13:37 +0200 Subject: [PATCH 122/335] - Fixed broken projectile firing projectiles code. This went unnoticed since ZDoom 2.0.90, which introduced the bug. Discovered with the recent TFlags improvements. --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index bf05ed298..9b451d40b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1014,7 +1014,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) targ=owner; missile->target=owner; // automatic handling of seeker missiles - if ((self->flags & MF_STEALTH) && (missile->flags2 & MF2_SEEKERMISSILE)) + if (self->flags2 & missile->flags2 & MF2_SEEKERMISSILE) { missile->tracer=self->tracer; } From 916b5f796de3991f8f0b52027bacfd085f7d7149 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 14 Oct 2015 13:17:21 +0300 Subject: [PATCH 123/335] Updated list of video resolutions for Cocoa backend Added resolutions for iMac Retina 4K 21.5" Added comments about a few resolutions specific to Macs --- src/posix/cocoa/i_video.mm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 410a106f5..3fc2b2aed 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -342,17 +342,19 @@ VideoModes[] = { 1680, 1050 }, // 16:10 { 1920, 1080 }, { 1920, 1200 }, + { 2048, 1152 }, // 16:9, iMac Retina 4K 21.5", HiDPI off { 2048, 1536 }, - { 2304, 1440 }, + { 2304, 1440 }, // 16:10, MacBook Retina 12" { 2560, 1440 }, { 2560, 1600 }, { 2560, 2048 }, - { 2880, 1800 }, + { 2880, 1800 }, // 16:10, MacBook Pro Retina 15" { 3200, 1800 }, { 3840, 2160 }, { 3840, 2400 }, { 4096, 2160 }, - { 5120, 2880 } + { 4096, 2304 }, // 16:9, iMac Retina 4K 21.5" + { 5120, 2880 } // 16:9, iMac Retina 5K 27" }; From c93bc2561e4bfcc2140c312b36e649d27560d805 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 15 Oct 2015 10:33:28 +0300 Subject: [PATCH 124/335] Added Toggle Run action to Customize Controls menu --- wadsrc/static/menudef.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index b1ca44de7..1b9a2c606 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -456,6 +456,7 @@ OptionMenu "CustomizeControls" Control "Look down", "+lookdown" Control "Center view", "centerview" Control "Run", "+speed" + Control "Toggle Run", "toggle cl_run" Control "Strafe", "+strafe" Control "Show Scoreboard", "+showscores" Control "Toggle Scoreboard", "togglescoreboard" From 869e16849537a0a1af05a677489975a95abe8183 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 18 Oct 2015 15:52:45 +0300 Subject: [PATCH 125/335] 'no monsters' option is no longer ignored in ACS Spawn functions See http://forum.zdoom.org/viewtopic.php?t=46459 --- src/p_acs.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e61f962ca..bca6ac62b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3365,6 +3365,14 @@ int DLevelScript::DoSpawn (int type, fixed_t x, fixed_t y, fixed_t z, int tid, i if (info != NULL) { + info = info->GetReplacement (); + + if ((GetDefaultByType (info)->flags3 & MF3_ISMONSTER) && + ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) + { + return 0; + } + actor = Spawn (info, x, y, z, ALLOW_REPLACE); if (actor != NULL) { From 27135d5c5da22a2027f617ba363b056af38abea4 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 18 Oct 2015 16:28:42 +0300 Subject: [PATCH 126/335] Fixed crash on loading map with corrupt linedefs and/or sectors See http://forum.zdoom.org/viewtopic.php?t=49276 --- src/p_setup.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 14b19348e..311bf8fc4 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2353,7 +2353,16 @@ static void P_LoopSidedefs (bool firstloop) // instead of as part of another loop if (line->frontsector == line->backsector) { - right = DWORD(line->sidedef[!sidetemp[i].b.lineside] - sides); + const side_t* const rightside = line->sidedef[!sidetemp[i].b.lineside]; + + if (NULL == rightside) + { + // There is no right side! + if (firstloop) Printf ("Line %d's right edge is unconnected\n", linemap[unsigned(line-lines)]); + continue; + } + + right = DWORD(rightside - sides); } else { From 2612fad326be24ab1493087840f8302221ed7454 Mon Sep 17 00:00:00 2001 From: John Palomo Jr Date: Sat, 21 Nov 2015 06:05:16 -0500 Subject: [PATCH 127/335] Backport RETURNTID and FORCETID flags for PickActor from GLOOME. Renamed prefix to avoid confusion with Pain Attack flags. Fixed broken enum. --- src/p_acs.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 83146b743..4f8a0c6c3 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -133,6 +133,16 @@ enum ARMORINFO_ACTUALSAVEAMOUNT, }; +// PickActor +// [JP] I've renamed these flags to something else to avoid confusion with the other PAF_ flags +enum +{ +// PAF_FORCETID, +// PAF_RETURNTID + PICKAF_FORCETID = 1, + PICKAF_RETURNTID = 2, +}; + struct CallReturn { CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway) @@ -5779,11 +5789,10 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) wallMask = args[6]; } - bool forceTID = 0; + int flags = 0; if (argCount >= 8) { - if (args[7] != 0) - forceTID = 1; + flags = args[7]; } AActor* pickedActor = P_LinePickActor(actor, args[1] << 16, args[3], args[2] << 16, actorMask, wallMask); @@ -5791,15 +5800,19 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return 0; } - if (!(forceTID) && (args[4] == 0) && (pickedActor->tid == 0)) + if (!(flags & PICKAF_FORCETID) && (args[4] == 0) && (pickedActor->tid == 0)) return 0; - if ((pickedActor->tid == 0) || (forceTID)) + if ((pickedActor->tid == 0) || (flags & PICKAF_FORCETID)) { pickedActor->RemoveFromHash(); pickedActor->tid = args[4]; pickedActor->AddToHash(); } + if (flags & PICKAF_RETURNTID) + { + return pickedActor->tid; + } return 1; } break; From 20bf4d6c8ebe8cf4bc3fedf24e9a609843a8b5b3 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 21 Nov 2015 17:43:49 +0200 Subject: [PATCH 128/335] Fixed crash on finishgame CCMD in non-game modes http://forum.zdoom.org/viewtopic.php?t=49943 --- src/g_level.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/g_level.cpp b/src/g_level.cpp index 15d88ccaf..aba58e810 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -698,6 +698,13 @@ void G_DoCompleted (void) gameaction = ga_nothing; + if ( gamestate == GS_DEMOSCREEN + || gamestate == GS_FULLCONSOLE + || gamestate == GS_STARTUP) + { + return; + } + if (gamestate == GS_TITLELEVEL) { level.MapName = nextlevel; From 7b017f472aef982a0e4049809f4aefdeb57e6687 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 11:49:34 +0100 Subject: [PATCH 129/335] - fixed: Due to the default skybox being moved to the global level data, there was insufficient information to distinguish between using the default skybox or the regular sky. Fixed by adding two new sector flags which get set by a 0-tid SkyPicker. --- src/g_shared/a_skies.cpp | 2 ++ src/p_sectors.cpp | 15 +++++++++++++++ src/r_bsp.cpp | 5 +++-- src/r_defs.h | 4 ++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index d62a2a07b..54661ea14 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -186,10 +186,12 @@ void ASkyPicker::PostBeginPlay () if (0 == (args[1] & 2)) { Sector->CeilingSkyBox = box; + if (box == NULL) Sector->MoreFlags |= SECF_NOCEILINGSKYBOX; // sector should ignore the level's default skybox } if (0 == (args[1] & 1)) { Sector->FloorSkyBox = box; + if (box == NULL) Sector->MoreFlags |= SECF_NOFLOORSKYBOX; // sector should ignore the level's default skybox } } Destroy (); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 904c76c1b..bc7abd380 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -29,6 +29,7 @@ #include "po_man.h" #include "farchive.h" #include "r_utility.h" +#include "a_sharedglobal.h" #include "r_data/colormaps.h" @@ -800,6 +801,20 @@ int sector_t::GetCeilingLight () const } } + +ASkyViewpoint *sector_t::GetSkyBox(int which) +{ + if (which == floor) + { + return FloorSkyBox != NULL ? FloorSkyBox : (MoreFlags & SECF_NOFLOORSKYBOX)? (ASkyViewpoint*)NULL : level.DefaultSkybox; + } + else + { + return CeilingSkyBox != NULL ? CeilingSkyBox : (MoreFlags & SECF_NOCEILINGSKYBOX)? (ASkyViewpoint*)NULL : level.DefaultSkybox; + } +} + + sector_t *sector_t::GetHeightSec() const { if (heightsec == NULL) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index bf0ac910f..545d009d9 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1087,7 +1087,8 @@ void R_Subsector (subsector_t *sub) basecolormap = frontsector->ColorMap; } - skybox = frontsector->CeilingSkyBox != NULL ? frontsector->CeilingSkyBox : level.DefaultSkybox; + skybox = frontsector->GetSkyBox(sector_t::ceiling); + ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 || frontsector->GetTexture(sector_t::ceiling) == skyflatnum || (skybox != NULL && skybox->bAlways) || @@ -1127,7 +1128,7 @@ void R_Subsector (subsector_t *sub) // killough 3/7/98: Add (x,y) offsets to flats, add deep water check // killough 3/16/98: add floorlightlevel // killough 10/98: add support for skies transferred from sidedefs - skybox = frontsector->FloorSkyBox != NULL ? frontsector->FloorSkyBox : level.DefaultSkybox; + skybox = frontsector->GetSkyBox(sector_t::floor); floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98 frontsector->GetTexture(sector_t::floor) == skyflatnum || (skybox != NULL && skybox->bAlways) || diff --git a/src/r_defs.h b/src/r_defs.h index afda92089..a93622b41 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -340,6 +340,8 @@ enum SECF_UNDERWATERMASK = 32+64, SECF_DRAWN = 128, // sector has been drawn at least once SECF_HIDDEN = 256, // Do not draw on textured automap + SECF_NOFLOORSKYBOX = 512, // force use of regular sky + SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky }; enum @@ -451,6 +453,8 @@ struct sector_t DInterpolation *SetInterpolation(int position, bool attach); void StopInterpolation(int position); + ASkyViewpoint *GetSkyBox(int which); + enum { floor, From 4a18a28448a6c99d9b63fa45dd54787330becac3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 12:20:35 +0100 Subject: [PATCH 130/335] - fixed: am_showtriggerlines will now ignore any non-activatable linedef types. --- src/am_map.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 045d48589..46a2d5a84 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2328,7 +2328,9 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, AMColors.LockedColor); // locked special } } - else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) && lines[i].special != 0 + else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) + && LineSpecialsInfo[lines[i].special] != NULL + && LineSpecialsInfo[lines[i].special]->max_args >= 0 && lines[i].special != Door_Open && lines[i].special != Door_Close && lines[i].special != Door_CloseWaitOpen From 43dff3021b4e6491ae48bd3e5054954be291b646 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:00:56 +0100 Subject: [PATCH 131/335] - fixed: The OpenAL backend ignored PlaySound's 'volume' parameter. --- src/sound/oalsound.cpp | 3898 ++++++++++++++++++++-------------------- 1 file changed, 1949 insertions(+), 1949 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 662e426e6..5c980a793 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1,66 +1,66 @@ -/* -** oalsound.cpp -** System interface for sound; uses OpenAL -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#define USE_WINDOWS_DWORD -#endif - -#include "except.h" -#include "doomstat.h" -#include "templates.h" -#include "oalsound.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "i_system.h" -#include "v_text.h" -#include "gi.h" -#include "actor.h" -#include "r_state.h" -#include "w_wad.h" -#include "i_music.h" -#include "i_musicinterns.h" -#include "tempfiles.h" - - -CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - - -bool IsOpenALPresent() -{ +/* +** oalsound.cpp +** System interface for sound; uses OpenAL +** +**--------------------------------------------------------------------------- +** Copyright 2008-2010 Chris Robinson +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif + +#include "except.h" +#include "doomstat.h" +#include "templates.h" +#include "oalsound.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "i_system.h" +#include "v_text.h" +#include "gi.h" +#include "actor.h" +#include "r_state.h" +#include "w_wad.h" +#include "i_music.h" +#include "i_musicinterns.h" +#include "tempfiles.h" + + +CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + + +bool IsOpenALPresent() +{ #ifdef NO_OPENAL return false; #elif !defined _WIN32 @@ -87,1889 +87,1889 @@ bool IsOpenALPresent() } return cached_result; #endif -} - -void I_BuildALDeviceList(FOptionValues *opt) -{ - opt->mValues.Resize(1); - opt->mValues[0].TextValue = "Default"; - opt->mValues[0].Text = "Default"; - -#ifndef NO_OPENAL - if (IsOpenALPresent()) - { - const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - if (!names) - Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - else while (*names) - { - unsigned int i = opt->mValues.Reserve(1); - opt->mValues[i].TextValue = names; - opt->mValues[i].Text = names; - - names += strlen(names) + 1; - } - } -#endif -} - -#ifndef NO_OPENAL - - -EXTERN_CVAR (Int, snd_channels) -EXTERN_CVAR (Int, snd_samplerate) -EXTERN_CVAR (Bool, snd_waterreverb) -EXTERN_CVAR (Bool, snd_pitched) - - -#define MAKE_PTRID(x) ((void*)(uintptr_t)(x)) -#define GET_PTRID(x) ((uint32)(uintptr_t)(x)) - - -static ALenum checkALError(const char *fn, unsigned int ln) -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); - } - return err; -} -#define getALError() checkALError(__FILE__, __LINE__) - -static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) -{ - ALCenum err = alcGetError(device); - if(err != ALC_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); - } - return err; -} -#define getALCError(d) checkALCError((d), __FILE__, __LINE__) - - -// Fallback methods for when AL_SOFT_deferred_updates isn't available. In most -// cases these don't actually do anything, except on some Creative drivers -// where they act as appropriate fallbacks. -static ALvoid AL_APIENTRY _wrap_DeferUpdatesSOFT(void) -{ - alcSuspendContext(alcGetCurrentContext()); -} - -static ALvoid AL_APIENTRY _wrap_ProcessUpdatesSOFT(void) -{ - alcProcessContext(alcGetCurrentContext()); -} - - -class OpenALSoundStream : public SoundStream -{ - OpenALSoundRenderer *Renderer; - - SoundStreamCallback Callback; - void *UserData; - - TArray Data; - - ALsizei SampleRate; - ALenum Format; - ALsizei FrameSize; - - static const int BufferCount = 4; - ALuint Buffers[BufferCount]; - ALuint Source; - - bool Playing; - bool Looping; - ALfloat Volume; - - - FileReader *Reader; - SoundDecoder *Decoder; - static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) - { - OpenALSoundStream *self = static_cast(_sstream); - if(length < 0) return false; - - size_t got = self->Decoder->read((char*)ptr, length); - if(got < (unsigned int)length) - { - if(!self->Looping || !self->Decoder->seek(0)) - return false; - got += self->Decoder->read((char*)ptr+got, length-got); - } - - return (got == (unsigned int)length); - } - - - bool SetupSource() - { - /* Get a source, killing the farthest, lowest-priority sound if needed */ - if(Renderer->FreeSfx.Size() == 0) - { - FSoundChan *lowest = Renderer->FindLowestChannel(); - if(lowest) Renderer->StopChannel(lowest); - - if(Renderer->FreeSfx.Size() == 0) - return false; - } - Renderer->FreeSfx.Pop(Source); - - /* Set the default properties for localized playback */ - alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); - alSourcef(Source, AL_MAX_GAIN, 1.f); - alSourcef(Source, AL_GAIN, 1.f); - alSourcef(Source, AL_PITCH, 1.f); - alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_SEC_OFFSET, 0.f); - alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(Source, AL_LOOPING, AL_FALSE); - if(Renderer->EnvSlot) - { - alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - - alGenBuffers(BufferCount, Buffers); - return (getALError() == AL_NO_ERROR); - } - -public: - OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f), Reader(NULL), Decoder(NULL) - { - Renderer->Streams.Push(this); - memset(Buffers, 0, sizeof(Buffers)); - } - - virtual ~OpenALSoundStream() - { - if(Source) - { - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); - - Renderer->FreeSfx.Push(Source); - Source = 0; - } - - if(Buffers[0]) - { - alDeleteBuffers(BufferCount, &Buffers[0]); - memset(Buffers, 0, sizeof(Buffers)); - } - getALError(); - - Renderer->Streams.Delete(Renderer->Streams.Find(this)); - Renderer = NULL; - - delete Decoder; - delete Reader; - } - - - virtual bool Play(bool loop, float vol) - { - SetVolume(vol); - - if(Playing) - return true; - - /* Clear the buffer queue, then fill and queue each buffer */ - alSourcei(Source, AL_BUFFER, 0); - for(int i = 0;i < BufferCount;i++) - { - if(!Callback(this, &Data[0], Data.Size(), UserData)) - { - if(i == 0) - return false; - break; - } - - alBufferData(Buffers[i], Format, &Data[0], Data.Size(), SampleRate); - alSourceQueueBuffers(Source, 1, &Buffers[i]); - } - if(getALError() != AL_NO_ERROR) - return false; - - alSourcePlay(Source); - Playing = (getALError()==AL_NO_ERROR); - - return Playing; - } - - virtual void Stop() - { - if(!Playing) - return; - - alSourceStop(Source); - alSourcei(Source, AL_BUFFER, 0); - getALError(); - - Playing = false; - } - - virtual void SetVolume(float vol) - { - Volume = vol; - UpdateVolume(); - } - - void UpdateVolume() - { - alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); - getALError(); - } - - virtual bool SetPaused(bool pause) - { - if(pause) - alSourcePause(Source); - else - alSourcePlay(Source); - return (getALError()==AL_NO_ERROR); - } - - virtual bool SetPosition(unsigned int ms_pos) - { - if(!Decoder->seek(ms_pos)) - return false; - - if(!Playing) - return true; - // Stop the source so that all buffers become processed, then call - // IsEnded() to refill and restart the source queue with the new - // position. - alSourceStop(Source); - getALError(); - return !IsEnded(); - } - - virtual unsigned int GetPosition() - { - ALint offset, queued, state; - alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_SOURCE_STATE, &state); - if(getALError() != AL_NO_ERROR) - return 0; - - size_t pos = Decoder->getSampleOffset(); - if(state != AL_STOPPED) - { - size_t rem = queued*(Data.Size()/FrameSize) - offset; - if(pos > rem) pos -= rem; - else pos = 0; - } - return (unsigned int)(pos * 1000.0 / SampleRate); - } - - virtual bool IsEnded() - { - if(!Playing) - return true; - - ALint state, processed; - alGetSourcei(Source, AL_SOURCE_STATE, &state); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - - Playing = (getALError()==AL_NO_ERROR); - if(!Playing) - return true; - - // For each processed buffer in the queue... - while(processed > 0) - { - ALuint bufid; - - // Unqueue the oldest buffer, fill it with more data, and queue it - // on the end - alSourceUnqueueBuffers(Source, 1, &bufid); - processed--; - - if(Callback(this, &Data[0], Data.Size(), UserData)) - { - alBufferData(bufid, Format, &Data[0], Data.Size(), SampleRate); - alSourceQueueBuffers(Source, 1, &bufid); - } - } - - // If the source is not playing or paused, and there are buffers queued, - // then there was an underrun. Restart the source. - Playing = (getALError()==AL_NO_ERROR); - if(Playing && state != AL_PLAYING && state != AL_PAUSED) - { - ALint queued = 0; - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - - Playing = (getALError() == AL_NO_ERROR) && (queued > 0); - if(Playing) - { - alSourcePlay(Source); - Playing = (getALError()==AL_NO_ERROR); - } - } - - return !Playing; - } - - FString GetStats() - { - FString stats; - size_t pos, len; - ALfloat volume; - ALint offset; - ALint processed; - ALint queued; - ALint state; - ALenum err; - - alGetSourcef(Source, AL_GAIN, &volume); - alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_SOURCE_STATE, &state); - if((err=alGetError()) != AL_NO_ERROR) - { - stats = "Error getting stats: "; - stats += alGetString(err); - return stats; - } - - stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : - (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; - - pos = Decoder->getSampleOffset(); - len = Decoder->getSampleLength(); - if(state == AL_STOPPED) - offset = BufferCount * (Data.Size()/FrameSize); - else - { - size_t rem = queued*(Data.Size()/FrameSize) - offset; - if(pos > rem) pos -= rem; - else if(len > 0) pos += len - rem; - else pos = 0; - } - pos = (size_t)(pos * 1000.0 / SampleRate); - len = (size_t)(len * 1000.0 / SampleRate); - stats.AppendFormat(",%3u%% buffered", 100 - 100*offset/(BufferCount*(Data.Size()/FrameSize))); - stats.AppendFormat(", %zu.%03zu", pos/1000, pos%1000); - if(len > 0) - stats.AppendFormat(" / %zu.%03zu", len/1000, len%1000); - if(state == AL_PAUSED) - stats += ", paused"; - if(state == AL_PLAYING) - stats += ", playing"; - stats.AppendFormat(", %uHz", SampleRate); - if(!Playing) - stats += " XX"; - return stats; - } - - bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) - { - if(!SetupSource()) - return false; - - Callback = callback; - UserData = userdata; - SampleRate = samplerate; - - Format = AL_NONE; - if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ - { - if((flags&Mono)) Format = AL_FORMAT_MONO8; - else Format = AL_FORMAT_STEREO8; - } - else if((flags&Float)) - { - if(alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; - else Format = AL_FORMAT_STEREO_FLOAT32; - } - } - else if((flags&Bits32)) - { - } - else - { - if((flags&Mono)) Format = AL_FORMAT_MONO16; - else Format = AL_FORMAT_STEREO16; - } - - if(Format == AL_NONE) - { - Printf("Unsupported format: 0x%x\n", flags); - return false; - } - - FrameSize = 1; - if((flags&Bits8)) - FrameSize *= 1; - else if((flags&(Bits32|Float))) - FrameSize *= 4; - else - FrameSize *= 2; - - if((flags&Mono)) - FrameSize *= 1; - else - FrameSize *= 2; - - buffbytes += FrameSize-1; - buffbytes -= buffbytes%FrameSize; - Data.Resize(buffbytes); - - return true; - } - - bool Init(FileReader *reader, bool loop) - { - if(!SetupSource()) - { - delete reader; - return false; - } - - if(Decoder) delete Decoder; - if(Reader) delete Reader; - Reader = reader; - Decoder = Renderer->CreateDecoder(Reader); - if(!Decoder) return false; - - Callback = DecoderCallback; - UserData = NULL; - Format = AL_NONE; - FrameSize = 1; - - ChannelConfig chans; - SampleType type; - int srate; - - Decoder->getInfo(&srate, &chans, &type); - if(chans == ChannelConfig_Mono) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; - if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; - FrameSize *= 1; - } - if(chans == ChannelConfig_Stereo) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; - if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; - FrameSize *= 2; - } - if(type == SampleType_UInt8) FrameSize *= 1; - if(type == SampleType_Int16) FrameSize *= 2; - - if(Format == AL_NONE) - { - Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), - GetSampleTypeName(type)); - return false; - } - SampleRate = srate; - Looping = loop; - - Data.Resize((size_t)(0.2 * SampleRate) * FrameSize); - - return true; - } -}; - - -extern ReverbContainer *ForcedEnvironment; - -#define AREA_SOUND_RADIUS (128.f) - -#define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ - -#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) - - -static float GetRolloff(const FRolloffInfo *rolloff, float distance) -{ - if(distance <= rolloff->MinDistance) - return 1.f; - // Logarithmic rolloff has no max distance where it goes silent. - if(rolloff->RolloffType == ROLLOFF_Log) - return rolloff->MinDistance / - (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); - if(distance >= rolloff->MaxDistance) - return 0.f; - - float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); - if(rolloff->RolloffType == ROLLOFF_Linear) - return volume; - - if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) - return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; - return (powf(10.f, volume) - 1.f) / 9.f; -} - -ALCdevice *OpenALSoundRenderer::InitDevice() -{ - ALCdevice *device = NULL; - if (IsOpenALPresent()) - { - if(strcmp(snd_aldevice, "Default") != 0) - { - device = alcOpenDevice(*snd_aldevice); - if(!device) - Printf(TEXTCOLOR_BLUE" Failed to open device " TEXTCOLOR_BOLD"%s" TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); - } - - if(!device) - { - device = alcOpenDevice(NULL); - if(!device) - { - Printf(TEXTCOLOR_RED" Could not open audio device\n"); - } - } - } - else - { - Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); - } - return device; -} - - -template -static void LoadALFunc(const char *name, T *x) -{ *x = reinterpret_cast(alGetProcAddress(name)); } - -#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) -OpenALSoundRenderer::OpenALSoundRenderer() - : Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) -{ - EnvFilters[0] = EnvFilters[1] = 0; - - Printf("I_InitSound: Initializing OpenAL\n"); - - Device = InitDevice(); - if (Device == NULL) return; - - const ALCchar *current = NULL; - if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) - current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); - if(alcGetError(Device) != ALC_NO_ERROR || !current) - current = alcGetString(Device, ALC_DEVICE_SPECIFIER); - Printf(" Opened device " TEXTCOLOR_ORANGE"%s\n", current); - - ALCint major=0, minor=0; - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - DPrintf(" ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - DPrintf(" ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - - TArray attribs; - if(*snd_samplerate > 0) - { - attribs.Push(ALC_FREQUENCY); - attribs.Push(*snd_samplerate); - } - // Make sure one source is capable of stereo output with the rest doing - // mono, without running out of voices - attribs.Push(ALC_MONO_SOURCES); - attribs.Push(MAX(*snd_channels, 2) - 1); - attribs.Push(ALC_STEREO_SOURCES); - attribs.Push(1); - // Other attribs..? - attribs.Push(0); - - Context = alcCreateContext(Device, &attribs[0]); - if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) - { - Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); - if(Context) - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - attribs.Clear(); - - DPrintf(" Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - DPrintf(" Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - DPrintf(" Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - DPrintf(" Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - - ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); - ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; - AL.EXT_source_distance_model = !!alIsExtensionPresent("AL_EXT_source_distance_model"); - AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); - AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); - - alDopplerFactor(0.5f); - alSpeedOfSound(343.3f * 96.0f); - alDistanceModel(AL_INVERSE_DISTANCE); - if(AL.EXT_source_distance_model) - alEnable(AL_SOURCE_DISTANCE_MODEL); - - if(AL.SOFT_deferred_updates) - { - LOAD_FUNC(alDeferUpdatesSOFT); - LOAD_FUNC(alProcessUpdatesSOFT); - } - else - { - alDeferUpdatesSOFT = _wrap_DeferUpdatesSOFT; - alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; - } - - ALenum err = getALError(); - if(err != AL_NO_ERROR) - { - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - - ALCint numMono=0, numStereo=0; - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - - Sources.Resize(MIN(MAX(*snd_channels, 2), numMono+numStereo)); - for(size_t i = 0;i < Sources.Size();i++) - { - alGenSources(1, &Sources[i]); - if(getALError() != AL_NO_ERROR) - { - Sources.Resize(i); - Sources.ShrinkToFit(); - break; - } - } - if(Sources.Size() == 0) - { - Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - FreeSfx = Sources; - DPrintf(" Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); - - WasInWater = false; - if(*snd_efx && ALC.EXT_EFX) - { - // EFX function pointers - LOAD_FUNC(alGenEffects); - LOAD_FUNC(alDeleteEffects); - LOAD_FUNC(alIsEffect); - LOAD_FUNC(alEffecti); - LOAD_FUNC(alEffectiv); - LOAD_FUNC(alEffectf); - LOAD_FUNC(alEffectfv); - LOAD_FUNC(alGetEffecti); - LOAD_FUNC(alGetEffectiv); - LOAD_FUNC(alGetEffectf); - LOAD_FUNC(alGetEffectfv); - - LOAD_FUNC(alGenFilters); - LOAD_FUNC(alDeleteFilters); - LOAD_FUNC(alIsFilter); - LOAD_FUNC(alFilteri); - LOAD_FUNC(alFilteriv); - LOAD_FUNC(alFilterf); - LOAD_FUNC(alFilterfv); - LOAD_FUNC(alGetFilteri); - LOAD_FUNC(alGetFilteriv); - LOAD_FUNC(alGetFilterf); - LOAD_FUNC(alGetFilterfv); - - LOAD_FUNC(alGenAuxiliaryEffectSlots); - LOAD_FUNC(alDeleteAuxiliaryEffectSlots); - LOAD_FUNC(alIsAuxiliaryEffectSlot); - LOAD_FUNC(alAuxiliaryEffectSloti); - LOAD_FUNC(alAuxiliaryEffectSlotiv); - LOAD_FUNC(alAuxiliaryEffectSlotf); - LOAD_FUNC(alAuxiliaryEffectSlotfv); - LOAD_FUNC(alGetAuxiliaryEffectSloti); - LOAD_FUNC(alGetAuxiliaryEffectSlotiv); - LOAD_FUNC(alGetAuxiliaryEffectSlotf); - LOAD_FUNC(alGetAuxiliaryEffectSlotfv); - if(getALError() == AL_NO_ERROR) - { - ALuint envReverb; - alGenEffects(1, &envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(" EAX Reverb found\n"); - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(" Standard Reverb found\n"); - - alDeleteEffects(1, &envReverb); - getALError(); - } - - alGenAuxiliaryEffectSlots(1, &EnvSlot); - alGenFilters(2, EnvFilters); - if(getALError() == AL_NO_ERROR) - { - alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - if(getALError() == AL_NO_ERROR) - DPrintf(" Lowpass found\n"); - else - { - alDeleteFilters(2, EnvFilters); - EnvFilters[0] = EnvFilters[1] = 0; - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvSlot = 0; - getALError(); - } - } - else - { - alDeleteFilters(2, EnvFilters); - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvFilters[0] = EnvFilters[1] = 0; - EnvSlot = 0; - getALError(); - } - } - } - - if(EnvSlot) - Printf(" EFX enabled\n"); -} -#undef LOAD_FUNC - -OpenALSoundRenderer::~OpenALSoundRenderer() -{ - if(!Device) - return; - - while(Streams.Size() > 0) - delete Streams[0]; - - alDeleteSources(Sources.Size(), &Sources[0]); - Sources.Clear(); - FreeSfx.Clear(); - SfxGroup.Clear(); - PausableSfx.Clear(); - ReverbSfx.Clear(); - - if(EnvEffects.CountUsed() > 0) - { - EffectMapIter iter(EnvEffects); - EffectMap::Pair *pair; - while(iter.NextPair(pair)) - alDeleteEffects(1, &(pair->Value)); - } - EnvEffects.Clear(); - - if(EnvSlot) - { - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - alDeleteFilters(2, EnvFilters); - } - EnvSlot = 0; - EnvFilters[0] = EnvFilters[1] = 0; - - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; -} - -void OpenALSoundRenderer::SetSfxVolume(float volume) -{ - SfxVolume = volume; - - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL) - { - ALuint source = GET_PTRID(schan->SysChannel); - volume = SfxVolume; - - alDeferUpdatesSOFT(); - alSourcef(source, AL_MAX_GAIN, volume); - alSourcef(source, AL_GAIN, volume * schan->Volume); - } - schan = schan->NextChan; - } - - alProcessUpdatesSOFT(); - - getALError(); -} - -void OpenALSoundRenderer::SetMusicVolume(float volume) -{ - MusicVolume = volume; - for(uint32 i = 0;i < Streams.Size();++i) - Streams[i]->UpdateVolume(); -} - -unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) -{ - if(sfx.data) - { - ALuint buffer = GET_PTRID(sfx.data); - if(alIsBuffer(buffer)) - { - ALint bits, channels, freq, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_FREQUENCY, &freq); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (unsigned int)(size / (channels*bits/8) * 1000. / freq); - } - } - return 0; -} - -unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) -{ - if(sfx.data) - { - ALuint buffer = GET_PTRID(sfx.data); - ALint bits, channels, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (ALsizei)(size / (channels * bits / 8)); - } - return 0; -} - -float OpenALSoundRenderer::GetOutputRate() -{ - ALCint rate = 44100; // Default, just in case - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); - return (float)rate; -} - - -SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) -{ - SoundHandle retval = { NULL }; - - if(length == 0) return retval; - - if(bits == -8) - { - // Simple signed->unsigned conversion - for(int i = 0;i < length;i++) - sfxdata[i] ^= 0x80; - bits = -bits; - } - - ALenum format = AL_NONE; - if(bits == 16) - { - if(channels == 1) format = AL_FORMAT_MONO16; - if(channels == 2) format = AL_FORMAT_STEREO16; - } - else if(bits == 8) - { - if(channels == 1) format = AL_FORMAT_MONO8; - if(channels == 2) format = AL_FORMAT_STEREO8; - } - - if(format == AL_NONE || frequency <= 0) - { - Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); - return retval; - } - length -= length%(channels*bits/8); - - ALenum err; - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, sfxdata, length, frequency); - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - return retval; - } - - if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points) - { - if(loopstart < 0) - loopstart = 0; - if(loopend < loopstart) - loopend = length / (channels*bits/8); - - ALint loops[2] = { loopstart, loopend }; - DPrintf("Setting loop points %d -> %d\n", loops[0], loops[1]); - alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); - getALError(); - } - else if(loopstart > 0 || loopend > 0) - { - static bool warned = false; - if(!warned) - Printf("Loop points not supported!\n"); - warned = true; - } - - retval.data = MAKE_PTRID(buffer); - return retval; -} - -SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) -{ - SoundHandle retval = { NULL }; - MemoryReader reader((const char*)sfxdata, length); - ALenum format = AL_NONE; - ChannelConfig chans; - SampleType type; - int srate; - - SoundDecoder *decoder = CreateDecoder(&reader); - if(!decoder) return retval; - - decoder->getInfo(&srate, &chans, &type); - if(chans == ChannelConfig_Mono) - { - if(type == SampleType_UInt8) format = AL_FORMAT_MONO8; - if(type == SampleType_Int16) format = AL_FORMAT_MONO16; - } - if(chans == ChannelConfig_Stereo) - { - if(type == SampleType_UInt8) format = AL_FORMAT_STEREO8; - if(type == SampleType_Int16) format = AL_FORMAT_STEREO16; - } - - if(format == AL_NONE) - { - Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), - GetSampleTypeName(type)); - delete decoder; - return retval; - } - - TArray data = decoder->readAll(); - - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, &data[0], data.Size(), srate); - - ALenum err; - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - delete decoder; - return retval; - } - - retval.data = MAKE_PTRID(buffer); - delete decoder; - return retval; -} - -void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) -{ - if(!sfx.data) - return; - - ALuint buffer = GET_PTRID(sfx.data); - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel) - { - ALint bufID = 0; - alGetSourcei(GET_PTRID(schan->SysChannel), AL_BUFFER, &bufID); - if((ALuint)bufID == buffer) - { - FSoundChan *next = schan->NextChan; - StopChannel(schan); - schan = next; - continue; - } - } - schan = schan->NextChan; - } - - alDeleteBuffers(1, &buffer); - getALError(); -} - - -SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) -{ - OpenALSoundStream *stream = new OpenALSoundStream(this); - if (!stream->Init(callback, buffbytes, flags, samplerate, userdata)) - { - delete stream; - return NULL; - } - return stream; -} - -SoundStream *OpenALSoundRenderer::OpenStream(FileReader *reader, int flags) -{ - OpenALSoundStream *stream = new OpenALSoundStream(this); - if (!stream->Init(reader, !!(flags&SoundStream::Loop))) - { - delete stream; - return NULL; - } - return stream; -} - -FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) -{ - if(FreeSfx.Size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) StopChannel(lowest); - - if(FreeSfx.Size() == 0) - return NULL; - } - - ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.Last(); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 1000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume*vol); - - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - } - if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); - - if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SEC_OFFSET, 0.f); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; - - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } - - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.Push(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.Push(source); - SfxGroup.Push(source); - FreeSfx.Pop(); - - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); - else chan->SysChannel = MAKE_PTRID(source); - - chan->Rolloff.RolloffType = ROLLOFF_Log; - chan->Rolloff.RolloffFactor = 0.f; - chan->Rolloff.MinDistance = 1.f; - chan->DistanceScale = 1.f; - chan->DistanceSqr = 0.f; - chan->ManualRolloff = false; - - return chan; -} - -FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, - FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, - int channum, int chanflags, FISoundChannel *reuse_chan) -{ - float dist_sqr = (float)(pos - listener->position).LengthSquared(); - - if(FreeSfx.Size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) - { - if(lowest->Priority < priority || (lowest->Priority == priority && - lowest->DistanceSqr > dist_sqr)) - StopChannel(lowest); - } - if(FreeSfx.Size() == 0) - return NULL; - } - - bool manualRolloff = true; - ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.Last(); - if(rolloff->RolloffType == ROLLOFF_Log) - { - if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); - manualRolloff = false; - } - else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) - { - alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - manualRolloff = false; - } - if(manualRolloff) - { - // How manual rolloff works: - // - // If a sound is using Custom or Doom style rolloff, or Linear style - // when AL_EXT_source_distance_model is not supported, we have to play - // around a bit to get appropriate distance attenation. What we do is - // calculate the attenuation that should be applied, then given an - // Inverse Distance rolloff model with OpenAL, reverse the calculation - // to get the distance needed for that much attenuation. The Inverse - // Distance calculation is: - // - // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) - // - // Thus, the reverse is: - // - // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist - // - // This can be simplified by using a MinDist and RolloffFactor of 1, - // which makes it: - // - // Distance = 1.0f/Gain; - // - // The source position is then set that many units away from the - // listener position, and OpenAL takes care of the rest. - if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 100000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - - FVector3 dir = pos - listener->position; - if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) - { - float gain = GetRolloff(rolloff, sqrt(dist_sqr) * distscale); - dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); - } - if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); - float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - dir += listener->position; - - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } - else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - FVector3 dir = pos - listener->position; - - float mindist = rolloff->MinDistance/distscale; - FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); - float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - - dir += listener->position; - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } - else - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume); - - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - } - if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); - - if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SAMPLE_OFFSET, 0.f); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; - - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } - - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.Push(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.Push(source); - SfxGroup.Push(source); - FreeSfx.Pop(); - - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); - else chan->SysChannel = MAKE_PTRID(source); - - chan->Rolloff = *rolloff; - chan->DistanceScale = distscale; - chan->DistanceSqr = dist_sqr; - chan->ManualRolloff = manualRolloff; - - return chan; -} - -void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - alDeferUpdatesSOFT(); - - ALuint source = GET_PTRID(chan->SysChannel); - alSourcef(source, AL_GAIN, SfxVolume * volume); -} - -void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - ALuint source = GET_PTRID(chan->SysChannel); - // Release first, so it can be properly marked as evicted if it's being - // forcefully killed - S_ChannelEnded(chan); - - alSourceRewind(source); - alSourcei(source, AL_BUFFER, 0); - getALError(); - - uint32 i; - if((i=PausableSfx.Find(source)) < PausableSfx.Size()) - PausableSfx.Delete(i); - if((i=ReverbSfx.Find(source)) < ReverbSfx.Size()) - ReverbSfx.Delete(i); - - SfxGroup.Delete(SfxGroup.Find(source)); - FreeSfx.Push(source); -} - -unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return 0; - - ALint pos; - alGetSourcei(GET_PTRID(chan->SysChannel), AL_SAMPLE_OFFSET, &pos); - if(getALError() == AL_NO_ERROR) - return pos; - return 0; -} - - -void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) -{ - int oldslots = SFXPaused; - - if(paused) - { - SFXPaused |= 1 << slot; - if(oldslots == 0 && PausableSfx.Size() > 0) - { - alSourcePausev(PausableSfx.Size(), &PausableSfx[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - SFXPaused &= ~(1 << slot); - if(SFXPaused == 0 && oldslots != 0 && PausableSfx.Size() > 0) - { - alSourcePlayv(PausableSfx.Size(), &PausableSfx[0]); - getALError(); - } - } -} - -void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState state) -{ - switch(state) - { - case SoundRenderer::INACTIVE_Active: - alListenerf(AL_GAIN, 1.0f); - break; - - /* FIXME: This doesn't stop anything. */ - case SoundRenderer::INACTIVE_Complete: - case SoundRenderer::INACTIVE_Mute: - alListenerf(AL_GAIN, 0.0f); - break; - } -} - -void OpenALSoundRenderer::Sync(bool sync) -{ - if(sync) - { - if(SfxGroup.Size() > 0) - { - alSourcePausev(SfxGroup.Size(), &SfxGroup[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - // Might already be something to handle this; basically, get a vector - // of all values in SfxGroup that are not also in PausableSfx (when - // SFXPaused is non-0). - TArray toplay = SfxGroup; - if(SFXPaused) - { - uint32 i = 0; - while(i < toplay.Size()) - { - uint32 p = PausableSfx.Find(toplay[i]); - if(p < PausableSfx.Size()) - toplay.Delete(i); - else - i++; - } - } - if(toplay.Size() > 0) - { - alSourcePlayv(toplay.Size(), &toplay[0]); - getALError(); - } - } -} - -void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - alDeferUpdatesSOFT(); - - FVector3 dir = pos - listener->position; - chan->DistanceSqr = (float)dir.LengthSquared(); - - if(chan->ManualRolloff) - { - if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) - { - float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); - dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); - } - if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); - float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - } - else if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; - FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); - float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - dir += listener->position; - - ALuint source = GET_PTRID(chan->SysChannel); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - getALError(); -} - -void OpenALSoundRenderer::UpdateListener(SoundListener *listener) -{ - if(!listener->valid) - return; - - alDeferUpdatesSOFT(); - - float angle = listener->angle; - ALfloat orient[6]; - // forward - orient[0] = cos(angle); - orient[1] = 0.f; - orient[2] = -sin(angle); - // up - orient[3] = 0.f; - orient[4] = 1.f; - orient[5] = 0.f; - - alListenerfv(AL_ORIENTATION, orient); - alListener3f(AL_POSITION, listener->position.X, - listener->position.Y, - -listener->position.Z); - alListener3f(AL_VELOCITY, listener->velocity.X, - listener->velocity.Y, - -listener->velocity.Z); - getALError(); - - const ReverbContainer *env = ForcedEnvironment; - if(!env) - { - env = listener->Environment; - if(!env) - env = DefaultEnvironments[0]; - } - if(env != PrevEnvironment || env->Modified) - { - PrevEnvironment = env; - DPrintf("Reverb Environment %s\n", env->Name); - - if(EnvSlot != 0) - LoadReverb(env); - - const_cast(env)->Modified = false; - } - - // NOTE: Moving into and out of water will undo pitch variations on sounds. - if(listener->underwater || env->SoftwareWater) - { - if(!WasInWater) - { - WasInWater = true; - - if(EnvSlot != 0 && *snd_waterreverb) - { - // Find the "Underwater" reverb environment - env = S_FindEnvironment(0x1600); - LoadReverb(env ? env : DefaultEnvironments[0]); - - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.125f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - - // Apply the updated filters on the sources - for(uint32 i = 0;i < ReverbSfx.Size();++i) - { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } - - for(uint32 i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); - getALError(); - } - } - else if(WasInWater) - { - WasInWater = false; - - if(EnvSlot != 0) - { - LoadReverb(env); - - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - for(uint32 i = 0;i < ReverbSfx.Size();++i) - { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } - - for(uint32 i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, 1.f); - getALError(); - } -} - -void OpenALSoundRenderer::UpdateSounds() -{ - alProcessUpdatesSOFT(); - - if(ALC.EXT_disconnect) - { - ALCint connected = ALC_TRUE; - alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); - if(connected == ALC_FALSE) - { - Printf("Sound device disconnected; restarting...\n"); - static char snd_reset[] = "snd_reset"; - AddCommandString(snd_reset); - return; - } - } - - PurgeStoppedSources(); -} - -void OpenALSoundRenderer::UpdateMusic() -{ - // For some reason this isn't being called? - for(uint32 i = 0;i < Streams.Size();++i) - Streams[i]->IsEnded(); -} - -bool OpenALSoundRenderer::IsValid() -{ - return Device != NULL; -} - -void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) -{ - // FIXME: Get current time (preferably from the audio clock, but the system - // time will have to do) - chan->StartTime.AsOne = 0; -} - -float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return 0.f; - - ALuint source = GET_PTRID(chan->SysChannel); - ALfloat volume = 0.f; - - alGetSourcef(source, AL_GAIN, &volume); - getALError(); - - volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); - return volume; -} - - -void OpenALSoundRenderer::PrintStatus() -{ - Printf("Output device: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); - getALCError(Device); - - ALCint frequency, major, minor, mono, stereo; - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("Device sample rate: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL"hz\n", frequency); - Printf("ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - Printf("Available sources: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" (" TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" mono, " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); - } - if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) - Printf("EFX not found\n"); - else - { - ALCint sends; - alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("EFX Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("Auxiliary sends: " TEXTCOLOR_BLUE"%d\n", sends); - } - } - Printf("Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - Printf("Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - Printf("Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - Printf("Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - getALError(); -} - -FString OpenALSoundRenderer::GatherStats() -{ - ALCint updates = 1; - alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); - getALCError(Device); - - uint32 total = Sources.Size(); - uint32 used = SfxGroup.Size()+Streams.Size(); - uint32 unused = FreeSfx.Size(); - - FString out; - out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%d" TEXTCOLOR_NORMAL"ms", - total, used, unused, 1000/updates); - return out; -} - -void OpenALSoundRenderer::PrintDriversList() -{ - const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - if(drivers == NULL) - { - Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - return; - } - - const ALCchar *current = NULL; - if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) - current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); - if(alcGetError(Device) != ALC_NO_ERROR || !current) - current = alcGetString(Device, ALC_DEVICE_SPECIFIER); - if(current == NULL) - { - Printf(TEXTCOLOR_YELLOW"Failed to retrieve device name: %s\n", alcGetString(Device, alcGetError(Device))); - return; - } - - Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, - "Default"); - for(int i = 1;*drivers;i++) - { - Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), - ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, - drivers); - drivers += strlen(drivers)+1; - } -} - -void OpenALSoundRenderer::PurgeStoppedSources() -{ - // Release channels that are stopped - for(uint32 i = 0;i < SfxGroup.Size();++i) - { - ALuint src = SfxGroup[i]; - ALint state = AL_INITIAL; - alGetSourcei(src, AL_SOURCE_STATE, &state); - if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) - continue; - - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) - { - StopChannel(schan); - break; - } - schan = schan->NextChan; - } - } - getALError(); -} - -void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) -{ - ALuint *envReverb = EnvEffects.CheckKey(env->ID); - bool doLoad = (env->Modified || !envReverb); - - if(!envReverb) - { - bool ok = false; - - envReverb = &EnvEffects.Insert(env->ID, 0); - alGenEffects(1, envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - ok = (alGetError() == AL_NO_ERROR); - if(!ok) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alDeleteEffects(1, envReverb); - getALError(); - } - } - if(!ok) - { - *envReverb = 0; - doLoad = false; - } - } - - if(doLoad) - { - const REVERB_PROPERTIES &props = env->Properties; - ALint type = AL_EFFECT_NULL; - - alGetEffecti(*envReverb, AL_EFFECT_TYPE, &type); -#define mB2Gain(x) ((float)pow(10., (x)/2000.)) - if(type == AL_EFFECT_EAXREVERB) - { - ALfloat reflectpan[3] = { props.ReflectionsPan0, - props.ReflectionsPan1, - props.ReflectionsPan2 }; - ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, - props.ReverbPan2 }; -#undef SETPARAM -#define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); - SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); - SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(*envReverb, DECAY_LFRATIO, props.DecayLFRatio); - SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - alEffectfv(*envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); - SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - alEffectfv(*envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); - SETPARAM(*envReverb, ECHO_TIME, props.EchoTime); - SETPARAM(*envReverb, ECHO_DEPTH, props.EchoDepth); - SETPARAM(*envReverb, MODULATION_TIME, props.ModulationTime); - SETPARAM(*envReverb, MODULATION_DEPTH, props.ModulationDepth); - SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(*envReverb, HFREFERENCE, props.HFReference); - SETPARAM(*envReverb, LFREFERENCE, props.LFReference); - SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(*envReverb, AL_EAXREVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); -#undef SETPARAM - } - else if(type == AL_EFFECT_REVERB) - { -#define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); - SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(*envReverb, AL_REVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); -#undef SETPARAM - } -#undef mB2Gain - } - - alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, *envReverb); - getALError(); -} - -FSoundChan *OpenALSoundRenderer::FindLowestChannel() -{ - FSoundChan *schan = Channels; - FSoundChan *lowest = NULL; - while(schan) - { - if(schan->SysChannel != NULL) - { - if(!lowest || schan->Priority < lowest->Priority || - (schan->Priority == lowest->Priority && - schan->DistanceSqr > lowest->DistanceSqr)) - lowest = schan; - } - schan = schan->NextChan; - } - return lowest; -} - -#endif // NO_OPENAL +} + +void I_BuildALDeviceList(FOptionValues *opt) +{ + opt->mValues.Resize(1); + opt->mValues[0].TextValue = "Default"; + opt->mValues[0].Text = "Default"; + +#ifndef NO_OPENAL + if (IsOpenALPresent()) + { + const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if (!names) + Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + else while (*names) + { + unsigned int i = opt->mValues.Reserve(1); + opt->mValues[i].TextValue = names; + opt->mValues[i].Text = names; + + names += strlen(names) + 1; + } + } +#endif +} + +#ifndef NO_OPENAL + + +EXTERN_CVAR (Int, snd_channels) +EXTERN_CVAR (Int, snd_samplerate) +EXTERN_CVAR (Bool, snd_waterreverb) +EXTERN_CVAR (Bool, snd_pitched) + + +#define MAKE_PTRID(x) ((void*)(uintptr_t)(x)) +#define GET_PTRID(x) ((uint32)(uintptr_t)(x)) + + +static ALenum checkALError(const char *fn, unsigned int ln) +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); + } + return err; +} +#define getALError() checkALError(__FILE__, __LINE__) + +static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); + } + return err; +} +#define getALCError(d) checkALCError((d), __FILE__, __LINE__) + + +// Fallback methods for when AL_SOFT_deferred_updates isn't available. In most +// cases these don't actually do anything, except on some Creative drivers +// where they act as appropriate fallbacks. +static ALvoid AL_APIENTRY _wrap_DeferUpdatesSOFT(void) +{ + alcSuspendContext(alcGetCurrentContext()); +} + +static ALvoid AL_APIENTRY _wrap_ProcessUpdatesSOFT(void) +{ + alcProcessContext(alcGetCurrentContext()); +} + + +class OpenALSoundStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + + SoundStreamCallback Callback; + void *UserData; + + TArray Data; + + ALsizei SampleRate; + ALenum Format; + ALsizei FrameSize; + + static const int BufferCount = 4; + ALuint Buffers[BufferCount]; + ALuint Source; + + bool Playing; + bool Looping; + ALfloat Volume; + + + FileReader *Reader; + SoundDecoder *Decoder; + static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) + { + OpenALSoundStream *self = static_cast(_sstream); + if(length < 0) return false; + + size_t got = self->Decoder->read((char*)ptr, length); + if(got < (unsigned int)length) + { + if(!self->Looping || !self->Decoder->seek(0)) + return false; + got += self->Decoder->read((char*)ptr+got, length-got); + } + + return (got == (unsigned int)length); + } + + + bool SetupSource() + { + /* Get a source, killing the farthest, lowest-priority sound if needed */ + if(Renderer->FreeSfx.Size() == 0) + { + FSoundChan *lowest = Renderer->FindLowestChannel(); + if(lowest) Renderer->StopChannel(lowest); + + if(Renderer->FreeSfx.Size() == 0) + return false; + } + Renderer->FreeSfx.Pop(Source); + + /* Set the default properties for localized playback */ + alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); + alSourcef(Source, AL_MAX_GAIN, 1.f); + alSourcef(Source, AL_GAIN, 1.f); + alSourcef(Source, AL_PITCH, 1.f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_SEC_OFFSET, 0.f); + alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(Source, AL_LOOPING, AL_FALSE); + if(Renderer->EnvSlot) + { + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); + alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + + alGenBuffers(BufferCount, Buffers); + return (getALError() == AL_NO_ERROR); + } + +public: + OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f), Reader(NULL), Decoder(NULL) + { + Renderer->Streams.Push(this); + memset(Buffers, 0, sizeof(Buffers)); + } + + virtual ~OpenALSoundStream() + { + if(Source) + { + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); + + Renderer->FreeSfx.Push(Source); + Source = 0; + } + + if(Buffers[0]) + { + alDeleteBuffers(BufferCount, &Buffers[0]); + memset(Buffers, 0, sizeof(Buffers)); + } + getALError(); + + Renderer->Streams.Delete(Renderer->Streams.Find(this)); + Renderer = NULL; + + delete Decoder; + delete Reader; + } + + + virtual bool Play(bool loop, float vol) + { + SetVolume(vol); + + if(Playing) + return true; + + /* Clear the buffer queue, then fill and queue each buffer */ + alSourcei(Source, AL_BUFFER, 0); + for(int i = 0;i < BufferCount;i++) + { + if(!Callback(this, &Data[0], Data.Size(), UserData)) + { + if(i == 0) + return false; + break; + } + + alBufferData(Buffers[i], Format, &Data[0], Data.Size(), SampleRate); + alSourceQueueBuffers(Source, 1, &Buffers[i]); + } + if(getALError() != AL_NO_ERROR) + return false; + + alSourcePlay(Source); + Playing = (getALError()==AL_NO_ERROR); + + return Playing; + } + + virtual void Stop() + { + if(!Playing) + return; + + alSourceStop(Source); + alSourcei(Source, AL_BUFFER, 0); + getALError(); + + Playing = false; + } + + virtual void SetVolume(float vol) + { + Volume = vol; + UpdateVolume(); + } + + void UpdateVolume() + { + alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); + getALError(); + } + + virtual bool SetPaused(bool pause) + { + if(pause) + alSourcePause(Source); + else + alSourcePlay(Source); + return (getALError()==AL_NO_ERROR); + } + + virtual bool SetPosition(unsigned int ms_pos) + { + if(!Decoder->seek(ms_pos)) + return false; + + if(!Playing) + return true; + // Stop the source so that all buffers become processed, then call + // IsEnded() to refill and restart the source queue with the new + // position. + alSourceStop(Source); + getALError(); + return !IsEnded(); + } + + virtual unsigned int GetPosition() + { + ALint offset, queued, state; + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + if(getALError() != AL_NO_ERROR) + return 0; + + size_t pos = Decoder->getSampleOffset(); + if(state != AL_STOPPED) + { + size_t rem = queued*(Data.Size()/FrameSize) - offset; + if(pos > rem) pos -= rem; + else pos = 0; + } + return (unsigned int)(pos * 1000.0 / SampleRate); + } + + virtual bool IsEnded() + { + if(!Playing) + return true; + + ALint state, processed; + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + + Playing = (getALError()==AL_NO_ERROR); + if(!Playing) + return true; + + // For each processed buffer in the queue... + while(processed > 0) + { + ALuint bufid; + + // Unqueue the oldest buffer, fill it with more data, and queue it + // on the end + alSourceUnqueueBuffers(Source, 1, &bufid); + processed--; + + if(Callback(this, &Data[0], Data.Size(), UserData)) + { + alBufferData(bufid, Format, &Data[0], Data.Size(), SampleRate); + alSourceQueueBuffers(Source, 1, &bufid); + } + } + + // If the source is not playing or paused, and there are buffers queued, + // then there was an underrun. Restart the source. + Playing = (getALError()==AL_NO_ERROR); + if(Playing && state != AL_PLAYING && state != AL_PAUSED) + { + ALint queued = 0; + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + + Playing = (getALError() == AL_NO_ERROR) && (queued > 0); + if(Playing) + { + alSourcePlay(Source); + Playing = (getALError()==AL_NO_ERROR); + } + } + + return !Playing; + } + + FString GetStats() + { + FString stats; + size_t pos, len; + ALfloat volume; + ALint offset; + ALint processed; + ALint queued; + ALint state; + ALenum err; + + alGetSourcef(Source, AL_GAIN, &volume); + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + if((err=alGetError()) != AL_NO_ERROR) + { + stats = "Error getting stats: "; + stats += alGetString(err); + return stats; + } + + stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : + (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; + + pos = Decoder->getSampleOffset(); + len = Decoder->getSampleLength(); + if(state == AL_STOPPED) + offset = BufferCount * (Data.Size()/FrameSize); + else + { + size_t rem = queued*(Data.Size()/FrameSize) - offset; + if(pos > rem) pos -= rem; + else if(len > 0) pos += len - rem; + else pos = 0; + } + pos = (size_t)(pos * 1000.0 / SampleRate); + len = (size_t)(len * 1000.0 / SampleRate); + stats.AppendFormat(",%3u%% buffered", 100 - 100*offset/(BufferCount*(Data.Size()/FrameSize))); + stats.AppendFormat(", %zu.%03zu", pos/1000, pos%1000); + if(len > 0) + stats.AppendFormat(" / %zu.%03zu", len/1000, len%1000); + if(state == AL_PAUSED) + stats += ", paused"; + if(state == AL_PLAYING) + stats += ", playing"; + stats.AppendFormat(", %uHz", SampleRate); + if(!Playing) + stats += " XX"; + return stats; + } + + bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + { + if(!SetupSource()) + return false; + + Callback = callback; + UserData = userdata; + SampleRate = samplerate; + + Format = AL_NONE; + if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ + { + if((flags&Mono)) Format = AL_FORMAT_MONO8; + else Format = AL_FORMAT_STEREO8; + } + else if((flags&Float)) + { + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; + else Format = AL_FORMAT_STEREO_FLOAT32; + } + } + else if((flags&Bits32)) + { + } + else + { + if((flags&Mono)) Format = AL_FORMAT_MONO16; + else Format = AL_FORMAT_STEREO16; + } + + if(Format == AL_NONE) + { + Printf("Unsupported format: 0x%x\n", flags); + return false; + } + + FrameSize = 1; + if((flags&Bits8)) + FrameSize *= 1; + else if((flags&(Bits32|Float))) + FrameSize *= 4; + else + FrameSize *= 2; + + if((flags&Mono)) + FrameSize *= 1; + else + FrameSize *= 2; + + buffbytes += FrameSize-1; + buffbytes -= buffbytes%FrameSize; + Data.Resize(buffbytes); + + return true; + } + + bool Init(FileReader *reader, bool loop) + { + if(!SetupSource()) + { + delete reader; + return false; + } + + if(Decoder) delete Decoder; + if(Reader) delete Reader; + Reader = reader; + Decoder = Renderer->CreateDecoder(Reader); + if(!Decoder) return false; + + Callback = DecoderCallback; + UserData = NULL; + Format = AL_NONE; + FrameSize = 1; + + ChannelConfig chans; + SampleType type; + int srate; + + Decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; + FrameSize *= 1; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; + FrameSize *= 2; + } + if(type == SampleType_UInt8) FrameSize *= 1; + if(type == SampleType_Int16) FrameSize *= 2; + + if(Format == AL_NONE) + { + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); + return false; + } + SampleRate = srate; + Looping = loop; + + Data.Resize((size_t)(0.2 * SampleRate) * FrameSize); + + return true; + } +}; + + +extern ReverbContainer *ForcedEnvironment; + +#define AREA_SOUND_RADIUS (128.f) + +#define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ + +#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) + + +static float GetRolloff(const FRolloffInfo *rolloff, float distance) +{ + if(distance <= rolloff->MinDistance) + return 1.f; + // Logarithmic rolloff has no max distance where it goes silent. + if(rolloff->RolloffType == ROLLOFF_Log) + return rolloff->MinDistance / + (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); + if(distance >= rolloff->MaxDistance) + return 0.f; + + float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); + if(rolloff->RolloffType == ROLLOFF_Linear) + return volume; + + if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) + return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; + return (powf(10.f, volume) - 1.f) / 9.f; +} + +ALCdevice *OpenALSoundRenderer::InitDevice() +{ + ALCdevice *device = NULL; + if (IsOpenALPresent()) + { + if(strcmp(snd_aldevice, "Default") != 0) + { + device = alcOpenDevice(*snd_aldevice); + if(!device) + Printf(TEXTCOLOR_BLUE" Failed to open device " TEXTCOLOR_BOLD"%s" TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); + } + + if(!device) + { + device = alcOpenDevice(NULL); + if(!device) + { + Printf(TEXTCOLOR_RED" Could not open audio device\n"); + } + } + } + else + { + Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); + } + return device; +} + + +template +static void LoadALFunc(const char *name, T *x) +{ *x = reinterpret_cast(alGetProcAddress(name)); } + +#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) +OpenALSoundRenderer::OpenALSoundRenderer() + : Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) +{ + EnvFilters[0] = EnvFilters[1] = 0; + + Printf("I_InitSound: Initializing OpenAL\n"); + + Device = InitDevice(); + if (Device == NULL) return; + + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + Printf(" Opened device " TEXTCOLOR_ORANGE"%s\n", current); + + ALCint major=0, minor=0; + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + DPrintf(" ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + DPrintf(" ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + + TArray attribs; + if(*snd_samplerate > 0) + { + attribs.Push(ALC_FREQUENCY); + attribs.Push(*snd_samplerate); + } + // Make sure one source is capable of stereo output with the rest doing + // mono, without running out of voices + attribs.Push(ALC_MONO_SOURCES); + attribs.Push(MAX(*snd_channels, 2) - 1); + attribs.Push(ALC_STEREO_SOURCES); + attribs.Push(1); + // Other attribs..? + attribs.Push(0); + + Context = alcCreateContext(Device, &attribs[0]); + if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) + { + Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); + if(Context) + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + attribs.Clear(); + + DPrintf(" Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + DPrintf(" Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + DPrintf(" Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + DPrintf(" Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + + ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); + ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; + AL.EXT_source_distance_model = !!alIsExtensionPresent("AL_EXT_source_distance_model"); + AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); + AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); + + alDopplerFactor(0.5f); + alSpeedOfSound(343.3f * 96.0f); + alDistanceModel(AL_INVERSE_DISTANCE); + if(AL.EXT_source_distance_model) + alEnable(AL_SOURCE_DISTANCE_MODEL); + + if(AL.SOFT_deferred_updates) + { + LOAD_FUNC(alDeferUpdatesSOFT); + LOAD_FUNC(alProcessUpdatesSOFT); + } + else + { + alDeferUpdatesSOFT = _wrap_DeferUpdatesSOFT; + alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; + } + + ALenum err = getALError(); + if(err != AL_NO_ERROR) + { + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + + ALCint numMono=0, numStereo=0; + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); + + Sources.Resize(MIN(MAX(*snd_channels, 2), numMono+numStereo)); + for(size_t i = 0;i < Sources.Size();i++) + { + alGenSources(1, &Sources[i]); + if(getALError() != AL_NO_ERROR) + { + Sources.Resize(i); + Sources.ShrinkToFit(); + break; + } + } + if(Sources.Size() == 0) + { + Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + FreeSfx = Sources; + DPrintf(" Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); + + WasInWater = false; + if(*snd_efx && ALC.EXT_EFX) + { + // EFX function pointers + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); + + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); + + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); + if(getALError() == AL_NO_ERROR) + { + ALuint envReverb; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" EAX Reverb found\n"); + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" Standard Reverb found\n"); + + alDeleteEffects(1, &envReverb); + getALError(); + } + + alGenAuxiliaryEffectSlots(1, &EnvSlot); + alGenFilters(2, EnvFilters); + if(getALError() == AL_NO_ERROR) + { + alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(getALError() == AL_NO_ERROR) + DPrintf(" Lowpass found\n"); + else + { + alDeleteFilters(2, EnvFilters); + EnvFilters[0] = EnvFilters[1] = 0; + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvSlot = 0; + getALError(); + } + } + else + { + alDeleteFilters(2, EnvFilters); + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvFilters[0] = EnvFilters[1] = 0; + EnvSlot = 0; + getALError(); + } + } + } + + if(EnvSlot) + Printf(" EFX enabled\n"); +} +#undef LOAD_FUNC + +OpenALSoundRenderer::~OpenALSoundRenderer() +{ + if(!Device) + return; + + while(Streams.Size() > 0) + delete Streams[0]; + + alDeleteSources(Sources.Size(), &Sources[0]); + Sources.Clear(); + FreeSfx.Clear(); + SfxGroup.Clear(); + PausableSfx.Clear(); + ReverbSfx.Clear(); + + if(EnvEffects.CountUsed() > 0) + { + EffectMapIter iter(EnvEffects); + EffectMap::Pair *pair; + while(iter.NextPair(pair)) + alDeleteEffects(1, &(pair->Value)); + } + EnvEffects.Clear(); + + if(EnvSlot) + { + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + alDeleteFilters(2, EnvFilters); + } + EnvSlot = 0; + EnvFilters[0] = EnvFilters[1] = 0; + + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; +} + +void OpenALSoundRenderer::SetSfxVolume(float volume) +{ + SfxVolume = volume; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL) + { + ALuint source = GET_PTRID(schan->SysChannel); + volume = SfxVolume; + + alDeferUpdatesSOFT(); + alSourcef(source, AL_MAX_GAIN, volume); + alSourcef(source, AL_GAIN, volume * schan->Volume); + } + schan = schan->NextChan; + } + + alProcessUpdatesSOFT(); + + getALError(); +} + +void OpenALSoundRenderer::SetMusicVolume(float volume) +{ + MusicVolume = volume; + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->UpdateVolume(); +} + +unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) +{ + if(sfx.data) + { + ALuint buffer = GET_PTRID(sfx.data); + if(alIsBuffer(buffer)) + { + ALint bits, channels, freq, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_FREQUENCY, &freq); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (unsigned int)(size / (channels*bits/8) * 1000. / freq); + } + } + return 0; +} + +unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) +{ + if(sfx.data) + { + ALuint buffer = GET_PTRID(sfx.data); + ALint bits, channels, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (ALsizei)(size / (channels * bits / 8)); + } + return 0; +} + +float OpenALSoundRenderer::GetOutputRate() +{ + ALCint rate = 44100; // Default, just in case + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); + return (float)rate; +} + + +SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) +{ + SoundHandle retval = { NULL }; + + if(length == 0) return retval; + + if(bits == -8) + { + // Simple signed->unsigned conversion + for(int i = 0;i < length;i++) + sfxdata[i] ^= 0x80; + bits = -bits; + } + + ALenum format = AL_NONE; + if(bits == 16) + { + if(channels == 1) format = AL_FORMAT_MONO16; + if(channels == 2) format = AL_FORMAT_STEREO16; + } + else if(bits == 8) + { + if(channels == 1) format = AL_FORMAT_MONO8; + if(channels == 2) format = AL_FORMAT_STEREO8; + } + + if(format == AL_NONE || frequency <= 0) + { + Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); + return retval; + } + length -= length%(channels*bits/8); + + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, sfxdata, length, frequency); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return retval; + } + + if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points) + { + if(loopstart < 0) + loopstart = 0; + if(loopend < loopstart) + loopend = length / (channels*bits/8); + + ALint loops[2] = { loopstart, loopend }; + DPrintf("Setting loop points %d -> %d\n", loops[0], loops[1]); + alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); + getALError(); + } + else if(loopstart > 0 || loopend > 0) + { + static bool warned = false; + if(!warned) + Printf("Loop points not supported!\n"); + warned = true; + } + + retval.data = MAKE_PTRID(buffer); + return retval; +} + +SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) +{ + SoundHandle retval = { NULL }; + MemoryReader reader((const char*)sfxdata, length); + ALenum format = AL_NONE; + ChannelConfig chans; + SampleType type; + int srate; + + SoundDecoder *decoder = CreateDecoder(&reader); + if(!decoder) return retval; + + decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) format = AL_FORMAT_MONO16; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) format = AL_FORMAT_STEREO16; + } + + if(format == AL_NONE) + { + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); + delete decoder; + return retval; + } + + TArray data = decoder->readAll(); + + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, &data[0], data.Size(), srate); + + ALenum err; + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + delete decoder; + return retval; + } + + retval.data = MAKE_PTRID(buffer); + delete decoder; + return retval; +} + +void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) +{ + if(!sfx.data) + return; + + ALuint buffer = GET_PTRID(sfx.data); + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel) + { + ALint bufID = 0; + alGetSourcei(GET_PTRID(schan->SysChannel), AL_BUFFER, &bufID); + if((ALuint)bufID == buffer) + { + FSoundChan *next = schan->NextChan; + StopChannel(schan); + schan = next; + continue; + } + } + schan = schan->NextChan; + } + + alDeleteBuffers(1, &buffer); + getALError(); +} + + +SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) +{ + OpenALSoundStream *stream = new OpenALSoundStream(this); + if (!stream->Init(callback, buffbytes, flags, samplerate, userdata)) + { + delete stream; + return NULL; + } + return stream; +} + +SoundStream *OpenALSoundRenderer::OpenStream(FileReader *reader, int flags) +{ + OpenALSoundStream *stream = new OpenALSoundStream(this); + if (!stream->Init(reader, !!(flags&SoundStream::Loop))) + { + delete stream; + return NULL; + } + return stream; +} + +FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) +{ + if(FreeSfx.Size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) StopChannel(lowest); + + if(FreeSfx.Size() == 0) + return NULL; + } + + ALuint buffer = GET_PTRID(sfx.data); + ALuint source = FreeSfx.Last(); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 1000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); + + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + } + if(WasInWater && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SEC_OFFSET, 0.f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.Push(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); + + chan->Rolloff.RolloffType = ROLLOFF_Log; + chan->Rolloff.RolloffFactor = 0.f; + chan->Rolloff.MinDistance = 1.f; + chan->DistanceScale = 1.f; + chan->DistanceSqr = 0.f; + chan->ManualRolloff = false; + + return chan; +} + +FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, + FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, + int channum, int chanflags, FISoundChannel *reuse_chan) +{ + float dist_sqr = (float)(pos - listener->position).LengthSquared(); + + if(FreeSfx.Size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) + { + if(lowest->Priority < priority || (lowest->Priority == priority && + lowest->DistanceSqr > dist_sqr)) + StopChannel(lowest); + } + if(FreeSfx.Size() == 0) + return NULL; + } + + bool manualRolloff = true; + ALuint buffer = GET_PTRID(sfx.data); + ALuint source = FreeSfx.Last(); + if(rolloff->RolloffType == ROLLOFF_Log) + { + if(AL.EXT_source_distance_model) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); + manualRolloff = false; + } + else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) + { + alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + manualRolloff = false; + } + if(manualRolloff) + { + // How manual rolloff works: + // + // If a sound is using Custom or Doom style rolloff, or Linear style + // when AL_EXT_source_distance_model is not supported, we have to play + // around a bit to get appropriate distance attenation. What we do is + // calculate the attenuation that should be applied, then given an + // Inverse Distance rolloff model with OpenAL, reverse the calculation + // to get the distance needed for that much attenuation. The Inverse + // Distance calculation is: + // + // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) + // + // Thus, the reverse is: + // + // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist + // + // This can be simplified by using a MinDist and RolloffFactor of 1, + // which makes it: + // + // Distance = 1.0f/Gain; + // + // The source position is then set that many units away from the + // listener position, and OpenAL takes care of the rest. + if(AL.EXT_source_distance_model) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 100000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + + FVector3 dir = pos - listener->position; + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(rolloff, sqrt(dist_sqr) * distscale); + dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + dir += listener->position; + + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 dir = pos - listener->position; + + float mindist = rolloff->MinDistance/distscale; + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + + dir += listener->position; + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + else + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); + + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + } + if(WasInWater && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SAMPLE_OFFSET, 0.f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.Push(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); + + chan->Rolloff = *rolloff; + chan->DistanceScale = distscale; + chan->DistanceSqr = dist_sqr; + chan->ManualRolloff = manualRolloff; + + return chan; +} + +void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alDeferUpdatesSOFT(); + + ALuint source = GET_PTRID(chan->SysChannel); + alSourcef(source, AL_GAIN, SfxVolume * volume); +} + +void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + ALuint source = GET_PTRID(chan->SysChannel); + // Release first, so it can be properly marked as evicted if it's being + // forcefully killed + S_ChannelEnded(chan); + + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + getALError(); + + uint32 i; + if((i=PausableSfx.Find(source)) < PausableSfx.Size()) + PausableSfx.Delete(i); + if((i=ReverbSfx.Find(source)) < ReverbSfx.Size()) + ReverbSfx.Delete(i); + + SfxGroup.Delete(SfxGroup.Find(source)); + FreeSfx.Push(source); +} + +unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0; + + ALint pos; + alGetSourcei(GET_PTRID(chan->SysChannel), AL_SAMPLE_OFFSET, &pos); + if(getALError() == AL_NO_ERROR) + return pos; + return 0; +} + + +void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) +{ + int oldslots = SFXPaused; + + if(paused) + { + SFXPaused |= 1 << slot; + if(oldslots == 0 && PausableSfx.Size() > 0) + { + alSourcePausev(PausableSfx.Size(), &PausableSfx[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + SFXPaused &= ~(1 << slot); + if(SFXPaused == 0 && oldslots != 0 && PausableSfx.Size() > 0) + { + alSourcePlayv(PausableSfx.Size(), &PausableSfx[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState state) +{ + switch(state) + { + case SoundRenderer::INACTIVE_Active: + alListenerf(AL_GAIN, 1.0f); + break; + + /* FIXME: This doesn't stop anything. */ + case SoundRenderer::INACTIVE_Complete: + case SoundRenderer::INACTIVE_Mute: + alListenerf(AL_GAIN, 0.0f); + break; + } +} + +void OpenALSoundRenderer::Sync(bool sync) +{ + if(sync) + { + if(SfxGroup.Size() > 0) + { + alSourcePausev(SfxGroup.Size(), &SfxGroup[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + // Might already be something to handle this; basically, get a vector + // of all values in SfxGroup that are not also in PausableSfx (when + // SFXPaused is non-0). + TArray toplay = SfxGroup; + if(SFXPaused) + { + uint32 i = 0; + while(i < toplay.Size()) + { + uint32 p = PausableSfx.Find(toplay[i]); + if(p < PausableSfx.Size()) + toplay.Delete(i); + else + i++; + } + } + if(toplay.Size() > 0) + { + alSourcePlayv(toplay.Size(), &toplay[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alDeferUpdatesSOFT(); + + FVector3 dir = pos - listener->position; + chan->DistanceSqr = (float)dir.LengthSquared(); + + if(chan->ManualRolloff) + { + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); + dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + } + else if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + dir += listener->position; + + ALuint source = GET_PTRID(chan->SysChannel); + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + getALError(); +} + +void OpenALSoundRenderer::UpdateListener(SoundListener *listener) +{ + if(!listener->valid) + return; + + alDeferUpdatesSOFT(); + + float angle = listener->angle; + ALfloat orient[6]; + // forward + orient[0] = cos(angle); + orient[1] = 0.f; + orient[2] = -sin(angle); + // up + orient[3] = 0.f; + orient[4] = 1.f; + orient[5] = 0.f; + + alListenerfv(AL_ORIENTATION, orient); + alListener3f(AL_POSITION, listener->position.X, + listener->position.Y, + -listener->position.Z); + alListener3f(AL_VELOCITY, listener->velocity.X, + listener->velocity.Y, + -listener->velocity.Z); + getALError(); + + const ReverbContainer *env = ForcedEnvironment; + if(!env) + { + env = listener->Environment; + if(!env) + env = DefaultEnvironments[0]; + } + if(env != PrevEnvironment || env->Modified) + { + PrevEnvironment = env; + DPrintf("Reverb Environment %s\n", env->Name); + + if(EnvSlot != 0) + LoadReverb(env); + + const_cast(env)->Modified = false; + } + + // NOTE: Moving into and out of water will undo pitch variations on sounds. + if(listener->underwater || env->SoftwareWater) + { + if(!WasInWater) + { + WasInWater = true; + + if(EnvSlot != 0 && *snd_waterreverb) + { + // Find the "Underwater" reverb environment + env = S_FindEnvironment(0x1600); + LoadReverb(env ? env : DefaultEnvironments[0]); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.125f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + + // Apply the updated filters on the sources + for(uint32 i = 0;i < ReverbSfx.Size();++i) + { + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); + getALError(); + } + } + else if(WasInWater) + { + WasInWater = false; + + if(EnvSlot != 0) + { + LoadReverb(env); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + for(uint32 i = 0;i < ReverbSfx.Size();++i) + { + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, 1.f); + getALError(); + } +} + +void OpenALSoundRenderer::UpdateSounds() +{ + alProcessUpdatesSOFT(); + + if(ALC.EXT_disconnect) + { + ALCint connected = ALC_TRUE; + alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); + if(connected == ALC_FALSE) + { + Printf("Sound device disconnected; restarting...\n"); + static char snd_reset[] = "snd_reset"; + AddCommandString(snd_reset); + return; + } + } + + PurgeStoppedSources(); +} + +void OpenALSoundRenderer::UpdateMusic() +{ + // For some reason this isn't being called? + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->IsEnded(); +} + +bool OpenALSoundRenderer::IsValid() +{ + return Device != NULL; +} + +void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) +{ + // FIXME: Get current time (preferably from the audio clock, but the system + // time will have to do) + chan->StartTime.AsOne = 0; +} + +float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0.f; + + ALuint source = GET_PTRID(chan->SysChannel); + ALfloat volume = 0.f; + + alGetSourcef(source, AL_GAIN, &volume); + getALError(); + + volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); + return volume; +} + + +void OpenALSoundRenderer::PrintStatus() +{ + Printf("Output device: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + getALCError(Device); + + ALCint frequency, major, minor, mono, stereo; + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("Device sample rate: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL"hz\n", frequency); + Printf("ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + Printf("Available sources: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" (" TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" mono, " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); + } + if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + Printf("EFX not found\n"); + else + { + ALCint sends; + alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("EFX Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("Auxiliary sends: " TEXTCOLOR_BLUE"%d\n", sends); + } + } + Printf("Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + Printf("Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + Printf("Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + Printf("Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + getALError(); +} + +FString OpenALSoundRenderer::GatherStats() +{ + ALCint updates = 1; + alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); + getALCError(Device); + + uint32 total = Sources.Size(); + uint32 used = SfxGroup.Size()+Streams.Size(); + uint32 unused = FreeSfx.Size(); + + FString out; + out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%d" TEXTCOLOR_NORMAL"ms", + total, used, unused, 1000/updates); + return out; +} + +void OpenALSoundRenderer::PrintDriversList() +{ + const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if(drivers == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + return; + } + + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + if(current == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device name: %s\n", alcGetString(Device, alcGetError(Device))); + return; + } + + Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, + "Default"); + for(int i = 1;*drivers;i++) + { + Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), + ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, + drivers); + drivers += strlen(drivers)+1; + } +} + +void OpenALSoundRenderer::PurgeStoppedSources() +{ + // Release channels that are stopped + for(uint32 i = 0;i < SfxGroup.Size();++i) + { + ALuint src = SfxGroup[i]; + ALint state = AL_INITIAL; + alGetSourcei(src, AL_SOURCE_STATE, &state); + if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) + continue; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) + { + StopChannel(schan); + break; + } + schan = schan->NextChan; + } + } + getALError(); +} + +void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) +{ + ALuint *envReverb = EnvEffects.CheckKey(env->ID); + bool doLoad = (env->Modified || !envReverb); + + if(!envReverb) + { + bool ok = false; + + envReverb = &EnvEffects.Insert(env->ID, 0); + alGenEffects(1, envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + ok = (alGetError() == AL_NO_ERROR); + if(!ok) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alDeleteEffects(1, envReverb); + getALError(); + } + } + if(!ok) + { + *envReverb = 0; + doLoad = false; + } + } + + if(doLoad) + { + const REVERB_PROPERTIES &props = env->Properties; + ALint type = AL_EFFECT_NULL; + + alGetEffecti(*envReverb, AL_EFFECT_TYPE, &type); +#define mB2Gain(x) ((float)pow(10., (x)/2000.)) + if(type == AL_EFFECT_EAXREVERB) + { + ALfloat reflectpan[3] = { props.ReflectionsPan0, + props.ReflectionsPan1, + props.ReflectionsPan2 }; + ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, + props.ReverbPan2 }; +#undef SETPARAM +#define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, DECAY_LFRATIO, props.DecayLFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + alEffectfv(*envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + alEffectfv(*envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); + SETPARAM(*envReverb, ECHO_TIME, props.EchoTime); + SETPARAM(*envReverb, ECHO_DEPTH, props.EchoDepth); + SETPARAM(*envReverb, MODULATION_TIME, props.ModulationTime); + SETPARAM(*envReverb, MODULATION_DEPTH, props.ModulationDepth); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, HFREFERENCE, props.HFReference); + SETPARAM(*envReverb, LFREFERENCE, props.LFReference); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_EAXREVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } + else if(type == AL_EFFECT_REVERB) + { +#define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_REVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } +#undef mB2Gain + } + + alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, *envReverb); + getALError(); +} + +FSoundChan *OpenALSoundRenderer::FindLowestChannel() +{ + FSoundChan *schan = Channels; + FSoundChan *lowest = NULL; + while(schan) + { + if(schan->SysChannel != NULL) + { + if(!lowest || schan->Priority < lowest->Priority || + (schan->Priority == lowest->Priority && + schan->DistanceSqr > lowest->DistanceSqr)) + lowest = schan; + } + schan = schan->NextChan; + } + return lowest; +} + +#endif // NO_OPENAL From 01917d9f15fdfbc8fc557c8e33348d11b5b83f39 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:06:39 +0100 Subject: [PATCH 132/335] - fixed incorrect state settings in Macil. --- wadsrc/static/actors/strife/macil.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/actors/strife/macil.txt b/wadsrc/static/actors/strife/macil.txt index 24af35ada..7b001e778 100644 --- a/wadsrc/static/actors/strife/macil.txt +++ b/wadsrc/static/actors/strife/macil.txt @@ -44,7 +44,7 @@ ACTOR Macil1 Death: LEAD E 2 A_FaceTarget LEAD F 2 BRIGHT A_ShootGun - LEAD E 2 A_SentinelRefire + LEAD E 1 A_SentinelRefire Loop Pain: LEAD Y 3 @@ -80,7 +80,7 @@ ACTOR Macil2 : Macil1 LEAD K 3 LEAD L 3 A_NoBlocking LEAD MNOPQRSTUV 3 - LEAD W 4 Bright A_SpawnItemEx("AlienSpectre4", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION) + LEAD W 3 A_SpawnItemEx("AlienSpectre4", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION) LEAD X -1 Stop } From 1e0366f98f7eae81ade2d860e6f9c9c6596bde19 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:27:35 +0100 Subject: [PATCH 133/335] - fixed: $musicalias must be resolved before comparing for equality with the currently playing music. --- src/s_sound.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index bacd5aa94..7b38e816c 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2375,6 +2375,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } } + FName *aliasp = MusicAliases.CheckKey(musicname); + if (aliasp != NULL) + { + if (*aliasp == NAME_None) + { + return true; // flagged to be ignored + } + musicname = aliasp->GetChars(); + } + if (!mus_playing.name.IsEmpty() && mus_playing.handle != NULL && stricmp (mus_playing.name, musicname) == 0 && @@ -2413,16 +2423,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) int length = 0; int device = MDEV_DEFAULT; MusInfo *handle = NULL; - FName musicasname = musicname; - FName *aliasp = MusicAliases.CheckKey(musicasname); - if (aliasp != NULL) - { - musicname = (musicasname = *aliasp).GetChars(); - if (musicasname == NAME_None) return true; - } - - int *devp = MidiDevices.CheckKey(musicasname); + int *devp = MidiDevices.CheckKey(musicname); if (devp != NULL) device = *devp; // Strip off any leading file:// component. From f4ab6074faf10624e76bad222cfe749d5c7bcbaf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:30:12 +0100 Subject: [PATCH 134/335] - today's 'GCC sucks' fix. (Yet again some overtly anal type issues with the '? :' operator...) --- src/p_sectors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index bc7abd380..361b220a7 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -806,12 +806,15 @@ ASkyViewpoint *sector_t::GetSkyBox(int which) { if (which == floor) { - return FloorSkyBox != NULL ? FloorSkyBox : (MoreFlags & SECF_NOFLOORSKYBOX)? (ASkyViewpoint*)NULL : level.DefaultSkybox; + if (FloorSkyBox != NULL) return FloorSkyBox; + if (MoreFlags & SECF_NOFLOORSKYBOX) return NULL; } else { - return CeilingSkyBox != NULL ? CeilingSkyBox : (MoreFlags & SECF_NOCEILINGSKYBOX)? (ASkyViewpoint*)NULL : level.DefaultSkybox; + if (CeilingSkyBox != NULL) return CeilingSkyBox; + if (MoreFlags & SECF_NOCEILINGSKYBOX) return NULL; } + return level.DefaultSkybox; } From 355f70986a9f106f857f38b261b0cd306659c114 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:36:42 +0100 Subject: [PATCH 135/335] - fixed: 'give' inventory functions ignored an items MaxAmount setting. --- src/g_shared/a_pickups.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 5d494c935..e87929677 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -680,6 +680,7 @@ AInventory *AInventory::CreateCopy (AActor *other) { AInventory *copy; + Amount = MIN(Amount, MaxAmount); if (GoAway ()) { copy = static_cast(Spawn (GetClass(), 0, 0, 0, NO_REPLACE)); From 78deb70a000b72be1bfa67f2ab84298ce4e941f4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:40:18 +0100 Subject: [PATCH 136/335] - fixed: ConfigSections were not properly deallocated --- src/configfile.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/configfile.cpp b/src/configfile.cpp index b8db74eb3..13cfea517 100644 --- a/src/configfile.cpp +++ b/src/configfile.cpp @@ -368,8 +368,7 @@ bool FConfigFile::DeleteCurrentSection() LastSectionPtr = &sec->Next; } - CurrentSection->~FConfigSection(); - delete[] (char *)CurrentSection; + delete CurrentSection; CurrentSection = sec->Next; return CurrentSection != NULL; From 6efc2a0ec747d90c536c2b3cb525caae1a3559d8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Nov 2015 13:47:04 +0100 Subject: [PATCH 137/335] - fixed positioning of map name on Hexen automap. --- src/g_shared/shared_sbar.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index c0442fc74..b74350633 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1338,17 +1338,17 @@ void DBaseStatusBar::Draw (EHudState state) { if (Scaled) { - y -= Scale (10, SCREENHEIGHT, 200); + y -= Scale (11, SCREENHEIGHT, 200); } else { if (SCREENWIDTH < 640) { - y -= 11; + y -= 12; } else { // Get past the tops of the gargoyles' wings - y -= 26; + y -= 28; } } } From fca469b053a86d17088a357e019485a25e69f5cf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Nov 2015 10:25:05 +0100 Subject: [PATCH 138/335] - moved the notification messages for SendToCommunicator into LANGUAGE. As a side effect this will now allow using custom messages with this function as well by using the arg2 parameter as part of the message's name (arg2=0 will use TXT_COMM0, arg1 TXT_COMM1 and so on.) --- src/p_lnspec.cpp | 14 ++++++++------ wadsrc/static/language.enu | 4 ++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 37d6d6058..35b0300ef 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -56,6 +56,7 @@ #include "p_3dmidtex.h" #include "d_net.h" #include "d_event.h" +#include "gstrings.h" #include "r_data/colormaps.h" #define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \ @@ -2985,13 +2986,14 @@ FUNC(LS_SendToCommunicator) { S_StopSound (CHAN_VOICE); S_Sound (CHAN_VOICE, name, 1, ATTN_NORM); - if (arg2 == 0) + + // Get the message from the LANGUAGE lump. + FString msg; + msg.Format("TXT_COMM%d", arg2); + const char *str = GStrings[msg]; + if (msg != NULL) { - Printf (PRINT_CHAT, "Incoming Message\n"); - } - else if (arg2 == 1) - { - Printf (PRINT_CHAT, "Incoming Message from BlackBird\n"); + Printf (PRINT_CHAT, "%s\n", str); } } return true; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index bdefa1b86..005a3f57d 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1550,6 +1550,10 @@ TXT_RANDOMGOODBYE_3 = "See you later!"; TXT_HAVEENOUGH = "You seem to have enough!"; TXT_GOAWAY = "Go away!"; +TXT_COMM0 = "Incoming Message"; +TXT_COMM1 = "Incoming Message from BlackBird"; + + // Skills: SKILL_BABY = "I'm too young to die"; From 7e8721687819fb83dd413982f21d91190ec02e40 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Nov 2015 10:44:37 +0100 Subject: [PATCH 139/335] - fixed: r_visibility values >= 205 appear to cause fixed point overflows at least on 5:4 aspect ratio so they should be blocked. --- src/r_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index 5da0b8992..b136d9cc6 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -254,7 +254,7 @@ void R_InitTextureMapping () void R_SetVisibility (float vis) { // Allow negative visibilities, just for novelty's sake - //vis = clamp (vis, -204.7f, 204.7f); + vis = clamp (vis, -204.7f, 204.7f); // (205 and larger do not work in 5:4 aspect ratio) CurrentVisibility = vis; From a55d85c51c9a928218bcbde480a21c46f5714380 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Nov 2015 12:12:08 +0100 Subject: [PATCH 140/335] - do not wait infinitely for termination of the Timidity++ process. This can lock up the engine indefinitely if the child process fails to exit. --- src/sound/music_midi_timidity.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index ec2843c79..dbc56cc56 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -713,11 +713,11 @@ BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) if ( hRT ) { - // Must wait process to terminate to guarantee that it has exited... - WaitForSingleObject(hProcess, INFINITE); - + // Must wait for process to terminate to guarantee that it has exited... + DWORD res = WaitForSingleObject(hProcess, 1000); CloseHandle(hRT); - bSuccess = TRUE; + bSuccess = (res == WAIT_OBJECT_0); + dwErr = WAIT_TIMEOUT; } if ( !bSuccess ) From 3fadfec77d58d41b8aab7cbcabbe17182f1b4ccb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Nov 2015 00:43:39 +0100 Subject: [PATCH 141/335] - fixed typo in SendToCommunicator enhancement. --- src/p_lnspec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 35b0300ef..26e736cb5 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2991,7 +2991,7 @@ FUNC(LS_SendToCommunicator) FString msg; msg.Format("TXT_COMM%d", arg2); const char *str = GStrings[msg]; - if (msg != NULL) + if (str != NULL) { Printf (PRINT_CHAT, "%s\n", str); } From 888f356e58c31f3a88544c7dbb458f9225ae4091 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Nov 2015 12:43:01 +0100 Subject: [PATCH 142/335] - use the recently added text input menu item to add the config file for GUS, the patch set for Fluidsynth and the timidity.exe path for Timidity++ to the menu. Even though there is no proper file select box, this is still better than nothing. - changed the text input item so that it realigns itself to show the entire text when in text input mode. --- src/menu/optionmenuitems.h | 13 +++++++++++++ wadsrc/static/menudef.txt | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index e87e78483..c63359f4b 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -1045,6 +1045,19 @@ public: return text; } + int Draw(FOptionMenuDescriptor*desc, int y, int indent, bool selected) + { + if (mEntering) + { + // reposition the text so that the cursor is visible when in entering mode. + FString text = Represent(); + int tlen = SmallFont->StringWidth(text) * CleanXfac_1; + int newindent = screen->GetWidth() - tlen - CURSORSPACE; + if (newindent < indent) indent = newindent; + } + return FOptionMenuFieldBase::Draw(desc, y, indent, selected); + } + bool MenuEvent ( int mkey, bool fromcontroller ) { if ( mkey == MKEY_Enter ) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 1b9a2c606..eef2629d3 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1590,10 +1590,24 @@ OptionMenu AdvSoundOptions Option "OPL Emulator Core", "opl_core", "OplCores" StaticText " " StaticText "GUS Emulation", 1 + TextField "GUS config file", "midi_config" Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 Option "Emulate TiMidity", "midi_timiditylike", "OnOff" Option "Read DMXGUS lumps", "midi_dmxgus", "OnOff" Option "GUS memory size", "gus_memsize", "GusMemory" + StaticText " " + StaticText "FluidSynth", 1 + TextField "Patch set", "fluid_patchset" + Slider "Gain", "fluid_gain", 0, 10, 0.5, 1 + Option "Reverb", "fluid_reverb", "OnOff" + Slider "MIDI voices", "fluid_voices", 16, 4096, 16, 1 + // Leaving out the more advanced stuff for now. + StaticText " " + StaticText "Timidity++", 1 + TextField "Path for executable", "timidity_exe" + Option "Reverb", "timidity_reverb", "OnOff" + Option "Chorus", "timidity_chorus", "OnOff" + Slider "Relative volume", "timidity_mastervolume", 0, 4, 0.2, 1 } /*======================================= From eff2286bc905c8891928513a7415cb24985365bc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Nov 2015 17:38:40 +0100 Subject: [PATCH 143/335] - added WildMidi library sources - all converted to C++ so that they can later interface with ZDoom's own MIDI code. Also redid the file loading function to use ZDoom's FileReader instead of low level IO. --- src/CMakeLists.txt | 8 + src/wildmidi/common.h | 94 + src/wildmidi/file_io.cpp | 71 + src/wildmidi/file_io.h | 33 + src/wildmidi/gus_pat.cpp | 900 +++++++ src/wildmidi/gus_pat.h | 77 + src/wildmidi/lock.cpp | 87 + src/wildmidi/lock.h | 36 + src/wildmidi/reverb.cpp | 398 +++ src/wildmidi/reverb.h | 57 + src/wildmidi/wildmidi_lib.cpp | 4290 +++++++++++++++++++++++++++++++++ src/wildmidi/wildmidi_lib.h | 75 + src/wildmidi/wm_error.cpp | 86 + src/wildmidi/wm_error.h | 56 + 14 files changed, 6268 insertions(+) create mode 100644 src/wildmidi/common.h create mode 100644 src/wildmidi/file_io.cpp create mode 100644 src/wildmidi/file_io.h create mode 100644 src/wildmidi/gus_pat.cpp create mode 100644 src/wildmidi/gus_pat.h create mode 100644 src/wildmidi/lock.cpp create mode 100644 src/wildmidi/lock.h create mode 100644 src/wildmidi/reverb.cpp create mode 100644 src/wildmidi/reverb.h create mode 100644 src/wildmidi/wildmidi_lib.cpp create mode 100644 src/wildmidi/wildmidi_lib.h create mode 100644 src/wildmidi/wm_error.cpp create mode 100644 src/wildmidi/wm_error.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 782e4bac0..614d2fb50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1128,6 +1128,12 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE timidity/playmidi.cpp timidity/resample.cpp timidity/timidity.cpp + wildmidi/file_io.cpp + wildmidi/gus_pat.cpp + wildmidi/lock.cpp + wildmidi/reverb.cpp + wildmidi/wildmidi_lib.cpp + wildmidi/wm_error.cpp xlat/parse_xlat.cpp fragglescript/t_fspic.cpp fragglescript/t_func.cpp @@ -1265,6 +1271,8 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h) source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$") source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$") +source_group("Audio Files\\WildMidi\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.h$") +source_group("Audio Files\\WildMidi\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.cpp$") source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+") diff --git a/src/wildmidi/common.h b/src/wildmidi/common.h new file mode 100644 index 000000000..44e90efdd --- /dev/null +++ b/src/wildmidi/common.h @@ -0,0 +1,94 @@ +/* + common.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __COMMON_H +#define __COMMON_H + +#define SAMPLE_16BIT 0x01 +#define SAMPLE_UNSIGNED 0x02 +#define SAMPLE_LOOP 0x04 +#define SAMPLE_PINGPONG 0x08 +#define SAMPLE_REVERSE 0x10 +#define SAMPLE_SUSTAIN 0x20 +#define SAMPLE_ENVELOPE 0x40 +#define SAMPLE_CLAMPED 0x80 + +#ifdef DEBUG_SAMPLES +#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) +#else +#define SAMPLE_CONVERT_DEBUG(dx) +#endif + +extern unsigned short int _WM_SampleRate; + +struct _sample { + unsigned long int data_length; + unsigned long int loop_start; + unsigned long int loop_end; + unsigned long int loop_size; + unsigned char loop_fraction; + unsigned short int rate; + unsigned long int freq_low; + unsigned long int freq_high; + unsigned long int freq_root; + unsigned char modes; + signed long int env_rate[7]; + signed long int env_target[7]; + unsigned long int inc_div; + signed short *data; + struct _sample *next; +}; + +struct _env { + float time; + float level; + unsigned char set; +}; + +struct _patch { + unsigned short patchid; + unsigned char loaded; + char *filename; + signed short int amp; + unsigned char keep; + unsigned char remove; + struct _env env[6]; + unsigned char note; + unsigned long int inuse_count; + struct _sample *first_sample; + struct _patch *next; +}; + +/* Set our global defines here */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +#endif /* __COMMON_H */ diff --git a/src/wildmidi/file_io.cpp b/src/wildmidi/file_io.cpp new file mode 100644 index 000000000..f14e22bbf --- /dev/null +++ b/src/wildmidi/file_io.cpp @@ -0,0 +1,71 @@ +/* +** file_io.cpp +** ZDoom compatible file IO interface for WildMIDI +** (This file was completely redone to remove the low level IO code references) +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "../files.h" +#include "wm_error.h" +#include "file_io.h" + +unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size) +{ + FileReader file; + + if (!file.Open(filename)) + { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + return NULL; + } + + long fsize = file.GetLength(); + + if (fsize > WM_MAXFILESIZE) + { + /* don't bother loading suspiciously long files */ + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0); + return NULL; + } + + unsigned char *data = (unsigned char*)malloc(fsize+1); + if (data == NULL) + { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + return NULL; + } + + file.Read(data, fsize); + data[fsize] = 0; + *size = fsize; + return data; +} diff --git a/src/wildmidi/file_io.h b/src/wildmidi/file_io.h new file mode 100644 index 000000000..d38caffbb --- /dev/null +++ b/src/wildmidi/file_io.h @@ -0,0 +1,33 @@ +/* + file_io.c + + file handling + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __FILE_IO_H +#define __FILE_IO_H + +#define WM_MAXFILESIZE 0x1fffffff +extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size); + +#endif /* __FILE_IO_H */ diff --git a/src/wildmidi/gus_pat.cpp b/src/wildmidi/gus_pat.cpp new file mode 100644 index 000000000..be3422db5 --- /dev/null +++ b/src/wildmidi/gus_pat.cpp @@ -0,0 +1,900 @@ +/* + gus_pat.c + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#include +#include +#include +#include + +#include "gus_pat.h" +#include "common.h" +#include "wm_error.h" +#include "file_io.h" + +#ifdef DEBUG_GUSPAT +#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx) + +#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy) +#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy) +#define GUSPAT_START_DEBUG() fprintf(stderr,"\r") +#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz) +#define GUSPAT_END_DEBUG() fprintf(stderr,"\n") +#else +#define GUSPAT_FILENAME_DEBUG(dx) +#define GUSPAT_INT_DEBUG(dx,dy) +#define GUSPAT_FLOAT_DEBUG(dx,dy) +#define GUSPAT_START_DEBUG() +#define GUSPAT_MODE_DEBUG(dx,dy,dz) +#define GUSPAT_END_DEBUG() +#endif + +/* + * sample data conversion functions + * convert data to signed shorts + */ + +/* 8bit signed */ +static int convert_8s(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data++) << 8; + } while (read_data != read_end); + return 0; + } + + _WM_ERROR_NEW("(%s:%i) ERROR: calloc failed (%s)", __FUNCTION__, __LINE__, + strerror(errno)); + return -1; +} + +/* 8bit signed ping pong */ +static int convert_8sp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data++) << 8; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b++ = (*read_data++) << 8; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed reverse */ +static int convert_8sr(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data-- = (*read_data++) << 8; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed reverse ping pong */ +static int convert_8srp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data--) << 8; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b++ = (*read_data--) << 8; + write_data_b++; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned */ +static int convert_8u(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned ping pong */ +static int convert_8up(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse */ +static int convert_8ur(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data-- = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse ping pong */ +static int convert_8urp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data--) ^ 0x80) << 8; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b++ = ((*read_data--) ^ 0x80) << 8; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed */ +static int convert_16s(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data++ |= (*read_data++) << 8; + } while (read_data < read_end); + + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed ping pong */ +static int convert_16sp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data++ |= (*read_data++) << 8; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = *(read_data++); + *write_data |= (*read_data++) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b = *(read_data++); + *write_data_b++ |= (*read_data++) << 8; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed reverse */ +static int convert_16sr(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data-- |= (*read_data++) << 8; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed reverse ping pong */ +static int convert_16srp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data--) << 8; + *write_data++ |= *read_data--; + } while (read_data < read_end); + + *write_data = (*read_data-- << 8); + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) << 8); + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = (*read_data--) << 8; + *write_data_b++ |= *read_data--; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned */ +static int convert_16u(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned ping pong */ +static int convert_16up(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b = (*read_data++); + *write_data_b++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse */ +static int convert_16ur(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data-- |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse ping pong */ +static int convert_16urp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data++ |= *read_data--; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = ((*read_data--) ^ 0x80) << 8; + *write_data_b++ |= *read_data--; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* sample loading */ + +struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { + unsigned char *gus_patch; + unsigned long int gus_size; + unsigned long int gus_ptr; + unsigned char no_of_samples; + struct _sample *gus_sample = NULL; + struct _sample *first_gus_sample = NULL; + unsigned long int i = 0; + + int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = { + convert_8s, + convert_16s, + convert_8u, + convert_16u, + convert_8sp, + convert_16sp, + convert_8up, + convert_16up, + convert_8sr, + convert_16sr, + convert_8ur, + convert_16ur, + convert_8srp, + convert_16srp, + convert_8urp, + convert_16urp + }; + unsigned long int tmp_loop; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename); + + if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) { + return NULL; + } + if (gus_size < 239) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) + && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (gus_patch[82] > 1) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (gus_patch[151] > 1) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + + GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]); + + no_of_samples = gus_patch[198]; + gus_ptr = 239; + while (no_of_samples) { + unsigned long int tmp_cnt; + if (first_gus_sample == NULL) { + first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample)); + gus_sample = first_gus_sample; + } else { + gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample)); + gus_sample = gus_sample->next; + } + if (gus_sample == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + + gus_sample->next = NULL; + gus_sample->loop_fraction = gus_patch[gus_ptr + 7]; + gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24) + | (gus_patch[gus_ptr + 10] << 16) + | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8]; + gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24) + | (gus_patch[gus_ptr + 14] << 16) + | (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12]; + gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24) + | (gus_patch[gus_ptr + 18] << 16) + | (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16]; + gus_sample->rate = (gus_patch[gus_ptr + 21] << 8) + | gus_patch[gus_ptr + 20]; + gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24) + | (gus_patch[gus_ptr + 24] << 16) + | (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]); + gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24) + | (gus_patch[gus_ptr + 28] << 16) + | (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]); + gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24) + | (gus_patch[gus_ptr + 32] << 16) + | (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]); + + /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */ + /* Result is 0.001% inacurate */ + gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2; + +#if 0 + /* We dont use this info at this time, kept in here for info */ + printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]); + printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]); +#endif + gus_sample->modes = gus_patch[gus_ptr + 55]; + GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG(); + + if (gus_sample->loop_start > gus_sample->loop_end) { + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->loop_start; + gus_sample->loop_start = tmp_loop; + gus_sample->loop_fraction = + ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + } + + /* + FIXME: Experimental Hacky Fix + */ + if (fix_release) { + if (env_time_table[gus_patch[gus_ptr + 40]] + < env_time_table[gus_patch[gus_ptr + 41]]) { + unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = tmp_hack_rate; + } + } + + for (i = 0; i < 6; i++) { + if (gus_sample->modes & SAMPLE_ENVELOPE) { + unsigned char env_rate = gus_patch[gus_ptr + 37 + i]; + gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i]; + GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]); + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[env_rate])); + GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate); + if (gus_sample->env_rate[i] == 0) { + _WM_ERROR_NEW("%s: Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.", + __FUNCTION__, i, filename, env_time_table[63]); + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); + } + } else { + gus_sample->env_target[i] = 4194303; + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); + } + } + + gus_sample->env_target[6] = 0; + gus_sample->env_rate[6] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + + gus_ptr += 96; + tmp_cnt = gus_sample->data_length; + + if (do_convert[(((gus_sample->modes & 0x18) >> 1) + | (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) + == -1) { + free(gus_patch); + return NULL; + } + + gus_ptr += tmp_cnt; + gus_sample->loop_start = (gus_sample->loop_start << 10) + | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); + gus_sample->loop_end = (gus_sample->loop_end << 10) + | (((gus_sample->loop_fraction & 0xf0) << 6) / 16); + gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start; + gus_sample->data_length = gus_sample->data_length << 10; + no_of_samples--; + } + free(gus_patch); + return first_gus_sample; +} diff --git a/src/wildmidi/gus_pat.h b/src/wildmidi/gus_pat.h new file mode 100644 index 000000000..084b8473a --- /dev/null +++ b/src/wildmidi/gus_pat.h @@ -0,0 +1,77 @@ +/* + gus_pat.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __GUS_PAT_H +#define __GUS_PAT_H + +/* Guspat Envelope Rate Timings */ + +static float env_time_table[] = { +/* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */ + 0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f, + 0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f, + 0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f, + 0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f, + 0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f, + 0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f, + 0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f, + 0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f, + +/* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */ + 0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f, + 0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f, + 0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f, + 0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f, + 0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f, + 0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f, + 0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f, + 0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f, + +/* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */ + 0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f, + 0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f, + 0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f, + 0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f, + 0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f, + 0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f, + 0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f, + 0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f, + +/* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */ + 0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f, + 5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f, + 2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f, + 1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f, + 1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f, + 1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f, + 0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f, + 0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f +}; + +extern struct _sample * _WM_load_gus_pat (const char *filename, int _fix_release); + +#endif /* __GUS_PAT_H */ + diff --git a/src/wildmidi/lock.cpp b/src/wildmidi/lock.cpp new file mode 100644 index 000000000..f8abfe926 --- /dev/null +++ b/src/wildmidi/lock.cpp @@ -0,0 +1,87 @@ +/* + lock.c - data locking code for lib + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#ifndef __DJGPP__ + +#ifdef _WIN32 +#include +#else +#define _GNU_SOURCE +#include +#endif + +#include "lock.h" +#include "common.h" + +/* + _WM_Lock(wmlock) + + wmlock = a pointer to a value + + returns nothing + + Attempts to set a lock on the MDI tree so that + only 1 library command may access it at any time. + If lock fails the process retries until successful. + */ +void _WM_Lock(int * wmlock) { + LOCK_START: + /* Check if lock is clear, if so set it */ + if (*wmlock == 0) { + (*wmlock)++; + /* Now that the lock is set, make sure we + * don't have a race condition. If so, + * decrement the lock by one and retry. */ + if (*wmlock == 1) { + return; /* Lock cleanly set */ + } + (*wmlock)--; + } +#ifdef _WIN32 + Sleep(10); +#else + usleep(500); +#endif + goto LOCK_START; +} + +/* + _WM_Unlock(wmlock) + + wmlock = a pointer to a value + + returns nothing + + Removes a lock previously placed on the MDI tree. + */ +void _WM_Unlock(int *wmlock) { + /* We don't want a -1 lock, so just to make sure */ + if ((*wmlock) != 0) { + (*wmlock)--; + } +} + +#endif /* __DJGPP__ */ diff --git a/src/wildmidi/lock.h b/src/wildmidi/lock.h new file mode 100644 index 000000000..6504bbecf --- /dev/null +++ b/src/wildmidi/lock.h @@ -0,0 +1,36 @@ +/* + lock.h - data locking code for lib + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __LOCK_H +#define __LOCK_H + +extern void _WM_Lock (int * wmlock); +extern void _WM_Unlock (int *wmlock); + +#ifdef __DJGPP__ +#define _WM_Lock(p) do {} while (0) +#define _WM_Unlock(p) do {} while (0) +#endif + +#endif /* __LOCK_H */ diff --git a/src/wildmidi/reverb.cpp b/src/wildmidi/reverb.cpp new file mode 100644 index 000000000..d183a1c71 --- /dev/null +++ b/src/wildmidi/reverb.cpp @@ -0,0 +1,398 @@ +/* + reverb.c + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#include +#include + +#include "common.h" +#include "reverb.h" + +/* + reverb function + */ +void _WM_reset_reverb(struct _rvb *rvb) { + int i, j, k; + for (i = 0; i < rvb->l_buf_size; i++) { + rvb->l_buf[i] = 0; + } + for (i = 0; i < rvb->r_buf_size; i++) { + rvb->r_buf[i] = 0; + } + for (k = 0; k < 8; k++) { + for (i = 0; i < 6; i++) { + for (j = 0; j < 2; j++) { + rvb->l_buf_flt_in[k][i][j] = 0; + rvb->l_buf_flt_out[k][i][j] = 0; + rvb->r_buf_flt_in[k][i][j] = 0; + rvb->r_buf_flt_out[k][i][j] = 0; + } + } + } +} + +/* + _WM_init_reverb + + ========================= + Engine Description + + 8 reflective points around the room + 2 speaker positions + 1 listener position + + Sounds come from the speakers to all points and to the listener. + Sound comes from the reflective points to the listener. + These sounds are combined, put through a filter that mimics surface absorbtion. + The combined sounds are also sent to the reflective points on the opposite side. + + */ +struct _rvb * +_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, + float listen_y) { + + /* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */ + double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0}; + + /* numbers calculated from + * 101.325 kPa, 20 deg C, 50% relative humidity */ + double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665}; + + /* modify these to adjust the absorption qualities of the surface. + * Remember that lower frequencies are less effected by surfaces + * Note: I am currently playing with the values and finding the ideal surfaces + * for nice default reverb. + */ + double dbAttn[8][6] = { + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942} + }; + /* + double dbAttn[6] = { + // concrete covered in carpet + // -0.175, -0.537, -1.412, -4.437, -7.959, -7.959 + // pleated drapes + -0.630, -3.223, -5.849, -12.041, -10.458, -7.959 + }; + */ + + /* distance */ + double SPL_DST[8] = {0.0}; + double SPR_DST[8] = {0.0}; + double RFN_DST[8] = {0.0}; + + double MAXL_DST = 0.0; + double MAXR_DST = 0.0; + + double SPL_LSN_XOFS = 0.0; + double SPL_LSN_YOFS = 0.0; + double SPL_LSN_DST = 0.0; + + double SPR_LSN_XOFS = 0.0; + double SPR_LSN_YOFS = 0.0; + double SPR_LSN_DST = 0.0; + + + struct _rvb *rtn_rvb = (struct _rvb*)malloc(sizeof(struct _rvb)); + int j = 0; + int i = 0; + + struct _coord { + double x; + double y; + }; + +#if 0 + struct _coord SPL = {2.5, 5.0}; /* Left Speaker Position */ + struct _coord SPR = {7.5, 5.0}; /* Right Speaker Position */ + /* position of the reflective points */ + struct _coord RFN[] = { + { 5.0, 0.0}, + { 0.0, 6.66666}, + { 0.0, 13.3333}, + { 5.0, 20.0}, + { 10.0, 20.0}, + { 15.0, 13.3333}, + { 15.0, 6.66666}, + { 10.0, 0.0} + }; +#else + struct _coord SPL; /* Left Speaker Position */ + struct _coord SPR; /* Right Speaker Position */ + /* position of the reflective points */ + struct _coord RFN[8]; + + SPL.x = room_x / 4.0; + SPR.x = room_x / 4.0 * 3.0; + SPL.y = room_y / 10.0; + SPR.y = room_y / 10.0; + + RFN[0].x = room_x / 3.0; + RFN[0].y = 0.0; + RFN[1].x = 0.0; + RFN[1].y = room_y / 3.0; + RFN[2].x = 0.0; + RFN[2].y = room_y / 3.0 * 2.0; + RFN[3].x = room_x / 3.0; + RFN[3].y = room_y; + RFN[4].x = room_x / 3.0 * 2.0; + RFN[4].y = room_y; + RFN[5].x = room_x; + RFN[5].y = room_y / 3.0 * 2.0; + RFN[6].x = room_x; + RFN[6].y = room_y / 3.0; + RFN[7].x = room_x / 3.0 * 2.0; + RFN[7].y = 0.0; +#endif + + SPL_LSN_XOFS = SPL.x - listen_x; + SPL_LSN_YOFS = SPL.y - listen_y; + SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS)); + + if (SPL_LSN_DST > MAXL_DST) + MAXL_DST = SPL_LSN_DST; + + SPR_LSN_XOFS = SPR.x - listen_x; + SPR_LSN_YOFS = SPR.y - listen_y; + SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS)); + + if (SPR_LSN_DST > MAXR_DST) + MAXR_DST = SPR_LSN_DST; + + if (rtn_rvb == NULL) { + return NULL; + } + + for (j = 0; j < 8; j++) { + double SPL_RFL_XOFS = 0; + double SPL_RFL_YOFS = 0; + double SPR_RFL_XOFS = 0; + double SPR_RFL_YOFS = 0; + double RFN_XOFS = listen_x - RFN[j].x; + double RFN_YOFS = listen_y - RFN[j].y; + RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS)); + + SPL_RFL_XOFS = SPL.x - RFN[i].x; + SPL_RFL_YOFS = SPL.y - RFN[i].y; + SPR_RFL_XOFS = SPR.x - RFN[i].x; + SPR_RFL_YOFS = SPR.y - RFN[i].y; + SPL_DST[i] = sqrt( + (SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS)); + SPR_DST[i] = sqrt( + (SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS)); + /* + add the 2 distances together and remove the speaker to listener distance + so we dont have to delay the initial output + */ + SPL_DST[i] += RFN_DST[i]; + + /* so i dont have to delay speaker output */ + SPL_DST[i] -= SPL_LSN_DST; + + if (i < 4) { + if (SPL_DST[i] > MAXL_DST) + MAXL_DST = SPL_DST[i]; + } else { + if (SPL_DST[i] > MAXR_DST) + MAXR_DST = SPL_DST[i]; + } + + SPR_DST[i] += RFN_DST[i]; + + /* so i dont have to delay speaker output */ + SPR_DST[i] -= SPR_LSN_DST; + + if (i < 4) { + if (SPR_DST[i] > MAXL_DST) + MAXL_DST = SPR_DST[i]; + } else { + if (SPR_DST[i] > MAXR_DST) + MAXR_DST = SPR_DST[i]; + } + + RFN_DST[j] *= 2.0; + + if (j < 4) { + if (RFN_DST[j] > MAXL_DST) + MAXL_DST = RFN_DST[j]; + } else { + if (RFN_DST[j] > MAXR_DST) + MAXR_DST = RFN_DST[j]; + } + + for (i = 0; i < 6; i++) { + double srate = (double) rate; + double bandwidth = 2.0; + double omega = 2.0 * M_PI * Freq[i] / srate; + double sn = sin(omega); + double cs = cos(omega); + double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn); + double A = pow(10.0, ((/*dbAttn[i]*/dbAttn[j][i] + + (dbAirAbs[i] * RFN_DST[j])) / 40.0) ); + /* + Peaking band EQ filter + */ + double b0 = 1 + (alpha * A); + double b1 = -2 * cs; + double b2 = 1 - (alpha * A); + double a0 = 1 + (alpha / A); + double a1 = -2 * cs; + double a2 = 1 - (alpha / A); + + rtn_rvb->coeff[j][i][0] = (signed long int) ((b0 / a0) * 1024.0); + rtn_rvb->coeff[j][i][1] = (signed long int) ((b1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][2] = (signed long int) ((b2 / a0) * 1024.0); + rtn_rvb->coeff[j][i][3] = (signed long int) ((a1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][4] = (signed long int) ((a2 / a0) * 1024.0); + } + } + + /* init the reverb buffers */ + rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29)); + rtn_rvb->l_buf = (long*)malloc( + sizeof(signed long int) * (rtn_rvb->l_buf_size + 1)); + rtn_rvb->l_out = 0; + + rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29)); + rtn_rvb->r_buf = (long*)malloc( + sizeof(signed long int) * (rtn_rvb->r_buf_size + 1)); + rtn_rvb->r_out = 0; + + for (i = 0; i < 4; i++) { + rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29)); + rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate + * (SPL_DST[i + 4] / 340.29)); + rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29)); + rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate + * (SPR_DST[i + 4] / 340.29)); + rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29)); + rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29)); + } + + rtn_rvb->gain = 4; + + _WM_reset_reverb(rtn_rvb); + return rtn_rvb; +} + +/* _WM_free_reverb - free up memory used for reverb */ +void _WM_free_reverb(struct _rvb *rvb) { + if (!rvb) return; + free(rvb->l_buf); + free(rvb->r_buf); + free(rvb); +} + +void _WM_do_reverb(struct _rvb *rvb, signed long int *buffer, int size) { + int i, j, k; + signed long int l_buf_flt = 0; + signed long int r_buf_flt = 0; + signed long int l_rfl = 0; + signed long int r_rfl = 0; + int vol_div = 64; + + for (i = 0; i < size; i += 2) { + signed long int tmp_l_val = 0; + signed long int tmp_r_val = 0; + /* + add the initial reflections + from each speaker, 4 to go the left, 4 go to the right buffers + */ + tmp_l_val = buffer[i] / vol_div; + tmp_r_val = buffer[i + 1] / vol_div; + for (j = 0; j < 4; j++) { + rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val; + rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size; + rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val; + rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size; + + rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val; + rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size; + rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val; + rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size; + } + + /* + filter the reverb output and add to buffer + */ + l_rfl = rvb->l_buf[rvb->l_out]; + rvb->l_buf[rvb->l_out] = 0; + rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size; + + r_rfl = rvb->r_buf[rvb->r_out]; + rvb->r_buf[rvb->r_out] = 0; + rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size; + + for (k = 0; k < 8; k++) { + for (j = 0; j < 6; j++) { + l_buf_flt = ((l_rfl * rvb->coeff[k][j][0]) + + (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + + (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) + - (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) + - (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) + / 1024; + rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0]; + rvb->l_buf_flt_in[k][j][0] = l_rfl; + rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0]; + rvb->l_buf_flt_out[k][j][0] = l_buf_flt; + buffer[i] += l_buf_flt / 8; + + r_buf_flt = ((r_rfl * rvb->coeff[k][j][0]) + + (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + + (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) + - (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) + - (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) + / 1024; + rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0]; + rvb->r_buf_flt_in[k][j][0] = r_rfl; + rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0]; + rvb->r_buf_flt_out[k][j][0] = r_buf_flt; + buffer[i + 1] += r_buf_flt / 8; + } + } + + /* + add filtered result back into the buffers but on the opposite side + */ + tmp_l_val = buffer[i + 1] / vol_div; + tmp_r_val = buffer[i] / vol_div; + for (j = 0; j < 4; j++) { + rvb->l_buf[rvb->l_in[j]] += tmp_l_val; + rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size; + + rvb->r_buf[rvb->r_in[j]] += tmp_r_val; + rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size; + } + } +} + diff --git a/src/wildmidi/reverb.h b/src/wildmidi/reverb.h new file mode 100644 index 000000000..b8f5a6333 --- /dev/null +++ b/src/wildmidi/reverb.h @@ -0,0 +1,57 @@ +/* + reverb.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __REVERB_H +#define __REVERB_H + +struct _rvb { + /* filter data */ + signed long int l_buf_flt_in[8][6][2]; + signed long int l_buf_flt_out[8][6][2]; + signed long int r_buf_flt_in[8][6][2]; + signed long int r_buf_flt_out[8][6][2]; + signed long int coeff[8][6][5]; + /* buffer data */ + signed long int *l_buf; + signed long int *r_buf; + int l_buf_size; + int r_buf_size; + int l_out; + int r_out; + int l_sp_in[8]; + int r_sp_in[8]; + int l_in[4]; + int r_in[4]; + int gain; + unsigned long int max_reverb_time; +}; + + extern void _WM_reset_reverb (struct _rvb *rvb); + extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y); + extern void _WM_free_reverb (struct _rvb *rvb); + extern void _WM_do_reverb (struct _rvb *rvb, signed long int *buffer, int size); + +#endif /* __REVERB_H */ diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp new file mode 100644 index 000000000..9ae3ad1be --- /dev/null +++ b/src/wildmidi/wildmidi_lib.cpp @@ -0,0 +1,4290 @@ +/* + wildmidi_lib.c + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2014 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#define UNUSED(x) (void)(x) + +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +/* +#ifdef _WIN32 +#include +#include +*/ +#undef strcasecmp +#define strcasecmp _stricmp +#undef strncasecmp +#define strncasecmp _strnicmp + + + +#include "common.h" +#include "wm_error.h" +#include "file_io.h" +#include "lock.h" +#include "reverb.h" +#include "gus_pat.h" +#include "wildmidi_lib.h" + +#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') +#ifdef _WIN32 +#define HAS_DRIVE_SPEC(f) ((f)[0] && ((f)[1] == ':')) +#else +#define HAS_DRIVE_SPEC(f) (0) +#endif +#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC((f))) + + +// Why is this shit even being used...? :( +#define __builtin_expect(a, b) a + +/* + * ========================= + * Global Data and Data Structs + * ========================= + */ + +#define MEM_CHUNK 8192 + +static int WM_Initialized = 0; +static signed short int WM_MasterVolume = 948; +static unsigned short int WM_MixerOptions = 0; + +static char WM_Version[] = "WildMidi Processing Library"; + +unsigned short int _WM_SampleRate; + +static struct _patch *patch[128]; + +static float reverb_room_width = 16.875f; +static float reverb_room_length = 22.5f; + +static float reverb_listen_posx = 8.4375f; +static float reverb_listen_posy = 16.875f; + +static int fix_release = 0; +static int auto_amp = 0; +static int auto_amp_with_amp = 0; + +static int patch_lock; + +struct _channel { + unsigned char bank; + struct _patch *patch; + unsigned char hold; + unsigned char volume; + unsigned char pressure; + unsigned char expression; + signed char balance; + signed char pan; + signed short int left_adjust; + signed short int right_adjust; + signed short int pitch; + signed short int pitch_range; + signed long int pitch_adjust; + unsigned short reg_data; + unsigned char reg_non; + unsigned char isdrum; +}; + +#define HOLD_OFF 0x02 + +struct _note { + unsigned short noteid; + unsigned char velocity; + struct _patch *patch; + struct _sample *sample; + unsigned long int sample_pos; + unsigned long int sample_inc; + signed long int env_inc; + unsigned char env; + signed long int env_level; + unsigned char modes; + unsigned char hold; + unsigned char active; + struct _note *replay; + struct _note *next; + unsigned long int vol_lvl; + unsigned char is_off; +}; + +struct _miditrack { + unsigned long int length; + unsigned long int ptr; + unsigned long int delta; + unsigned char running_event; + unsigned char EOT; +}; + +struct _mdi_patches { + struct _patch *patch; + struct _mdi_patch *next; +}; + +struct _event_data { + unsigned char channel; + unsigned long int data; +}; + +struct _mdi { + int lock; + unsigned long int samples_to_mix; + struct _event *events; + struct _event *current_event; + unsigned long int event_count; + unsigned long int events_size; /* try to stay optimally ahead to prevent reallocs */ + + unsigned short midi_master_vol; + struct _WM_Info info; + struct _WM_Info *tmp_info; + struct _channel channel[16]; + struct _note *note; + struct _note note_table[2][16][128]; + + struct _patch **patches; + unsigned long int patch_count; + signed short int amp; + + signed long int *mix_buffer; + unsigned long int mix_buffer_size; + + struct _rvb *reverb; +}; + +struct _event { + void (*do_event)(struct _mdi *mdi, struct _event_data *data); + struct _event_data event_data; + unsigned long int samples_to_next; + unsigned long int samples_to_next_fixed; +}; + +#define FPBITS 10 +#define FPMASK ((1L<> 1); + int j; + int sign; + double ck; + double x, x_inc, xz; + double z[35]; + double *gptr, *t; + + _WM_Lock(&gauss_lock); + if (gauss_table) { + _WM_Unlock(&gauss_lock); + return; + } + + newt_coeffs[0][0] = 1; + for (i = 0; i <= n; i++) { + newt_coeffs[i][0] = 1; + newt_coeffs[i][i] = 1; + + if (i > 1) { + newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i; + newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i; + } + + for (j = 1; j < i; j++) { + newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] + + newt_coeffs[i - 1][j]; + if (i > 1) + newt_coeffs[i][j] /= i; + } + z[i] = i / (4 * M_PI); + } + + for (i = 0; i <= n; i++) + for (j = 0, sign = (int)pow(-1., i); j <= i; j++, sign *= -1) + newt_coeffs[i][j] *= sign; + + t = (double*)malloc((1<event_count >= mdi->events_size) { + mdi->events_size += MEM_CHUNK; + mdi->events = (struct _event*)realloc(mdi->events, + (mdi->events_size * sizeof(struct _event))); + } +} + +static void WM_InitPatches(void) { + int i; + for (i = 0; i < 128; i++) { + patch[i] = NULL; + } +} + +static void WM_FreePatches(void) { + int i; + struct _patch * tmp_patch; + struct _sample * tmp_sample; + + _WM_Lock(&patch_lock); + for (i = 0; i < 128; i++) { + while (patch[i]) { + while (patch[i]->first_sample) { + tmp_sample = patch[i]->first_sample->next; + free(patch[i]->first_sample->data); + free(patch[i]->first_sample); + patch[i]->first_sample = tmp_sample; + } + free(patch[i]->filename); + tmp_patch = patch[i]->next; + free(patch[i]); + patch[i] = tmp_patch; + } + } + _WM_Unlock(&patch_lock); +} + +/* wm_strdup -- adds extra space for appending up to 4 chars */ +static char *wm_strdup (const char *str) { + size_t l = strlen(str) + 5; + char *d = (char *) malloc(l * sizeof(char)); + if (d) { + strcpy(d, str); + return d; + } + return NULL; +} + +static inline int wm_isdigit(int c) { + return (c >= '0' && c <= '9'); +} + +#define TOKEN_CNT_INC 8 +static char** WM_LC_Tokenize_Line(char *line_data) { + int line_length = strlen(line_data); + int token_data_length = 0; + int line_ofs = 0; + int token_start = 0; + char **token_data = NULL; + int token_count = 0; + + if (line_length == 0) + return NULL; + + do { + /* ignore everything after # */ + if (line_data[line_ofs] == '#') { + break; + } + + if ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t')) { + /* whitespace means we aren't in a token */ + if (token_start) { + token_start = 0; + line_data[line_ofs] = '\0'; + } + } else { + if (!token_start) { + /* the start of a token in the line */ + token_start = 1; + if (token_count >= token_data_length) { + token_data_length += TOKEN_CNT_INC; + token_data = (char**)realloc(token_data, token_data_length * sizeof(char *)); + if (token_data == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,"to parse config", errno); + return NULL; + } + } + + token_data[token_count] = &line_data[line_ofs]; + token_count++; + } + } + line_ofs++; + } while (line_ofs != line_length); + + /* if we have found some tokens then add a null token to the end */ + if (token_count) { + if (token_count >= token_data_length) { + token_data = (char**)realloc(token_data, + ((token_count + 1) * sizeof(char *))); + } + token_data[token_count] = NULL; + } + + return token_data; +} + +static int WM_LoadConfig(const char *config_file) { + unsigned long int config_size = 0; + char *config_buffer = NULL; + const char *dir_end = NULL; + char *config_dir = NULL; + unsigned long int config_ptr = 0; + unsigned long int line_start_ptr = 0; + unsigned short int patchid = 0; + struct _patch * tmp_patch; + char **line_tokens = NULL; + int token_count = 0; + + config_buffer = (char *) _WM_BufferFile(config_file, &config_size); + if (!config_buffer) { + WM_FreePatches(); + return -1; + } + + + // This part was rewritten because the original depended on a header that was GPL'd. + dir_end = strrchr(config_file, '/'); +#ifdef _WIN32 + const char *dir_end2 = strrchr(config_file, '\\'); + if (dir_end2 > dir_end) dir_end = dir_end2; +#endif + + if (dir_end) { + config_dir = (char*)malloc((dir_end - config_file + 2)); + if (config_dir == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", + errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free(config_buffer); + return -1; + } + strncpy(config_dir, config_file, (dir_end - config_file + 1)); + config_dir[dir_end - config_file + 1] = '\0'; + } + + config_ptr = 0; + line_start_ptr = 0; + + /* handle files without a newline at the end: this relies on + * _WM_BufferFile() allocating the buffer with one extra byte */ + config_buffer[config_size] = '\n'; + + while (config_ptr <= config_size) { + if (config_buffer[config_ptr] == '\r' || + config_buffer[config_ptr] == '\n') + { + config_buffer[config_ptr] = '\0'; + + if (config_ptr != line_start_ptr) { + line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]); + if (line_tokens) { + if (strcasecmp(line_tokens[0], "dir") == 0) { + free(config_dir); + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in dir line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!(config_dir = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } + if (!IS_DIR_SEPARATOR(config_dir[strlen(config_dir) - 1])) { + config_dir[strlen(config_dir) + 1] = '\0'; + config_dir[strlen(config_dir)] = '/'; + } + } else if (strcasecmp(line_tokens[0], "source") == 0) { + char *new_config = NULL; + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in source line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { + new_config = (char*)malloc( + strlen(config_dir) + strlen(line_tokens[1]) + + 1); + if (new_config == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + strcpy(new_config, config_dir); + strcpy(&new_config[strlen(config_dir)], line_tokens[1]); + } else { + if (!(new_config = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } + } + if (WM_LoadConfig(new_config) == -1) { + free(new_config); + free(line_tokens); + free(config_buffer); + free(config_dir); + return -1; + } + free(new_config); + } else if (strcasecmp(line_tokens[0], "bank") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in bank line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + patchid = (atoi(line_tokens[1]) & 0xFF) << 8; + } else if (strcasecmp(line_tokens[0], "drumset") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in drumset line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80; + } else if (strcasecmp(line_tokens[0], "reverb_room_width") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_room_width line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_room_width = (float) atof(line_tokens[1]); + if (reverb_room_width < 1.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_width < 1 meter, setting to minimum of 1 meter)", + 0); + reverb_room_width = 1.0f; + } else if (reverb_room_width > 100.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_width > 100 meters, setting to maximum of 100 meters)", + 0); + reverb_room_width = 100.0f; + } + } else if (strcasecmp(line_tokens[0], "reverb_room_length") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_room_length line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_room_length = (float) atof(line_tokens[1]); + if (reverb_room_length < 1.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_length < 1 meter, setting to minimum of 1 meter)", + 0); + reverb_room_length = 1.0f; + } else if (reverb_room_length > 100.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_length > 100 meters, setting to maximum of 100 meters)", + 0); + reverb_room_length = 100.0f; + } + } else if (strcasecmp(line_tokens[0], "reverb_listener_posx") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_listen_posx line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_listen_posx = (float) atof(line_tokens[1]); + if ((reverb_listen_posx > reverb_room_width) + || (reverb_listen_posx < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_listen_posx set outside of room)", + 0); + reverb_listen_posx = reverb_room_width / 2.0f; + } + } else if (strcasecmp(line_tokens[0], + "reverb_listener_posy") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_listen_posy line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_listen_posy = (float) atof(line_tokens[1]); + if ((reverb_listen_posy > reverb_room_width) + || (reverb_listen_posy < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_listen_posy set outside of room)", + 0); + reverb_listen_posy = reverb_room_length * 0.75f; + } + } else if (strcasecmp(line_tokens[0], + "guspat_editor_author_cant_read_so_fix_release_time_for_me") + == 0) { + fix_release = 1; + } else if (strcasecmp(line_tokens[0], "auto_amp") == 0) { + auto_amp = 1; + } else if (strcasecmp(line_tokens[0], "auto_amp_with_amp") + == 0) { + auto_amp = 1; + auto_amp_with_amp = 1; + } else if (wm_isdigit(line_tokens[0][0])) { + patchid = (patchid & 0xFF80) + | (atoi(line_tokens[0]) & 0x7F); + if (patch[(patchid & 0x7F)] == NULL) { + patch[(patchid & 0x7F)] = (struct _patch*)malloc( + sizeof(struct _patch)); + if (patch[(patchid & 0x7F)] == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = patch[(patchid & 0x7F)]; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = patch[(patchid & 0x7F)]; + if (tmp_patch->patchid == patchid) { + free(tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } else { + if (tmp_patch->next) { + while (tmp_patch->next) { + if (tmp_patch->next->patchid == patchid) + break; + tmp_patch = tmp_patch->next; + } + if (tmp_patch->next == NULL) { + if ((tmp_patch->next = (struct _patch*)malloc( + sizeof(struct _patch))) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_MEM, NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_LOAD, config_file, + 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = tmp_patch->next; + free(tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } + } else { + tmp_patch->next = (struct _patch*)malloc( + sizeof(struct _patch)); + if (tmp_patch->next == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_MEM, NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } + } + } + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in patch line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { + tmp_patch->filename = (char*)malloc( + strlen(config_dir) + strlen(line_tokens[1]) + + 5); + if (tmp_patch->filename == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + strcpy(tmp_patch->filename, config_dir); + strcat(tmp_patch->filename, line_tokens[1]); + } else { + if (!(tmp_patch->filename = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + } + if (strncasecmp( + &tmp_patch->filename[strlen(tmp_patch->filename) + - 4], ".pat", 4) != 0) { + strcat(tmp_patch->filename, ".pat"); + } + tmp_patch->env[0].set = 0x00; + tmp_patch->env[1].set = 0x00; + tmp_patch->env[2].set = 0x00; + tmp_patch->env[3].set = 0x00; + tmp_patch->env[4].set = 0x00; + tmp_patch->env[5].set = 0x00; + tmp_patch->keep = 0; + tmp_patch->remove = 0; + + token_count = 0; + while (line_tokens[token_count]) { + if (strncasecmp(line_tokens[token_count], "amp=", 4) + == 0) { + if (!wm_isdigit(line_tokens[token_count][4])) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + tmp_patch->amp = (atoi( + &line_tokens[token_count][4]) << 10) + / 100; + } + } else if (strncasecmp(line_tokens[token_count], + "note=", 5) == 0) { + if (!wm_isdigit(line_tokens[token_count][5])) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + tmp_patch->note = atoi( + &line_tokens[token_count][5]); + } + } else if (strncasecmp(line_tokens[token_count], + "env_time", 8) == 0) { + if ((!wm_isdigit(line_tokens[token_count][8])) + || (!wm_isdigit( + line_tokens[token_count][10])) + || (line_tokens[token_count][9] != '=')) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + unsigned int env_no = atoi( + &line_tokens[token_count][8]); + if (env_no > 5) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", + 0); + } else { + tmp_patch->env[env_no].time = + (float) atof( + &line_tokens[token_count][10]); + if ((tmp_patch->env[env_no].time + > 45000.0f) + || (tmp_patch->env[env_no].time + < 1.47f)) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(range error in patch line)", + 0); + tmp_patch->env[env_no].set &= 0xFE; + } else { + tmp_patch->env[env_no].set |= 0x01; + } + } + } + } else if (strncasecmp(line_tokens[token_count], + "env_level", 9) == 0) { + if ((!wm_isdigit(line_tokens[token_count][9])) + || (!wm_isdigit( + line_tokens[token_count][11])) + || (line_tokens[token_count][10] != '=')) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + unsigned int env_no = atoi( + &line_tokens[token_count][9]); + if (env_no > 5) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", + 0); + } else { + tmp_patch->env[env_no].level = + (float) atof( + &line_tokens[token_count][11]); + if ((tmp_patch->env[env_no].level > 1.0f) + || (tmp_patch->env[env_no].level + < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(range error in patch line)", + 0); + tmp_patch->env[env_no].set &= 0xFD; + } else { + tmp_patch->env[env_no].set |= 0x02; + } + } + } + } else if (strcasecmp(line_tokens[token_count], + "keep=loop") == 0) { + tmp_patch->keep |= SAMPLE_LOOP; + } else if (strcasecmp(line_tokens[token_count], + "keep=env") == 0) { + tmp_patch->keep |= SAMPLE_ENVELOPE; + } else if (strcasecmp(line_tokens[token_count], + "remove=sustain") == 0) { + tmp_patch->remove |= SAMPLE_SUSTAIN; + } else if (strcasecmp(line_tokens[token_count], + "remove=clamped") == 0) { + tmp_patch->remove |= SAMPLE_CLAMPED; + } + token_count++; + } + } + } + /* free up tokens */ + free(line_tokens); + } + line_start_ptr = config_ptr + 1; + } + config_ptr++; + } + + free(config_buffer); + free(config_dir); + + return 0; +} + +/* sample loading */ + +static int load_sample(struct _patch *sample_patch) { + struct _sample *guspat = NULL; + struct _sample *tmp_sample = NULL; + unsigned int i = 0; + + /* we only want to try loading the guspat once. */ + sample_patch->loaded = 1; + + if ((guspat = _WM_load_gus_pat(sample_patch->filename, fix_release)) == NULL) { + return -1; + } + + if (auto_amp) { + signed short int tmp_max = 0; + signed short int tmp_min = 0; + signed short samp_max = 0; + signed short samp_min = 0; + tmp_sample = guspat; + do { + samp_max = 0; + samp_min = 0; + for (i = 0; i < (tmp_sample->data_length >> 10); i++) { + if (tmp_sample->data[i] > samp_max) + samp_max = tmp_sample->data[i]; + if (tmp_sample->data[i] < samp_min) + samp_min = tmp_sample->data[i]; + + } + if (samp_max > tmp_max) + tmp_max = samp_max; + if (samp_min < tmp_min) + tmp_min = samp_min; + tmp_sample = tmp_sample->next; + } while (tmp_sample); + if (auto_amp_with_amp) { + if (tmp_max >= -tmp_min) { + sample_patch->amp = (sample_patch->amp + * ((32767 << 10) / tmp_max)) >> 10; + } else { + sample_patch->amp = (sample_patch->amp + * ((32768 << 10) / -tmp_min)) >> 10; + } + } else { + if (tmp_max >= -tmp_min) { + sample_patch->amp = (32767 << 10) / tmp_max; + } else { + sample_patch->amp = (32768 << 10) / -tmp_min; + } + } + } + + sample_patch->first_sample = guspat; + + if (sample_patch->patchid & 0x0080) { + if (!(sample_patch->keep & SAMPLE_LOOP)) { + do { + guspat->modes &= 0xFB; + guspat = guspat->next; + } while (guspat); + } + guspat = sample_patch->first_sample; + if (!(sample_patch->keep & SAMPLE_ENVELOPE)) { + do { + guspat->modes &= 0xBF; + guspat = guspat->next; + } while (guspat); + } + guspat = sample_patch->first_sample; + } + + if (sample_patch->patchid == 47) { + do { + if (!(guspat->modes & SAMPLE_LOOP)) { + for (i = 3; i < 6; i++) { + guspat->env_target[i] = guspat->env_target[2]; + guspat->env_rate[i] = guspat->env_rate[2]; + } + } + guspat = guspat->next; + } while (guspat); + guspat = sample_patch->first_sample; + } + + do { + if ((sample_patch->remove & SAMPLE_SUSTAIN) + && (guspat->modes & SAMPLE_SUSTAIN)) { + guspat->modes ^= SAMPLE_SUSTAIN; + } + if ((sample_patch->remove & SAMPLE_CLAMPED) + && (guspat->modes & SAMPLE_CLAMPED)) { + guspat->modes ^= SAMPLE_CLAMPED; + } + if (sample_patch->keep & SAMPLE_ENVELOPE) { + guspat->modes |= SAMPLE_ENVELOPE; + } + + for (i = 0; i < 6; i++) { + if (guspat->modes & SAMPLE_ENVELOPE) { + if (sample_patch->env[i].set & 0x02) { + guspat->env_target[i] = 16448 + * (signed long int) (255.0 + * sample_patch->env[i].level); + } + + if (sample_patch->env[i].set & 0x01) { + guspat->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate + * (sample_patch->env[i].time / 1000.0))); + } + } else { + guspat->env_target[i] = 4194303; + guspat->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + } + } + + guspat = guspat->next; + } while (guspat); + return 0; +} + +static struct _patch * +get_patch_data(struct _mdi *mdi, unsigned short patchid) { + struct _patch *search_patch; + + _WM_Lock(&patch_lock); + + search_patch = patch[patchid & 0x007F]; + + if (search_patch == NULL) { + _WM_Unlock(&patch_lock); + return NULL; + } + + while (search_patch) { + if (search_patch->patchid == patchid) { + _WM_Unlock(&patch_lock); + return search_patch; + } + search_patch = search_patch->next; + } + if ((patchid >> 8) != 0) { + _WM_Unlock(&patch_lock); + return (get_patch_data(mdi, patchid & 0x00FF)); + } + _WM_Unlock(&patch_lock); + return NULL; +} + +static void load_patch(struct _mdi *mdi, unsigned short patchid) { + unsigned int i; + struct _patch *tmp_patch = NULL; + + for (i = 0; i < mdi->patch_count; i++) { + if (mdi->patches[i]->patchid == patchid) { + return; + } + } + + tmp_patch = get_patch_data(mdi, patchid); + if (tmp_patch == NULL) { + return; + } + + _WM_Lock(&patch_lock); + if (!tmp_patch->loaded) { + if (load_sample(tmp_patch) == -1) { + _WM_Unlock(&patch_lock); + return; + } + } + + if (tmp_patch->first_sample == NULL) { + _WM_Unlock(&patch_lock); + return; + } + + mdi->patch_count++; + mdi->patches = (struct _patch**)realloc(mdi->patches, + (sizeof(struct _patch*) * mdi->patch_count)); + mdi->patches[mdi->patch_count - 1] = tmp_patch; + tmp_patch->inuse_count++; + _WM_Unlock(&patch_lock); +} + +static struct _sample * +get_sample_data(struct _patch *sample_patch, unsigned long int freq) { + struct _sample *last_sample = NULL; + struct _sample *return_sample = NULL; + + _WM_Lock(&patch_lock); + if (sample_patch == NULL) { + _WM_Unlock(&patch_lock); + return NULL; + } + if (sample_patch->first_sample == NULL) { + _WM_Unlock(&patch_lock); + return NULL; + } + if (freq == 0) { + _WM_Unlock(&patch_lock); + return sample_patch->first_sample; + } + + return_sample = sample_patch->first_sample; + last_sample = sample_patch->first_sample; + while (last_sample) { + if (freq > last_sample->freq_low) { + if (freq < last_sample->freq_high) { + _WM_Unlock(&patch_lock); + return last_sample; + } else { + return_sample = last_sample; + } + } + last_sample = last_sample->next; + } + _WM_Unlock(&patch_lock); + return return_sample; +} + +static void do_note_off_extra(struct _note *nte) { + + nte->is_off = 0; + + if (nte->hold) { + nte->hold |= HOLD_OFF; + } else { + if (!(nte->modes & SAMPLE_ENVELOPE)) { + if (nte->modes & SAMPLE_LOOP) { + nte->modes ^= SAMPLE_LOOP; + } + nte->env_inc = 0; + + } else if (nte->modes & SAMPLE_CLAMPED) { + if (nte->env < 5) { + nte->env = 5; + if (nte->env_level > nte->sample->env_target[5]) { + nte->env_inc = -nte->sample->env_rate[5]; + } else { + nte->env_inc = nte->sample->env_rate[5]; + } + } +#if 1 + } else if (nte->modes & SAMPLE_SUSTAIN) { + if (nte->env < 3) { + nte->env = 3; + if (nte->env_level > nte->sample->env_target[3]) { + nte->env_inc = -nte->sample->env_rate[3]; + } else { + nte->env_inc = nte->sample->env_rate[3]; + } + } +#endif + } else if (nte->env < 4) { + nte->env = 4; + if (nte->env_level > nte->sample->env_target[4]) { + nte->env_inc = -nte->sample->env_rate[4]; + } else { + nte->env_inc = nte->sample->env_rate[4]; + } + } + } +} + +static void do_note_off(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][(data->data >> 8)]; + if (!nte->active) + nte = &mdi->note_table[1][ch][(data->data >> 8)]; + if (!nte->active) { + return; + } + + if ((mdi->channel[ch].isdrum) && (!(nte->modes & SAMPLE_LOOP))) { + return; + } + + if (nte->env == 0) { + nte->is_off = 1; + } else { + do_note_off_extra(nte); + } +} + +static inline unsigned long int get_inc(struct _mdi *mdi, struct _note *nte) { + int ch = nte->noteid >> 8; + signed long int note_f; + unsigned long int freq; + + if (__builtin_expect((nte->patch->note != 0), 0)) { + note_f = nte->patch->note * 100; + } else { + note_f = (nte->noteid & 0x7f) * 100; + } + note_f += mdi->channel[ch].pitch_adjust; + if (__builtin_expect((note_f < 0), 0)) { + note_f = 0; + } else if (__builtin_expect((note_f > 12700), 0)) { + note_f = 12700; + } + freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); + return (((freq / ((_WM_SampleRate * 100) / 1024)) * 1024 + / nte->sample->inc_div)); +} + +static inline unsigned long int get_volume(struct _mdi *mdi, unsigned char ch, + struct _note *nte) { + signed long int volume; + + if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { + volume = (sqr_volume[mdi->channel[ch].volume] + * sqr_volume[mdi->channel[ch].expression] + * sqr_volume[nte->velocity]) / 1048576; + } else { + volume = (lin_volume[mdi->channel[ch].volume] + * lin_volume[mdi->channel[ch].expression] + * lin_volume[nte->velocity]) / 1048576; + } + + volume = volume * nte->patch->amp / 100; + return (volume); +} + +static void do_note_on(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + struct _note *prev_nte; + struct _note *nte_array; + unsigned long int freq = 0; + struct _patch *patch; + struct _sample *sample; + unsigned char ch = data->channel; + unsigned char note = (unsigned char)(data->data >> 8); + unsigned char velocity = (data->data & 0xFF); + + if (velocity == 0x00) { + do_note_off(mdi, data); + return; + } + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (!mdi->channel[ch].isdrum) { + patch = mdi->channel[ch].patch; + if (patch == NULL) { + return; + } + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } else { + patch = get_patch_data(mdi, + ((mdi->channel[ch].bank << 8) | note | 0x80)); + if (patch == NULL) { + return; + } + if (patch->note) { + freq = freq_table[(patch->note % 12) * 100] + >> (10 - (patch->note / 12)); + } else { + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } + } + + sample = get_sample_data(patch, (freq / 100)); + if (sample == NULL) { + return; + } + + nte = &mdi->note_table[0][ch][note]; + + if (nte->active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) + && (!(nte->hold & HOLD_OFF))) + return; + nte->replay = &mdi->note_table[1][ch][note]; + nte->env = 6; + nte->env_inc = -nte->sample->env_rate[6]; + nte = nte->replay; + } else { + if (mdi->note_table[1][ch][note].active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) + && (!(nte->hold & HOLD_OFF))) + return; + mdi->note_table[1][ch][note].replay = nte; + mdi->note_table[1][ch][note].env = 6; + mdi->note_table[1][ch][note].env_inc = + -mdi->note_table[1][ch][note].sample->env_rate[6]; + } else { + nte_array = mdi->note; + if (nte_array == NULL) { + mdi->note = nte; + } else { + do { + prev_nte = nte_array; + nte_array = nte_array->next; + } while (nte_array); + prev_nte->next = nte; + } + nte->active = 1; + nte->next = NULL; + } + } + nte->noteid = (ch << 8) | note; + nte->patch = patch; + nte->sample = sample; + nte->sample_pos = 0; + nte->sample_inc = get_inc(mdi, nte); + nte->velocity = velocity; + nte->env = 0; + nte->env_inc = nte->sample->env_rate[0]; + nte->env_level = 0; + nte->modes = sample->modes; + nte->hold = mdi->channel[ch].hold; + nte->vol_lvl = get_volume(mdi, ch, nte); + nte->replay = NULL; + nte->is_off = 0; +} + +static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][(data->data >> 8)]; + if (!nte->active) { + nte = &mdi->note_table[1][ch][(data->data >> 8)]; + if (!nte->active) { + return; + } + } + + nte->velocity = data->data & 0xff; + nte->vol_lvl = get_volume(mdi, ch, nte); + + if (nte->replay) { + nte->replay->velocity = data->data & 0xff; + nte->replay->vol_lvl = get_volume(mdi, ch, nte->replay); + } +} + +static void do_pan_adjust(struct _mdi *mdi, unsigned char ch) { + signed short int pan_adjust = mdi->channel[ch].balance + + mdi->channel[ch].pan; + signed short int left, right; + int amp = 32; + + if (pan_adjust > 63) { + pan_adjust = 63; + } else if (pan_adjust < -64) { + pan_adjust = -64; + } + + pan_adjust += 64; +/* if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) {*/ + left = (pan_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576; + right = (pan_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576; +/* } else { + left = (lin_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576; + right= (lin_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576; + }*/ + + mdi->channel[ch].left_adjust = left; + mdi->channel[ch].right_adjust = right; +} + +static void do_control_bank_select(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].bank = (unsigned char)data->data; +} + +static void do_control_data_entry_course(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + int data_tmp; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + data_tmp = mdi->channel[ch].pitch_range % 100; + mdi->channel[ch].pitch_range = short(data->data * 100 + data_tmp); + /* printf("Data Entry Course: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ + /* printf("Data Entry Course: data %li\n\r",data->data);*/ + } +} + +static void do_control_channel_volume(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].volume = (unsigned char)data->data; + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->vol_lvl = get_volume(mdi, ch, note_data); + if (note_data->replay) + note_data->replay->vol_lvl = get_volume(mdi, ch, + note_data->replay); + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_control_channel_balance(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + mdi->channel[ch].balance = (signed char)(data->data - 64); + do_pan_adjust(mdi, ch); +} + +static void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + + mdi->channel[ch].pan = signed char(data->data - 64); + do_pan_adjust(mdi, ch); +} + +static void do_control_channel_expression(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].expression = (unsigned char)data->data; + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->vol_lvl = get_volume(mdi, ch, note_data); + if (note_data->replay) + note_data->replay->vol_lvl = get_volume(mdi, ch, + note_data->replay); + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_control_data_entry_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + int data_tmp; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + data_tmp = mdi->channel[ch].pitch_range / 100; + mdi->channel[ch].pitch_range = short((data_tmp * 100) + data->data); + /* printf("Data Entry Fine: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ + /* printf("Data Entry Fine: data: %li\n\r", data->data);*/ + } + +} + +static void do_control_channel_hold(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (data->data > 63) { + mdi->channel[ch].hold = 1; + } else { + mdi->channel[ch].hold = 0; + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + if (note_data->hold & HOLD_OFF) { + if (note_data->modes & SAMPLE_ENVELOPE) { + if (note_data->modes & SAMPLE_CLAMPED) { + if (note_data->env < 5) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + } + } else if (note_data->env < 4) { + note_data->env = 4; + if (note_data->env_level + > note_data->sample->env_target[4]) { + note_data->env_inc = + -note_data->sample->env_rate[4]; + } else { + note_data->env_inc = + note_data->sample->env_rate[4]; + } + } + } else { + if (note_data->modes & SAMPLE_LOOP) { + note_data->modes ^= SAMPLE_LOOP; + } + note_data->env_inc = 0; + } + } + note_data->hold = 0x00; + } + note_data = note_data->next; + } while (note_data); + } + } +} + +static void do_control_data_increment(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + if (mdi->channel[ch].pitch_range < 0x3FFF) + mdi->channel[ch].pitch_range++; + } +} + +static void do_control_data_decrement(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + if (mdi->channel[ch].pitch_range > 0) + mdi->channel[ch].pitch_range--; + } +} +static void do_control_non_registered_param(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_non = 1; +} + +static void do_control_registered_param_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x3F80) + | data->data); + mdi->channel[ch].reg_non = 0; +} + +static void do_control_registered_param_course(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x7F) + | (data->data << 7)); + mdi->channel[ch].reg_non = 0; +} + +static void do_control_channel_sound_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->active = 0; + if (note_data->replay) { + note_data->replay = NULL; + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_control_channel_controllers_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].expression = 127; + mdi->channel[ch].pressure = 127; + mdi->channel[ch].volume = 100; + mdi->channel[ch].pan = 0; + mdi->channel[ch].balance = 0; + mdi->channel[ch].reg_data = 0xffff; + mdi->channel[ch].pitch_range = 200; + mdi->channel[ch].pitch = 0; + mdi->channel[ch].pitch_adjust = 0; + mdi->channel[ch].hold = 0; + do_pan_adjust(mdi, ch); + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->sample_inc = get_inc(mdi, note_data); + note_data->velocity = 0; + note_data->vol_lvl = get_volume(mdi, ch, note_data); + note_data->hold = 0; + + if (note_data->replay) { + note_data->replay->velocity = (unsigned char)data->data; + note_data->replay->vol_lvl = get_volume(mdi, ch, + note_data->replay); + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_control_channel_notes_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (mdi->channel[ch].isdrum) + return; + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + if (!note_data->hold) { + if (note_data->modes & SAMPLE_ENVELOPE) { + if (note_data->env < 5) { + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + note_data->env = 5; + } + } + } else { + note_data->hold |= HOLD_OFF; + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_patch(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (!mdi->channel[ch].isdrum) { + mdi->channel[ch].patch = get_patch_data(mdi, + (unsigned short)(((mdi->channel[ch].bank << 8) | data->data))); + } else { + mdi->channel[ch].bank = (unsigned char)data->data; + } +} + +static void do_channel_pressure(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->velocity = (unsigned char)data->data; + note_data->vol_lvl = get_volume(mdi, ch, note_data); + + if (note_data->replay) { + note_data->replay->velocity = (unsigned char)data->data; + note_data->replay->vol_lvl = get_volume(mdi, ch, + note_data->replay); + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_pitch(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + mdi->channel[ch].pitch = short(data->data - 0x2000); + + if (mdi->channel[ch].pitch < 0) { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range + * mdi->channel[ch].pitch / 8192; + } else { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range + * mdi->channel[ch].pitch / 8191; + } + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->sample_inc = get_inc(mdi, note_data); + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_sysex_roland_drum_track(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (data->data > 0) { + mdi->channel[ch].isdrum = 1; + mdi->channel[ch].patch = NULL; + } else { + mdi->channel[ch].isdrum = 0; + mdi->channel[ch].patch = get_patch_data(mdi, 0); + } +} + +static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { + int i; + for (i = 0; i < 16; i++) { + mdi->channel[i].bank = 0; + if (i != 9) { + mdi->channel[i].patch = get_patch_data(mdi, 0); + } else { + mdi->channel[i].patch = NULL; + } + mdi->channel[i].hold = 0; + mdi->channel[i].volume = 100; + mdi->channel[i].pressure = 127; + mdi->channel[i].expression = 127; + mdi->channel[i].balance = 0; + mdi->channel[i].pan = 0; + mdi->channel[i].left_adjust = 1; + mdi->channel[i].right_adjust = 1; + mdi->channel[i].pitch = 0; + mdi->channel[i].pitch_range = 200; + mdi->channel[i].reg_data = 0xFFFF; + mdi->channel[i].isdrum = 0; + do_pan_adjust(mdi, i); + } + mdi->channel[9].isdrum = 1; + UNUSED(data); /* NOOP, to please the compiler gods */ +} + +static void WM_ResetToStart(midi * handle) { + struct _mdi *mdi = (struct _mdi *) handle; + + mdi->current_event = mdi->events; + mdi->samples_to_mix = 0; + mdi->info.current_sample = 0; + + do_sysex_roland_reset(mdi, NULL); +} + +static int midi_setup_noteoff(struct _mdi *mdi, unsigned char channel, + unsigned char note, unsigned char velocity) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_note_off; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = (note << 8) + | velocity; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_note_off; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = (note << 8) | velocity; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + return 0; +} + +static int midi_setup_noteon(struct _mdi *mdi, unsigned char channel, + unsigned char note, unsigned char velocity) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_note_on; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = (note << 8) + | velocity; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_note_on; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = (note << 8) | velocity; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + + if (mdi->channel[channel].isdrum) + load_patch(mdi, ((mdi->channel[channel].bank << 8) | (note | 0x80))); + return 0; +} + +static int midi_setup_aftertouch(struct _mdi *mdi, unsigned char channel, + unsigned char note, unsigned char pressure) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_aftertouch; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = (note << 8) + | pressure; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_aftertouch; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = (note << 8) | pressure; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + return 0; +} + +static int midi_setup_control(struct _mdi *mdi, unsigned char channel, + unsigned char controller, unsigned char setting) { + void (*tmp_event)(struct _mdi *mdi, struct _event_data *data) = NULL; + + switch (controller) { + case 0: + tmp_event = *do_control_bank_select; + mdi->channel[channel].bank = setting; + break; + case 6: + tmp_event = *do_control_data_entry_course; + break; + case 7: + tmp_event = *do_control_channel_volume; + mdi->channel[channel].volume = setting; + break; + case 8: + tmp_event = *do_control_channel_balance; + break; + case 10: + tmp_event = *do_control_channel_pan; + break; + case 11: + tmp_event = *do_control_channel_expression; + break; + case 38: + tmp_event = *do_control_data_entry_fine; + break; + case 64: + tmp_event = *do_control_channel_hold; + break; + case 96: + tmp_event = *do_control_data_increment; + break; + case 97: + tmp_event = *do_control_data_decrement; + break; + case 98: + case 99: + tmp_event = *do_control_non_registered_param; + break; + case 100: + tmp_event = *do_control_registered_param_fine; + break; + case 101: + tmp_event = *do_control_registered_param_course; + break; + case 120: + tmp_event = *do_control_channel_sound_off; + break; + case 121: + tmp_event = *do_control_channel_controllers_off; + break; + case 123: + tmp_event = *do_control_channel_notes_off; + break; + default: + return 0; + } + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = tmp_event; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = setting; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = tmp_event; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = setting; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + return 0; +} + +static int midi_setup_patch(struct _mdi *mdi, unsigned char channel, + unsigned char patch) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_patch; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = patch; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_patch; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = patch; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + if (mdi->channel[channel].isdrum) { + mdi->channel[channel].bank = patch; + } else { + load_patch(mdi, ((mdi->channel[channel].bank << 8) | patch)); + mdi->channel[channel].patch = get_patch_data(mdi, + ((mdi->channel[channel].bank << 8) | patch)); + } + return 0; +} + +static int midi_setup_channel_pressure(struct _mdi *mdi, unsigned char channel, + unsigned char pressure) { + + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_channel_pressure; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = pressure; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_channel_pressure; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = pressure; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + + return 0; +} + +static int midi_setup_pitch(struct _mdi *mdi, unsigned char channel, + unsigned short pitch) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_pitch; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = pitch; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_pitch; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = pitch; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + return 0; +} + +static int midi_setup_sysex_roland_drum_track(struct _mdi *mdi, + unsigned char channel, unsigned short setting) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = + *do_sysex_roland_drum_track; + mdi->events[mdi->event_count - 1].event_data.channel = channel; + mdi->events[mdi->event_count - 1].event_data.data = setting; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_sysex_roland_drum_track; + mdi->events[mdi->event_count].event_data.channel = channel; + mdi->events[mdi->event_count].event_data.data = setting; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + + if (setting > 0) { + mdi->channel[channel].isdrum = 1; + } else { + mdi->channel[channel].isdrum = 0; + } + + return 0; +} + +static int midi_setup_sysex_roland_reset(struct _mdi *mdi) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].do_event = *do_sysex_roland_reset; + mdi->events[mdi->event_count - 1].event_data.channel = 0; + mdi->events[mdi->event_count - 1].event_data.data = 0; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = *do_sysex_roland_reset; + mdi->events[mdi->event_count].event_data.channel = 0; + mdi->events[mdi->event_count].event_data.data = 0; + mdi->events[mdi->event_count].samples_to_next = 0; + mdi->event_count++; + } + return 0; +} + +static int add_handle(void * handle) { + struct _hndl *tmp_handle = NULL; + + if (first_handle == NULL) { + first_handle = (struct _hndl*)malloc(sizeof(struct _hndl)); + if (first_handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); + return -1; + } + first_handle->handle = handle; + first_handle->prev = NULL; + first_handle->next = NULL; + } else { + tmp_handle = first_handle; + if (tmp_handle->next) { + while (tmp_handle->next) + tmp_handle = tmp_handle->next; + } + tmp_handle->next = (struct _hndl*)malloc(sizeof(struct _hndl)); + if (tmp_handle->next == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); + return -1; + } + tmp_handle->next->prev = tmp_handle; + tmp_handle = tmp_handle->next; + tmp_handle->next = NULL; + tmp_handle->handle = handle; + } + return 0; +} + +static struct _mdi * +Init_MDI(void) { + struct _mdi *mdi; + + mdi = (struct _mdi*)malloc(sizeof(struct _mdi)); + memset(mdi, 0, (sizeof(struct _mdi))); + + mdi->info.copyright = NULL; + mdi->info.mixer_options = WM_MixerOptions; + + load_patch(mdi, 0x0000); + + mdi->events_size = MEM_CHUNK; + mdi->events = (struct _event*)malloc(mdi->events_size * sizeof(struct _event)); + mdi->events[0].do_event = NULL; + mdi->events[0].event_data.channel = 0; + mdi->events[0].event_data.data = 0; + mdi->events[0].samples_to_next = 0; + mdi->event_count++; + + mdi->current_event = mdi->events; + mdi->samples_to_mix = 0; + mdi->info.current_sample = 0; + mdi->info.total_midi_time = 0; + mdi->info.approx_total_samples = 0; + + do_sysex_roland_reset(mdi, NULL); + + return mdi; +} + +static void freeMDI(struct _mdi *mdi) { + struct _sample *tmp_sample; + unsigned long int i; + + if (mdi->patch_count != 0) { + _WM_Lock(&patch_lock); + for (i = 0; i < mdi->patch_count; i++) { + mdi->patches[i]->inuse_count--; + if (mdi->patches[i]->inuse_count == 0) { + /* free samples here */ + while (mdi->patches[i]->first_sample) { + tmp_sample = mdi->patches[i]->first_sample->next; + free(mdi->patches[i]->first_sample->data); + free(mdi->patches[i]->first_sample); + mdi->patches[i]->first_sample = tmp_sample; + } + mdi->patches[i]->loaded = 0; + } + } + _WM_Unlock(&patch_lock); + free(mdi->patches); + } + + free(mdi->events); + free(mdi->tmp_info); + _WM_free_reverb(mdi->reverb); + free(mdi->mix_buffer); + free(mdi); +} + +static unsigned long int get_decay_samples(struct _patch *patch, unsigned char note) { + + struct _sample *sample = NULL; + unsigned long int freq = 0; + unsigned long int decay_samples = 0; + + if (patch == NULL) + return 0; + + /* first get the freq we need so we can check the right sample */ + if (patch->patchid & 0x80) { + /* is a drum patch */ + if (patch->note) { + freq = freq_table[(patch->note % 12) * 100] + >> (10 - (patch->note / 12)); + } else { + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } + } else { + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } + + /* get the sample */ + sample = get_sample_data(patch, (freq / 100)); + if (sample == NULL) + return 0; + + if (patch->patchid & 0x80) { + float sratedata = ((float) sample->rate / (float) _WM_SampleRate) + * (float) (sample->data_length >> 10); + decay_samples = (unsigned long int) sratedata; + /* printf("Drums (%i / %i) * %lu = %f\n", sample->rate, _WM_SampleRate, (sample->data_length >> 10), sratedata);*/ + } else if (sample->modes & SAMPLE_CLAMPED) { + decay_samples = (4194303 / sample->env_rate[5]); + /* printf("clamped 4194303 / %lu = %lu\n", sample->env_rate[5], decay_samples);*/ + } else { + decay_samples = + ((4194303 - sample->env_target[4]) / sample->env_rate[4]) + + (sample->env_target[4] / sample->env_rate[5]); + /* printf("NOT clamped ((4194303 - %lu) / %lu) + (%lu / %lu)) = %lu\n", sample->env_target[4], sample->env_rate[4], sample->env_target[4], sample->env_rate[5], decay_samples);*/ + } + return decay_samples; +} + +static struct _mdi * +WM_ParseNewMidi(unsigned char *midi_data, unsigned int midi_size) { + struct _mdi *mdi; + unsigned int tmp_val; + unsigned int midi_type; + unsigned int track_size; + unsigned char **tracks; + unsigned int end_of_tracks = 0; + unsigned int no_tracks; + unsigned int i; + unsigned int divisions = 96; + unsigned int tempo = 500000; + float samples_per_delta_f = 0.0; + float microseconds_per_pulse = 0.0; + float pulses_per_second = 0.0; + + unsigned long int sample_count = 0; + float sample_count_tmp = 0; + float sample_remainder = 0; + unsigned char *sysex_store = NULL; + unsigned long int sysex_store_len = 0; + + unsigned long int *track_delta; + unsigned char *track_end; + unsigned long int smallest_delta = 0; + unsigned long int subtract_delta = 0; + unsigned long int tmp_length = 0; + unsigned char current_event = 0; + unsigned char current_event_ch = 0; + unsigned char *running_event; + unsigned long int decay_samples = 0; + + if (memcmp(midi_data, "RIFF", 4) == 0) { + midi_data += 20; + midi_size -= 20; + } + if (memcmp(midi_data, "MThd", 4)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0); + return NULL; + } + midi_data += 4; + midi_size -= 4; + + if (midi_size < 10) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + return NULL; + } + + /* + * Get Midi Header Size - must always be 6 + */ + tmp_val = *midi_data++ << 24; + tmp_val |= *midi_data++ << 16; + tmp_val |= *midi_data++ << 8; + tmp_val |= *midi_data++; + midi_size -= 4; + if (tmp_val != 6) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0); + return NULL; + } + + /* + * Get Midi Format - we only support 0, 1 & 2 + */ + tmp_val = *midi_data++ << 8; + tmp_val |= *midi_data++; + midi_size -= 2; + if (tmp_val > 2) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); + return NULL; + } + midi_type = tmp_val; + + /* + * Get No. of Tracks + */ + tmp_val = *midi_data++ << 8; + tmp_val |= *midi_data++; + midi_size -= 2; + if (tmp_val < 1) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(no tracks)", 0); + return NULL; + } + no_tracks = tmp_val; + + /* + * Check that type 0 midi file has only 1 track + */ + if ((midi_type == 0) && (no_tracks > 1)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(expected 1 track for type 0 midi file, found more)", 0); + return NULL; + } + + /* + * Get Divisions + */ + divisions = *midi_data++ << 8; + divisions |= *midi_data++; + midi_size -= 2; + if (divisions & 0x00008000) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); + return NULL; + } + + if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { + float bpm_f = (float) (60000000 / tempo); + tempo = 60000000 / (unsigned long int) bpm_f; + } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { + float bpm_fr = (float) (60000000 / tempo) + 0.5f; + tempo = 60000000 / (unsigned long int) bpm_fr; + } + /* Slow but needed for accuracy */ + microseconds_per_pulse = (float) tempo / (float) divisions; + pulses_per_second = 1000000.0f / microseconds_per_pulse; + samples_per_delta_f = (float) _WM_SampleRate / pulses_per_second; + + mdi = Init_MDI(); + + tracks = (unsigned char**)malloc(sizeof(unsigned char *) * no_tracks); + track_delta = (unsigned long*)malloc(sizeof(unsigned long int) * no_tracks); + track_end = (unsigned char*)malloc(sizeof(unsigned char) * no_tracks); + running_event = (unsigned char*)malloc(sizeof(unsigned char) * no_tracks); + + for (i = 0; i < no_tracks; i++) { + if (midi_size < 8) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + goto _end; + } + if (memcmp(midi_data, "MTrk", 4) != 0) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing track header)", 0); + goto _end; + } + midi_data += 4; + midi_size -= 4; + + track_size = *midi_data++ << 24; + track_size |= *midi_data++ << 16; + track_size |= *midi_data++ << 8; + track_size |= *midi_data++; + midi_size -= 4; + if (midi_size < track_size) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + goto _end; + } + if ((midi_data[track_size - 3] != 0xFF) + || (midi_data[track_size - 2] != 0x2F) + || (midi_data[track_size - 1] != 0x00)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing EOT)", 0); + goto _end; + } + tracks[i] = midi_data; + midi_data += track_size; + midi_size -= track_size; + track_end[i] = 0; + running_event[i] = 0; + track_delta[i] = 0; + decay_samples = 0; + while (*tracks[i] > 0x7F) { + track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + } + track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + } + + /* + * Handle type 0 & 1 the same, but type 2 differently + */ + switch (midi_type) { + case 0: + case 1: + /* Type 0 & 1 can use the same code */ + while (end_of_tracks != no_tracks) { + smallest_delta = 0; + for (i = 0; i < no_tracks; i++) { + if (track_end[i]) + continue; + + if (track_delta[i]) { + track_delta[i] -= subtract_delta; + if (track_delta[i]) { + if ((!smallest_delta) + || (smallest_delta > track_delta[i])) { + smallest_delta = track_delta[i]; + } + continue; + } + } + do { + if (*tracks[i] > 0x7F) { + current_event = *tracks[i]; + tracks[i]++; + } else { + current_event = running_event[i]; + if (running_event[i] < 0x80) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); + goto _end; + } + } + current_event_ch = current_event & 0x0F; + switch (current_event >> 4) { + case 0x8: + NOTEOFF: midi_setup_noteoff(mdi, current_event_ch, + tracks[i][0], tracks[i][1]); + /* To better calculate samples needed after the end of midi, + * we calculate samples for decay for note off */ + { + unsigned long int tmp_decay_samples = 0; + struct _patch *tmp_patch = NULL; + if (mdi->channel[current_event_ch].isdrum) { + tmp_patch = get_patch_data(mdi, + ((mdi->channel[current_event_ch].bank << 8) + | tracks[i][0] | 0x80)); + /* if (tmp_patch == NULL) + printf("Drum patch not loaded 0x%02x on channel %i\n",((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80),current_event_ch);*/ + } else { + tmp_patch = mdi->channel[current_event_ch].patch; + /* if (tmp_patch == NULL) + printf("Channel %i patch not loaded\n", current_event_ch);*/ + } + tmp_decay_samples = get_decay_samples(tmp_patch, + tracks[i][0]); + /* if the note off decay is more than the decay we currently tracking then + * we set it to new decay. */ + if (tmp_decay_samples > decay_samples) { + decay_samples = tmp_decay_samples; + } + } + + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0x9: + if (tracks[i][1] == 0) { + goto NOTEOFF; + } + midi_setup_noteon(mdi, (current_event & 0x0F), tracks[i][0], + tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xA: + midi_setup_aftertouch(mdi, (current_event & 0x0F), + tracks[i][0], tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xB: + midi_setup_control(mdi, (current_event & 0x0F), + tracks[i][0], tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xC: + midi_setup_patch(mdi, (current_event & 0x0F), *tracks[i]); + tracks[i]++; + running_event[i] = current_event; + break; + case 0xD: + midi_setup_channel_pressure(mdi, (current_event & 0x0F), + *tracks[i]); + tracks[i]++; + running_event[i] = current_event; + break; + case 0xE: + midi_setup_pitch(mdi, (current_event & 0x0F), + ((tracks[i][1] << 7) | (tracks[i][0] & 0x7F))); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xF: /* Meta Event */ + if (current_event == 0xFF) { + if (tracks[i][0] == 0x02) { /* Copyright Event */ + /* Get Length */ + tmp_length = 0; + tracks[i]++; + while (*tracks[i] > 0x7f) { + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i]++; + } + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + /* Copy copyright info in the getinfo struct */ + if (mdi->info.copyright) { + mdi->info.copyright = (char*)realloc( + mdi->info.copyright, + (strlen(mdi->info.copyright) + 1 + + tmp_length + 1)); + strncpy( + &mdi->info.copyright[strlen( + mdi->info.copyright) + 1], + (char *) tracks[i], tmp_length); + mdi->info.copyright[strlen(mdi->info.copyright) + + 1 + tmp_length] = '\0'; + mdi->info.copyright[strlen(mdi->info.copyright)] = '\n'; + + } else { + mdi->info.copyright = (char*)malloc(tmp_length + 1); + strncpy(mdi->info.copyright, (char *) tracks[i], + tmp_length); + mdi->info.copyright[tmp_length] = '\0'; + } + tracks[i] += tmp_length + 1; + } else if ((tracks[i][0] == 0x2F) + && (tracks[i][1] == 0x00)) { + /* End of Track */ + end_of_tracks++; + track_end[i] = 1; + goto NEXT_TRACK; + } else if ((tracks[i][0] == 0x51) + && (tracks[i][1] == 0x03)) { + /* Tempo */ + tempo = (tracks[i][2] << 16) + (tracks[i][3] << 8) + + tracks[i][4]; + tracks[i] += 5; + if (!tempo) + tempo = 500000; + + if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { + float bpm_f = (float) (60000000 / tempo); + tempo = 60000000 + / (unsigned long int) bpm_f; + } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { + float bpm_fr = (float) (60000000 / tempo) + + 0.5f; + tempo = 60000000 + / (unsigned long int) bpm_fr; + } + /* Slow but needed for accuracy */ + microseconds_per_pulse = (float) tempo + / (float) divisions; + pulses_per_second = 1000000.0f + / microseconds_per_pulse; + samples_per_delta_f = (float) _WM_SampleRate + / pulses_per_second; + + } else { + tmp_length = 0; + tracks[i]++; + while (*tracks[i] > 0x7f) { + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i]++; + } + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i] += tmp_length + 1; + } + } else if ((current_event == 0xF0) + || (current_event == 0xF7)) { + /* Roland Sysex Events */ + unsigned long int sysex_len = 0; + while (*tracks[i] > 0x7F) { + sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + } + sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + + running_event[i] = 0; + + sysex_store = (unsigned char*)realloc(sysex_store, + sizeof(unsigned char) + * (sysex_store_len + sysex_len)); + memcpy(&sysex_store[sysex_store_len], tracks[i], + sysex_len); + sysex_store_len += sysex_len; + + if (sysex_store[sysex_store_len - 1] == 0xF7) { + unsigned char tmpsysexdata[] = { 0x41, 0x10, 0x42, 0x12 }; + if (memcmp(tmpsysexdata, sysex_store, 4) == 0) { + /* checksum */ + unsigned char sysex_cs = 0; + unsigned int sysex_ofs = 4; + do { + sysex_cs += sysex_store[sysex_ofs]; + if (sysex_cs > 0x7F) { + sysex_cs -= 0x80; + } + sysex_ofs++; + } while (sysex_store[sysex_ofs + 1] != 0xF7); + sysex_cs = 128 - sysex_cs; + /* is roland sysex message valid */ + if (sysex_cs == sysex_store[sysex_ofs]) { + /* process roland sysex event */ + if (sysex_store[4] == 0x40) { + if (((sysex_store[5] & 0xF0) == 0x10) + && (sysex_store[6] == 0x15)) { + /* Roland Drum Track Setting */ + unsigned char sysex_ch = 0x0F + & sysex_store[5]; + if (sysex_ch == 0x00) { + sysex_ch = 0x09; + } else if (sysex_ch <= 0x09) { + sysex_ch -= 1; + } + midi_setup_sysex_roland_drum_track( + mdi, sysex_ch, + sysex_store[7]); + } else if ((sysex_store[5] == 0x00) + && (sysex_store[6] == 0x7F) + && (sysex_store[7] == 0x00)) { + /* Roland GS Reset */ + midi_setup_sysex_roland_reset(mdi); + } + } + } + } + free(sysex_store); + sysex_store = NULL; + sysex_store_len = 0; + } + tracks[i] += sysex_len; + } else { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta event)", 0); + goto _end; + } + break; + default: + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized event)", 0); + goto _end; + } + while (*tracks[i] > 0x7F) { + track_delta[i] = (track_delta[i] << 7) + + (*tracks[i] & 0x7F); + tracks[i]++; + } + track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + } while (!track_delta[i]); + if ((!smallest_delta) || (smallest_delta > track_delta[i])) { + smallest_delta = track_delta[i]; + } + NEXT_TRACK: continue; + } + + subtract_delta = smallest_delta; + sample_count_tmp = (((float) smallest_delta * samples_per_delta_f) + + sample_remainder); + sample_count = (unsigned long int) sample_count_tmp; + sample_remainder = sample_count_tmp - (float) sample_count; + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].samples_to_next += sample_count; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = NULL; + mdi->events[mdi->event_count].event_data.channel = 0; + mdi->events[mdi->event_count].event_data.data = 0; + mdi->events[mdi->event_count].samples_to_next = sample_count; + mdi->event_count++; + } + mdi->info.approx_total_samples += sample_count; + /* printf("Decay Samples = %lu\n",decay_samples);*/ + if (decay_samples > sample_count) { + decay_samples -= sample_count; + } else { + decay_samples = 0; + } + } + break; + + case 2: /* Type 2 has to be handled differently */ + for (i = 0; i < no_tracks; i++) { + sample_remainder = 0.0; + decay_samples = 0; + track_delta[i] = 0; + do { + if(track_delta[i]) { + sample_count_tmp = (((float) track_delta[i] * samples_per_delta_f) + + sample_remainder); + sample_count = (unsigned long int) sample_count_tmp; + sample_remainder = sample_count_tmp - (float) sample_count; + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].samples_to_next += sample_count; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = NULL; + mdi->events[mdi->event_count].event_data.channel = 0; + mdi->events[mdi->event_count].event_data.data = 0; + mdi->events[mdi->event_count].samples_to_next = sample_count; + mdi->event_count++; + } + mdi->info.approx_total_samples += sample_count; + /* printf("Decay Samples = %lu\n",decay_samples);*/ + if (decay_samples > sample_count) { + decay_samples -= sample_count; + } else { + decay_samples = 0; + } + } + if (*tracks[i] > 0x7F) { + current_event = *tracks[i]; + tracks[i]++; + } else { + current_event = running_event[i]; + if (running_event[i] < 0x80) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); + goto _end; + } + } + current_event_ch = current_event & 0x0F; + switch (current_event >> 4) { + case 0x8: + NOTEOFF2: midi_setup_noteoff(mdi, current_event_ch, + tracks[i][0], tracks[i][1]); + /* To better calculate samples needed after the end of midi, + * we calculate samples for decay for note off */ + { + unsigned long int tmp_decay_samples = 0; + struct _patch *tmp_patch = NULL; + + if (mdi->channel[current_event_ch].isdrum) { + tmp_patch = get_patch_data(mdi, + ((mdi->channel[current_event_ch].bank << 8) + | tracks[i][0] | 0x80)); + /* if (tmp_patch == NULL) + printf("Drum patch not loaded 0x%02x on channel %i\n",((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80),current_event_ch);*/ + } else { + tmp_patch = mdi->channel[current_event_ch].patch; + /* if (tmp_patch == NULL) + printf("Channel %i patch not loaded\n", current_event_ch);*/ + } + tmp_decay_samples = get_decay_samples(tmp_patch, + tracks[i][0]); + /* if the note off decay is more than the decay we currently tracking then + * we set it to new decay. */ + if (tmp_decay_samples > decay_samples) { + decay_samples = tmp_decay_samples; + } + } + + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0x9: + if (tracks[i][1] == 0) { + goto NOTEOFF2; + } + midi_setup_noteon(mdi, (current_event & 0x0F), tracks[i][0], + tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xA: + midi_setup_aftertouch(mdi, (current_event & 0x0F), + tracks[i][0], tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xB: + midi_setup_control(mdi, (current_event & 0x0F), + tracks[i][0], tracks[i][1]); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xC: + midi_setup_patch(mdi, (current_event & 0x0F), *tracks[i]); + tracks[i]++; + running_event[i] = current_event; + break; + case 0xD: + midi_setup_channel_pressure(mdi, (current_event & 0x0F), + *tracks[i]); + tracks[i]++; + running_event[i] = current_event; + break; + case 0xE: + midi_setup_pitch(mdi, (current_event & 0x0F), + ((tracks[i][1] << 7) | (tracks[i][0] & 0x7F))); + tracks[i] += 2; + running_event[i] = current_event; + break; + case 0xF: /* Meta Event */ + if (current_event == 0xFF) { + if (tracks[i][0] == 0x02) { /* Copyright Event */ + /* Get Length */ + tmp_length = 0; + tracks[i]++; + while (*tracks[i] > 0x7f) { + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i]++; + } + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + /* Copy copyright info in the getinfo struct */ + if (mdi->info.copyright) { + mdi->info.copyright = (char*)realloc( + mdi->info.copyright, + (strlen(mdi->info.copyright) + 1 + + tmp_length + 1)); + strncpy( + &mdi->info.copyright[strlen( + mdi->info.copyright) + 1], + (char *) tracks[i], tmp_length); + mdi->info.copyright[strlen(mdi->info.copyright) + + 1 + tmp_length] = '\0'; + mdi->info.copyright[strlen(mdi->info.copyright)] = '\n'; + + } else { + mdi->info.copyright = (char*)malloc(tmp_length + 1); + strncpy(mdi->info.copyright, (char *) tracks[i], + tmp_length); + mdi->info.copyright[tmp_length] = '\0'; + } + tracks[i] += tmp_length + 1; + } else if ((tracks[i][0] == 0x2F) + && (tracks[i][1] == 0x00)) { + /* End of Track */ + end_of_tracks++; + track_end[i] = 1; + goto NEXT_TRACK2; + } else if ((tracks[i][0] == 0x51) + && (tracks[i][1] == 0x03)) { + /* Tempo */ + tempo = (tracks[i][2] << 16) + (tracks[i][3] << 8) + + tracks[i][4]; + tracks[i] += 5; + if (!tempo) + tempo = 500000; + + if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { + float bpm_f = (float) (60000000 / tempo); + tempo = 60000000 + / (unsigned long int) bpm_f; + } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { + float bpm_fr = (float) (60000000 / tempo) + + 0.5f; + tempo = 60000000 + / (unsigned long int) bpm_fr; + } + /* Slow but needed for accuracy */ + microseconds_per_pulse = (float) tempo + / (float) divisions; + pulses_per_second = 1000000.0f + / microseconds_per_pulse; + samples_per_delta_f = (float) _WM_SampleRate + / pulses_per_second; + + } else { + tmp_length = 0; + tracks[i]++; + while (*tracks[i] > 0x7f) { + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i]++; + } + tmp_length = (tmp_length << 7) + + (*tracks[i] & 0x7f); + tracks[i] += tmp_length + 1; + } + } else if ((current_event == 0xF0) + || (current_event == 0xF7)) { + /* Roland Sysex Events */ + unsigned long int sysex_len = 0; + while (*tracks[i] > 0x7F) { + sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + } + sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + + running_event[i] = 0; + + sysex_store = (unsigned char*)realloc(sysex_store, + sizeof(unsigned char) + * (sysex_store_len + sysex_len)); + memcpy(&sysex_store[sysex_store_len], tracks[i], + sysex_len); + sysex_store_len += sysex_len; + + if (sysex_store[sysex_store_len - 1] == 0xF7) { + unsigned char tmpsysexdata[] = { 0x41, 0x10, 0x42, 0x12 }; + if (memcmp(tmpsysexdata, sysex_store, 4) == 0) { + /* checksum */ + unsigned char sysex_cs = 0; + unsigned int sysex_ofs = 4; + do { + sysex_cs += sysex_store[sysex_ofs]; + if (sysex_cs > 0x7F) { + sysex_cs -= 0x80; + } + sysex_ofs++; + } while (sysex_store[sysex_ofs + 1] != 0xF7); + sysex_cs = 128 - sysex_cs; + /* is roland sysex message valid */ + if (sysex_cs == sysex_store[sysex_ofs]) { + /* process roland sysex event */ + if (sysex_store[4] == 0x40) { + if (((sysex_store[5] & 0xF0) == 0x10) + && (sysex_store[6] == 0x15)) { + /* Roland Drum Track Setting */ + unsigned char sysex_ch = 0x0F + & sysex_store[5]; + if (sysex_ch == 0x00) { + sysex_ch = 0x09; + } else if (sysex_ch <= 0x09) { + sysex_ch -= 1; + } + midi_setup_sysex_roland_drum_track( + mdi, sysex_ch, + sysex_store[7]); + } else if ((sysex_store[5] == 0x00) + && (sysex_store[6] == 0x7F) + && (sysex_store[7] == 0x00)) { + /* Roland GS Reset */ + midi_setup_sysex_roland_reset(mdi); + } + } + } + } + free(sysex_store); + sysex_store = NULL; + sysex_store_len = 0; + } + tracks[i] += sysex_len; + } else { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta event)", 0); + goto _end; + } + break; + default: + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized event)", 0); + goto _end; + } + track_delta[i] = 0; + while (*tracks[i] > 0x7F) { + track_delta[i] = (track_delta[i] << 7) + + (*tracks[i] & 0x7F); + tracks[i]++; + } + track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); + tracks[i]++; + NEXT_TRACK2: + smallest_delta = track_delta[i]; /* Added just to keep Xcode happy */ + UNUSED(smallest_delta); /* Added to just keep clang happy */ + } while (track_end[i] == 0); + /* + * Add decay at the end of each song + */ + if (decay_samples) { + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->events[mdi->event_count - 1].samples_to_next += decay_samples; + } else { + WM_CheckEventMemoryPool(mdi); + mdi->events[mdi->event_count].do_event = NULL; + mdi->events[mdi->event_count].event_data.channel = 0; + mdi->events[mdi->event_count].event_data.data = 0; + mdi->events[mdi->event_count].samples_to_next = decay_samples; + mdi->event_count++; + } + } + } + break; + + default: break; /* Don't expect to get here, added for completeness */ + } + + if ((mdi->event_count) + && (mdi->events[mdi->event_count - 1].do_event == NULL)) { + mdi->info.approx_total_samples -= + mdi->events[mdi->event_count - 1].samples_to_next; + mdi->event_count--; + } + /* Set total MIDI time to 1/1000's seconds */ + mdi->info.total_midi_time = (mdi->info.approx_total_samples * 1000) + / _WM_SampleRate; + /*mdi->info.approx_total_samples += _WM_SampleRate * 3;*/ + + /* Add additional samples needed for decay */ + mdi->info.approx_total_samples += decay_samples; + /*printf("decay_samples = %lu\n",decay_samples);*/ + + if ((mdi->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, + reverb_room_length, reverb_listen_posx, reverb_listen_posy)) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); + goto _end; + } + + mdi->info.current_sample = 0; + mdi->current_event = &mdi->events[0]; + mdi->samples_to_mix = 0; + mdi->note = NULL; + + WM_ResetToStart(mdi); + +_end: free(sysex_store); + free(track_end); + free(track_delta); + free(running_event); + free(tracks); + if (mdi->reverb) return mdi; + freeMDI(mdi); + return NULL; +} + +static int WM_GetOutput_Linear(midi * handle, char * buffer, + unsigned long int size) { + unsigned long int buffer_used = 0; + unsigned long int i; + struct _mdi *mdi = (struct _mdi *) handle; + unsigned long int real_samples_to_mix = 0; + unsigned long int data_pos; + signed long int premix, left_mix, right_mix; + signed long int vol_mul; + struct _note *note_data = NULL; + unsigned long int count; + struct _event *event = mdi->current_event; + signed long int *tmp_buffer; + signed long int *out_buffer; + + _WM_Lock(&mdi->lock); + + buffer_used = 0; + memset(buffer, 0, size); + + if ( (size / 2) > mdi->mix_buffer_size) { + if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { + mdi->mix_buffer_size += MEM_CHUNK; + } else { + mdi->mix_buffer_size = size / 2; + } + mdi->mix_buffer = (long*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed long int)); + } + + tmp_buffer = mdi->mix_buffer; + + memset(tmp_buffer, 0, ((size / 2) * sizeof(signed long int))); + out_buffer = tmp_buffer; + + do { + if (__builtin_expect((!mdi->samples_to_mix), 0)) { + while ((!mdi->samples_to_mix) && (event->do_event)) { + event->do_event(mdi, &event->event_data); + event++; + mdi->samples_to_mix = event->samples_to_next; + mdi->current_event = event; + } + + if (!mdi->samples_to_mix) { + if (mdi->info.current_sample + >= mdi->info.approx_total_samples) { + break; + } else if ((mdi->info.approx_total_samples + - mdi->info.current_sample) > (size >> 2)) { + mdi->samples_to_mix = size >> 2; + } else { + mdi->samples_to_mix = mdi->info.approx_total_samples + - mdi->info.current_sample; + } + } + } + if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { + real_samples_to_mix = size >> 2; + } else { + real_samples_to_mix = mdi->samples_to_mix; + if (real_samples_to_mix == 0) { + continue; + } + } + + /* do mixing here */ + count = real_samples_to_mix; + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((note_data != NULL), 1)) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + vol_mul = ((note_data->vol_lvl + * (note_data->env_level >> 12)) >> FPBITS); + + premix = (note_data->sample->data[data_pos] + + ((note_data->sample->data[data_pos + 1] + - note_data->sample->data[data_pos]) + * (signed long int) (note_data->sample_pos + & FPMASK)>> FPBITS)) * vol_mul + / 1024; + + left_mix += premix + * mdi->channel[note_data->noteid >> 8].left_adjust; + right_mix += premix + * mdi->channel[note_data->noteid >> 8].right_adjust; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (__builtin_expect( + (note_data->sample_pos > note_data->sample->loop_end), + 0)) { + if (note_data->modes & SAMPLE_LOOP) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } else if (__builtin_expect( + (note_data->sample_pos + >= note_data->sample->data_length), + 0)) { + if (__builtin_expect((note_data->replay == NULL), 1)) { + goto KILL_NOTE; + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect((note_data->env_inc == 0), 0)) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (__builtin_expect((note_data->env_level > 4194304), 0)) { + note_data->env_level = + note_data->sample->env_target[note_data->env]; + } + if (__builtin_expect( + ((note_data->env_inc < 0) + && (note_data->env_level + > note_data->sample->env_target[note_data->env])) + || ((note_data->env_inc > 0) + && (note_data->env_level + < note_data->sample->env_target[note_data->env])), + 1)) { + note_data = note_data->next; + continue; + } + + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: +#if 0 + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } +#endif + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (__builtin_expect((note_data->env_level == 0), 1)) { + goto KILL_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + if (__builtin_expect((note_data->replay != NULL), 1)) { + RESTART_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + KILL_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + left_mix /= 1024; + right_mix /= 1024; + } + + *tmp_buffer++ = left_mix; + *tmp_buffer++ = right_mix; + } while (--count); + + buffer_used += real_samples_to_mix * 4; + size -= (real_samples_to_mix << 2); + mdi->info.current_sample += real_samples_to_mix; + mdi->samples_to_mix -= real_samples_to_mix; + } while (size); + + tmp_buffer = out_buffer; + + if (mdi->info.mixer_options & WM_MO_REVERB) { + _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); + } + + for (i = 0; i < buffer_used; i += 4) { + left_mix = *tmp_buffer++; + right_mix = *tmp_buffer++; + + if (left_mix > 32767) { + left_mix = 32767; + } else if (left_mix < -32768) { + left_mix = -32768; + } + + if (right_mix > 32767) { + right_mix = 32767; + } else if (right_mix < -32768) { + right_mix = -32768; + } + + /* + * =================== + * Write to the buffer + * =================== + */ + (*buffer++) = left_mix & 0xff; + (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); + (*buffer++) = right_mix & 0xff; + (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); + } + + _WM_Unlock(&mdi->lock); + return buffer_used; +} + +static int WM_GetOutput_Gauss(midi * handle, char * buffer, + unsigned long int size) { + unsigned long int buffer_used = 0; + unsigned long int i; + struct _mdi *mdi = (struct _mdi *) handle; + unsigned long int real_samples_to_mix = 0; + unsigned long int data_pos; + signed long int premix, left_mix, right_mix; + signed long int vol_mul; + struct _note *note_data = NULL; + unsigned long int count; + signed short int *sptr; + double y, xd; + double *gptr, *gend; + int left, right, temp_n; + int ii, jj; + struct _event *event = mdi->current_event; + signed long int *tmp_buffer; + signed long int *out_buffer; + + _WM_Lock(&mdi->lock); + + buffer_used = 0; + memset(buffer, 0, size); + if ( (size / 2) > mdi->mix_buffer_size) { + if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { + mdi->mix_buffer_size += MEM_CHUNK; + } else { + mdi->mix_buffer_size = size / 2; + } + mdi->mix_buffer = (long*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed long int)); + } + tmp_buffer = mdi->mix_buffer; + memset(tmp_buffer, 0, ((size / 2) * sizeof(signed long int))); + out_buffer = tmp_buffer; + + do { + if (__builtin_expect((!mdi->samples_to_mix), 0)) { + while ((!mdi->samples_to_mix) && (event->do_event)) { + event->do_event(mdi, &event->event_data); + event++; + mdi->samples_to_mix = event->samples_to_next; + mdi->current_event = event; + } + + if (!mdi->samples_to_mix) { + if (mdi->info.current_sample + >= mdi->info.approx_total_samples) { + break; + } else if ((mdi->info.approx_total_samples + - mdi->info.current_sample) > (size >> 2)) { + mdi->samples_to_mix = size >> 2; + } else { + mdi->samples_to_mix = mdi->info.approx_total_samples + - mdi->info.current_sample; + } + } + } + if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { + real_samples_to_mix = size >> 2; + } else { + real_samples_to_mix = mdi->samples_to_mix; + if (real_samples_to_mix == 0) { + continue; + } + } + + /* do mixing here */ + count = real_samples_to_mix; + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((note_data != NULL), 1)) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + vol_mul = ((note_data->vol_lvl + * (note_data->env_level >> 12)) >> FPBITS); + + /* check to see if we're near one of the ends */ + left = data_pos; + right = (note_data->sample->data_length >> FPBITS) - left + - 1; + temp_n = (right << 1) - 1; + if (temp_n <= 0) + temp_n = 1; + if (temp_n > (left << 1) + 1) + temp_n = (left << 1) + 1; + + /* use Newton if we can't fill the window */ + if (temp_n < gauss_n) { + xd = note_data->sample_pos & FPMASK; + xd /= (1L << FPBITS); + xd += temp_n >> 1; + y = 0; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (temp_n >> 1); + for (ii = temp_n; ii;) { + for (jj = 0; jj <= ii; jj++) + y += sptr[jj] * newt_coeffs[ii][jj]; + y *= xd - --ii; + } + y += *sptr; + } else { /* otherwise, use Gauss as usual */ + y = 0; + gptr = &gauss_table[(note_data->sample_pos & FPMASK) * + (gauss_n + 1)]; + gend = gptr + gauss_n; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (gauss_n >> 1); + do { + y += *(sptr++) * *(gptr++); + } while (gptr <= gend); + } + + premix = (long) (y * vol_mul / 1024); + + left_mix += premix + * mdi->channel[note_data->noteid >> 8].left_adjust; + right_mix += premix + * mdi->channel[note_data->noteid >> 8].right_adjust; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (__builtin_expect( + (note_data->sample_pos > note_data->sample->loop_end), + 0)) { + if (note_data->modes & SAMPLE_LOOP) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } else if (__builtin_expect( + (note_data->sample_pos + >= note_data->sample->data_length), + 0)) { + if (__builtin_expect((note_data->replay == NULL), 1)) { + goto KILL_NOTE; + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect((note_data->env_inc == 0), 0)) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (__builtin_expect((note_data->env_level > 4194304), 0)) { + note_data->env_level = + note_data->sample->env_target[note_data->env]; + } + if (__builtin_expect( + ((note_data->env_inc < 0) + && (note_data->env_level + > note_data->sample->env_target[note_data->env])) + || ((note_data->env_inc > 0) + && (note_data->env_level + < note_data->sample->env_target[note_data->env])), + 1)) { + note_data = note_data->next; + continue; + } + + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: +#if 0 + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } +#endif + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (__builtin_expect((note_data->env_level == 0), 1)) { + goto KILL_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + if (__builtin_expect((note_data->replay != NULL), 1)) { + RESTART_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + KILL_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + left_mix /= 1024; + right_mix /= 1024; + } + + *tmp_buffer++ = left_mix; + *tmp_buffer++ = right_mix; + } while (--count); + + buffer_used += real_samples_to_mix * 4; + size -= (real_samples_to_mix << 2); + mdi->info.current_sample += real_samples_to_mix; + mdi->samples_to_mix -= real_samples_to_mix; + } while (size); + + tmp_buffer = out_buffer; + + if (mdi->info.mixer_options & WM_MO_REVERB) { + _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); + } + + for (i = 0; i < buffer_used; i += 4) { + left_mix = *tmp_buffer++; + right_mix = *tmp_buffer++; + + if (left_mix > 32767) { + left_mix = 32767; + } else if (left_mix < -32768) { + left_mix = -32768; + } + + if (right_mix > 32767) { + right_mix = 32767; + } else if (right_mix < -32768) { + right_mix = -32768; + } + + /* + * =================== + * Write to the buffer + * =================== + */ + (*buffer++) = left_mix & 0xff; + (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); + (*buffer++) = right_mix & 0xff; + (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); + } + _WM_Unlock(&mdi->lock); + return buffer_used; +} + +/* + * ========================= + * External Functions + * ========================= + */ + +WM_SYMBOL const char * +WildMidi_GetString(unsigned short int info) { + switch (info) { + case WM_GS_VERSION: + return WM_Version; + } + return NULL; +} + +WM_SYMBOL int WildMidi_Init(const char * config_file, unsigned short int rate, + unsigned short int options) { + if (WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_ALR_INIT, NULL, 0); + return -1; + } + + if (config_file == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(NULL config file pointer)", 0); + return -1; + } + WM_InitPatches(); + if (WM_LoadConfig(config_file) == -1) { + return -1; + } + + if (options & 0x5FF8) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", + 0); + WM_FreePatches(); + return -1; + } + WM_MixerOptions = options; + + if (rate < 11025) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(rate out of bounds, range is 11025 - 65535)", 0); + WM_FreePatches(); + return -1; + } + _WM_SampleRate = rate; + + gauss_lock = 0; + patch_lock = 0; + WM_Initialized = 1; + + return 0; +} + +WM_SYMBOL int WildMidi_MasterVolume(unsigned char master_volume) { + struct _mdi *mdi = NULL; + struct _hndl * tmp_handle = first_handle; + int i = 0; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (master_volume > 127) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(master volume out of range, range is 0-127)", 0); + return -1; + } + + WM_MasterVolume = lin_volume[master_volume]; + + if (tmp_handle) { + while (tmp_handle) { + mdi = (struct _mdi *) tmp_handle->handle; + for (i = 0; i < 16; i++) { + do_pan_adjust(mdi, i); + } + tmp_handle = tmp_handle->next; + } + } + + return 0; +} + +WM_SYMBOL int WildMidi_Close(midi * handle) { + struct _mdi *mdi = (struct _mdi *) handle; + struct _hndl * tmp_handle; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + if (first_handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", + 0); + return -1; + } + _WM_Lock(&mdi->lock); + if (first_handle->handle == handle) { + tmp_handle = first_handle->next; + free(first_handle); + first_handle = tmp_handle; + if (first_handle) + first_handle->prev = NULL; + } else { + tmp_handle = first_handle; + while (tmp_handle->handle != handle) { + tmp_handle = tmp_handle->next; + if (tmp_handle == NULL) { + break; + } + } + if (tmp_handle) { + tmp_handle->prev->next = tmp_handle->next; + if (tmp_handle->next) { + tmp_handle->next->prev = tmp_handle->prev; + } + free(tmp_handle); + } + } + + freeMDI(mdi); + + return 0; +} + +WM_SYMBOL midi * +WildMidi_Open(const char *midifile) { + unsigned char *mididata = NULL; + unsigned long int midisize = 0; + midi * ret = NULL; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (midifile == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", + 0); + return NULL; + } + + if ((mididata = _WM_BufferFile(midifile, &midisize)) == NULL) { + return NULL; + } + + ret = (void *) WM_ParseNewMidi(mididata, midisize); + free(mididata); + + if (ret) { + if (add_handle(ret) != 0) { + WildMidi_Close(ret); + ret = NULL; + } + } + + return ret; +} + +WM_SYMBOL midi * +WildMidi_OpenBuffer(unsigned char *midibuffer, unsigned long int size) { + midi * ret = NULL; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (midibuffer == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(NULL midi data buffer)", 0); + return NULL; + } + if (size > WM_MAXFILESIZE) { + /* don't bother loading suspiciously long files */ + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, NULL, 0); + return NULL; + } + ret = (void *) WM_ParseNewMidi(midibuffer, size); + + if (ret) { + if (add_handle(ret) != 0) { + WildMidi_Close(ret); + ret = NULL; + } + } + + return ret; +} + +WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { + struct _mdi *mdi; + struct _event *event; + struct _note *note_data; + unsigned long int real_samples_to_mix; + unsigned long int count; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + if (sample_pos == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(NULL seek position pointer)", 0); + return -1; + } + + mdi = (struct _mdi *) handle; + _WM_Lock(&mdi->lock); + event = mdi->current_event; + + /* make sure we havent asked for a positions beyond the end of the song. */ + if (*sample_pos > mdi->info.approx_total_samples) { + /* if so set the position to the end of the song */ + *sample_pos = mdi->info.approx_total_samples; + } + + /* was end of song requested and are we are there? */ + if (*sample_pos == mdi->info.current_sample) { + /* yes */ + _WM_Unlock(&mdi->lock); + return 0; + } + + /* did we want to fast forward? */ + if (mdi->info.current_sample < *sample_pos) { + /* yes */ + count = *sample_pos - mdi->info.current_sample; + } else { + /* no, reset values to start as the beginning */ + count = *sample_pos; + WM_ResetToStart(handle); + event = mdi->current_event; + } + + /* clear the reverb buffers since we not gonna be using them here */ + _WM_reset_reverb(mdi->reverb); + + while (count) { + if (__builtin_expect((!mdi->samples_to_mix), 0)) { + while ((!mdi->samples_to_mix) && (event->do_event)) { + event->do_event(mdi, &event->event_data); + event++; + mdi->samples_to_mix = event->samples_to_next; + mdi->current_event = event; + } + + if (!mdi->samples_to_mix) { + if (event->do_event == NULL) { + mdi->samples_to_mix = mdi->info.approx_total_samples + - *sample_pos; + } else { + mdi->samples_to_mix = count; + } + } + } + + if (__builtin_expect((mdi->samples_to_mix > count), 0)) { + real_samples_to_mix = count; + } else { + real_samples_to_mix = mdi->samples_to_mix; + } + + if (real_samples_to_mix == 0) { + break; + } + + count -= real_samples_to_mix; + mdi->info.current_sample += real_samples_to_mix; + mdi->samples_to_mix -= real_samples_to_mix; + } + + note_data = mdi->note; + if (note_data) { + do { + note_data->active = 0; + if (note_data->replay) { + note_data->replay = NULL; + } + note_data = note_data->next; + } while (note_data); + } + mdi->note = NULL; + + _WM_Unlock(&mdi->lock); + return 0; +} + +WM_SYMBOL int WildMidi_GetOutput(midi * handle, char *buffer, unsigned long int size) { + if (__builtin_expect((!WM_Initialized), 0)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (__builtin_expect((handle == NULL), 0)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + if (__builtin_expect((buffer == NULL), 0)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(NULL buffer pointer)", 0); + return -1; + } + if (__builtin_expect((size == 0), 0)) { + return 0; + } + if (__builtin_expect((!!(size % 4)), 0)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(size not a multiple of 4)", 0); + return -1; + } + if (((struct _mdi *) handle)->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) { + if (!gauss_table) init_gauss(); + return WM_GetOutput_Gauss(handle, buffer, size); + } + return WM_GetOutput_Linear(handle, buffer, size); +} + +WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, + unsigned short int setting) { + struct _mdi *mdi; + int i; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + + mdi = (struct _mdi *) handle; + _WM_Lock(&mdi->lock); + if ((!(options & 0x0007)) || (options & 0xFFF8)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", + 0); + _WM_Unlock(&mdi->lock); + return -1; + } + if (setting & 0xFFF8) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(invalid setting)", 0); + _WM_Unlock(&mdi->lock); + return -1; + } + + mdi->info.mixer_options = ((mdi->info.mixer_options & (0x00FF ^ options)) + | (options & setting)); + + if (options & WM_MO_LOG_VOLUME) { + struct _note *note_data = mdi->note; + + for (i = 0; i < 16; i++) { + do_pan_adjust(mdi, i); + } + + if (note_data) { + do { + note_data->vol_lvl = get_volume(mdi, (note_data->noteid >> 8), + note_data); + if (note_data->replay) + note_data->replay->vol_lvl = get_volume(mdi, + (note_data->noteid >> 8), note_data->replay); + note_data = note_data->next; + } while (note_data); + } + } else if (options & WM_MO_REVERB) { + _WM_reset_reverb(mdi->reverb); + } + + _WM_Unlock(&mdi->lock); + return 0; +} + +WM_SYMBOL struct _WM_Info * +WildMidi_GetInfo(midi * handle) { + struct _mdi *mdi = (struct _mdi *) handle; + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return NULL; + } + _WM_Lock(&mdi->lock); + if (mdi->tmp_info == NULL) { + mdi->tmp_info = (struct _WM_Info*)malloc(sizeof(struct _WM_Info)); + if (mdi->tmp_info == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0); + _WM_Unlock(&mdi->lock); + return NULL; + } + mdi->tmp_info->copyright = NULL; + } + mdi->tmp_info->current_sample = mdi->info.current_sample; + mdi->tmp_info->approx_total_samples = mdi->info.approx_total_samples; + mdi->tmp_info->mixer_options = mdi->info.mixer_options; + if (mdi->info.copyright) { + free(mdi->tmp_info->copyright); + mdi->tmp_info->copyright = (char*)malloc(strlen(mdi->info.copyright) + 1); + strcpy(mdi->tmp_info->copyright, mdi->info.copyright); + } else { + mdi->tmp_info->copyright = NULL; + } + _WM_Unlock(&mdi->lock); + return mdi->tmp_info; +} + +WM_SYMBOL int WildMidi_Shutdown(void) { + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + while (first_handle) { + /* closes open handle and rotates the handles list. */ + WildMidi_Close((struct _mdi *) first_handle->handle); + } + WM_FreePatches(); + free_gauss(); + + /* reset the globals */ + WM_MasterVolume = 948; + WM_MixerOptions = 0; + fix_release = 0; + auto_amp = 0; + auto_amp_with_amp = 0; + reverb_room_width = 16.875f; + reverb_room_length = 22.5f; + reverb_listen_posx = 8.4375f; + reverb_listen_posy = 16.875f; + + WM_Initialized = 0; + + return 0; +} diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h new file mode 100644 index 000000000..e6317a271 --- /dev/null +++ b/src/wildmidi/wildmidi_lib.h @@ -0,0 +1,75 @@ +/* + wildmidi_lib.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef WILDMIDI_LIB_H +#define WILDMIDI_LIB_H + +#define WM_MO_LOG_VOLUME 0x0001 +#define WM_MO_ENHANCED_RESAMPLING 0x0002 +#define WM_MO_REVERB 0x0004 +#define WM_MO_WHOLETEMPO 0x8000 +#define WM_MO_ROUNDTEMPO 0x2000 + +#define WM_GS_VERSION 0x0001 + +#define WM_SYMBOL // we do not need this in ZDoom + +/* +#if defined(__cplusplus) +extern "C" { +#endif +*/ + +struct _WM_Info { + char *copyright; + unsigned long int current_sample; + unsigned long int approx_total_samples; + unsigned short int mixer_options; + unsigned long int total_midi_time; +}; + +typedef void midi; + +WM_SYMBOL const char * WildMidi_GetString (unsigned short int info); +WM_SYMBOL int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options); +WM_SYMBOL int WildMidi_MasterVolume (unsigned char master_volume); +WM_SYMBOL midi * WildMidi_Open (const char *midifile); +WM_SYMBOL midi * WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size); +WM_SYMBOL int WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size); +WM_SYMBOL int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting); +WM_SYMBOL struct _WM_Info * WildMidi_GetInfo (midi * handle); +WM_SYMBOL int WildMidi_FastSeek (midi * handle, unsigned long int *sample_pos); +WM_SYMBOL int WildMidi_Close (midi * handle); +WM_SYMBOL int WildMidi_Shutdown (void); + +/* +#if defined(__cplusplus) +} +#endif +*/ + +#endif /* WILDMIDI_LIB_H */ + diff --git a/src/wildmidi/wm_error.cpp b/src/wildmidi/wm_error.cpp new file mode 100644 index 000000000..9fabdff84 --- /dev/null +++ b/src/wildmidi/wm_error.cpp @@ -0,0 +1,86 @@ +/* + wm_error.c + error reporting + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#include +#include +#include +#include "wm_error.h" +#include "doomtype.h" +#include "v_text.h" + +void _WM_ERROR_NEW(const char * wmfmt, ...) { + va_list args; + fprintf(stderr, "\r"); + va_start(args, wmfmt); + vfprintf(stderr, wmfmt, args); + va_end(args); + fprintf(stderr, "\n"); +} + +void _WM_ERROR(const char * func, unsigned int lne, int wmerno, + const char * wmfor, int error) { + + static const char *errors[WM_ERR_MAX+1] = { + "No error", + "Unable to obtain memory", + "Unable to stat", + "Unable to load", + "Unable to open", + "Unable to read", + "Invalid or Unsuported file format", + "File corrupt", + "Library not Initialized", + "Invalid argument", + "Library Already Initialized", + "Not a midi file", + "Refusing to load unusually long file", + + "Invalid error code" + }; + + if (wmerno < 0 || wmerno > WM_ERR_MAX) + wmerno = WM_ERR_MAX; + + if (wmfor != NULL) { + if (error != 0) { + Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s (%s)\n", func, + lne, errors[wmerno], wmfor, strerror(error)); + } else { + Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s\n", func, lne, + errors[wmerno], wmfor); + } + } else { + if (error != 0) { + Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s (%s)\n", func, lne, + errors[wmerno], strerror(error)); + } else { + Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s\n", func, lne, + errors[wmerno]); + } + } +} + diff --git a/src/wildmidi/wm_error.h b/src/wildmidi/wm_error.h new file mode 100644 index 000000000..316924648 --- /dev/null +++ b/src/wildmidi/wm_error.h @@ -0,0 +1,56 @@ +/* + wm_error.h + + error reporting + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +#ifndef __WM_ERROR_H +#define __WM_ERROR_H + +enum { + WM_ERR_NONE = 0, + WM_ERR_MEM, + WM_ERR_STAT, + WM_ERR_LOAD, + WM_ERR_OPEN, + WM_ERR_READ, + WM_ERR_INVALID, + WM_ERR_CORUPT, + WM_ERR_NOT_INIT, + WM_ERR_INVALID_ARG, + WM_ERR_ALR_INIT, + WM_ERR_NOT_MIDI, + WM_ERR_LONGFIL, + + WM_ERR_MAX +}; + + extern void _WM_ERROR_NEW(const char * wmfmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 1, 2))) +#endif + ; + extern void _WM_ERROR(const char * func, unsigned int lne, int wmerno, + const char * wmfor, int error); + +#endif /* __WM_ERROR_H */ From 4fb48b332b8faab1ab731653a84c941abed27609 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 28 Nov 2015 10:53:34 -0600 Subject: [PATCH 144/335] Added A_CheckProximity. - Checks to see if a certain actor class, in numbers, is close to the actor/pointer via distance, based upon count. Can check for ancestry, disable Z searching, perform less than or equal to instead of greater or equal to, exact counts, check a pointer instead of itself and differentiate between live monsters and dead. --- src/thingdef/thingdef_codeptr.cpp | 99 +++++++++++++++++++++++++++++- wadsrc/static/actors/actor.txt | 1 + wadsrc/static/actors/constants.txt | 11 ++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 14440d884..c01ff687e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5886,6 +5886,103 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) self->RipLevelMax = max; } +//========================================================================== +// +// A_CheckProximity(jump, classname, distance, count, flags, ptr) +// +// Checks to see if a certain actor class is close to the +// actor/pointer within distance, in numbers. +//========================================================================== +enum CPXFflags +{ + CPXF_ANCESTOR = 1, + CPXF_LESSOREQUAL = 1 << 1, + CPXF_NOZ = 1 << 2, + CPXF_COUNTDEAD = 1 << 3, + CPXF_DEADONLY = 1 << 4, + CPXF_EXACT = 1 << 5, +}; +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) +{ + ACTION_PARAM_START(6); + ACTION_PARAM_STATE(jump, 0); + ACTION_PARAM_CLASS(classname, 1); + ACTION_PARAM_FIXED(distance, 2); + ACTION_PARAM_INT(count, 3); + ACTION_PARAM_INT(flags, 4); + ACTION_PARAM_INT(ptr, 5); + + ACTION_SET_RESULT(false); //No inventory chain results please. + AActor *ref = COPY_AAPTR(self, ptr); + + //We need these to check out. + if (!ref || !jump || !classname || distance <= 0) + return; + + int counter = 0; + bool result = false; + + TThinkerIterator it; + AActor * mo; + + //[MC] Process of elimination, I think, will get through this as quickly and + //efficiently as possible. + while ((mo = it.Next())) + { + if (mo == ref) //Don't count self. + continue; + + //Check inheritance for the classname. Taken partly from CheckClass DECORATE function. + if (flags & CPXF_ANCESTOR) + { + if (!(mo->GetClass()->IsAncestorOf(classname))) + continue; + } + //Otherwise, just check for the regular class name. + else if (classname != mo->GetClass()) + continue; + + //Make sure it's in range and respect the desire for Z or not. + if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance && + ((flags & CPXF_NOZ) || + ((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) || + (ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance)))) + { + if (mo->flags6 & MF6_KILLED) + { + if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) + continue; + counter++; + } + else + { + if (flags & CPXF_DEADONLY) + continue; + counter++; + } + + //Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal. + if (counter > count) + { + result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; + break; + } + } + } + + if (counter == count) + result = true; + else if (counter < count) + result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); + + + + if (result) + { + ACTION_JUMP(jump); + } +} + /*=========================================================================== A_CheckBlock (state block, int flags, int ptr) @@ -5944,4 +6041,4 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) { ACTION_JUMP(block); } -} \ No newline at end of file +} diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index be4b8b416..5158aa7b5 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -337,6 +337,7 @@ ACTOR Actor native //: Thinker action native A_SetRipperLevel(int level); action native A_SetRipMin(int min); action native A_SetRipMax(int max); + action native A_CheckProximity(state jump, class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false); action native A_CheckRange(float distance, state label, bool two_dimension = false); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 7f8fbc09e..956ed119f 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -484,6 +484,17 @@ enum QF_WAVE = 1 << 5, }; +// A_CheckProximity flags +enum +{ + CPXF_ANCESTOR = 1, + CPXF_LESSOREQUAL = 1 << 1, + CPXF_NOZ = 1 << 2, + CPXF_COUNTDEAD = 1 << 3, + CPXF_DEADONLY = 1 << 4, + CPXF_EXACT = 1 << 5, +}; + // Flags for A_CheckBlock // These flags only affect the calling actor('s pointer), not the ones being searched. enum From a03b9477295743b038e9af141525e818eda6943c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Nov 2015 20:58:14 +0100 Subject: [PATCH 145/335] - WildMidi generally working, some cleanup left to do... --- src/CMakeLists.txt | 1 + src/s_advsound.cpp | 1 + src/s_sound.h | 1 + src/sound/i_musicinterns.h | 19 +++++++++++++++++++ src/sound/music_midi_base.cpp | 13 ++++++++----- src/sound/music_midistream.cpp | 4 ++++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 614d2fb50..5bc88249c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1080,6 +1080,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE sound/music_midistream.cpp sound/music_midi_base.cpp sound/music_midi_timidity.cpp + sound/music_midi_wildmidi.cpp sound/music_mus_opl.cpp sound/music_stream.cpp sound/music_fluidsynth_mididevice.cpp diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c72005813..cb0f26ae6 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1372,6 +1372,7 @@ static void S_AddSNDINFO (int lump) else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS; + else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI; else sc.ScriptError("Unknown MIDI device %s\n", sc.String); } break; diff --git a/src/s_sound.h b/src/s_sound.h index 49fb81fb3..16aa8b333 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -394,6 +394,7 @@ enum EMidiDevice MDEV_TIMIDITY = 3, MDEV_FLUIDSYNTH = 4, MDEV_GUS = 5, + MDEV_WILDMIDI = 6, }; typedef TMap MusicAliasMap; diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 77aa31312..4aa5f8254 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -24,6 +24,7 @@ #include "i_music.h" #include "s_sound.h" #include "files.h" +#include "wildmidi/wildmidi_lib.h" void I_InitMusicWin32 (); void I_ShutdownMusicWin32 (); @@ -218,6 +219,24 @@ protected: #endif }; +class WildMidiMIDIDevice : public PseudoMIDIDevice +{ +public: + WildMidiMIDIDevice(); + ~WildMidiMIDIDevice(); + + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + bool Preprocess(MIDIStreamer *song, bool looping); + bool IsOpen() const; + +protected: + + midi *mMidi; + bool mLoop; + + static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); +}; + // Base class for software synthesizer MIDI output devices ------------------ diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 649f9002e..e1afa09a8 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -11,9 +11,9 @@ static DWORD nummididevices; static bool nummididevicesset; #ifdef HAVE_FLUIDSYNTH -#define NUM_DEF_DEVICES 5 +#define NUM_DEF_DEVICES 6 #else -#define NUM_DEF_DEVICES 4 +#define NUM_DEF_DEVICES 5 #endif static void AddDefaultMidiDevices(FOptionValues *opt) @@ -33,8 +33,10 @@ static void AddDefaultMidiDevices(FOptionValues *opt) pair[p+1].Value = -3.0; pair[p+2].Text = "TiMidity++"; pair[p+2].Value = -2.0; - pair[p+3].Text = "Sound System"; - pair[p+3].Value = -1.0; + pair[p+3].Text = "WildMidi"; + pair[p+3].Value = -6.0; + pair[p+4].Text = "Sound System"; + pair[p+4].Value = -1.0; } @@ -70,7 +72,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) if (!nummididevicesset) return; - if ((self >= (signed)nummididevices) || (self < -5)) + if ((self >= (signed)nummididevices) || (self < -6)) { Printf ("ID out of range. Using default device.\n"); self = 0; @@ -211,6 +213,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt) CCMD (snd_listmididevices) { + Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : ""); #ifdef HAVE_FLUIDSYNTH Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : ""); #endif diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 6c85c06af..42e8b5926 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -240,6 +240,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) #ifdef HAVE_FLUIDSYNTH case -5: return MDEV_FLUIDSYNTH; #endif + case -6: return MDEV_WILDMIDI; default: #ifdef _WIN32 return MDEV_MMAPI; @@ -292,6 +293,9 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const case MDEV_TIMIDITY: return new TimidityPPMIDIDevice; + case MDEV_WILDMIDI: + return new WildMidiMIDIDevice; + default: return NULL; } From 3682924249390acb4cb0ab3c0b4daa1ba2b44eba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 11:27:08 +0100 Subject: [PATCH 146/335] - removed redundant parameter --- src/wildmidi/wildmidi_lib.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 9ae3ad1be..84c2f382a 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -1299,7 +1299,7 @@ static int load_sample(struct _patch *sample_patch) { } static struct _patch * -get_patch_data(struct _mdi *mdi, unsigned short patchid) { +get_patch_data(unsigned short patchid) { struct _patch *search_patch; _WM_Lock(&patch_lock); @@ -1320,7 +1320,7 @@ get_patch_data(struct _mdi *mdi, unsigned short patchid) { } if ((patchid >> 8) != 0) { _WM_Unlock(&patch_lock); - return (get_patch_data(mdi, patchid & 0x00FF)); + return (get_patch_data(patchid & 0x00FF)); } _WM_Unlock(&patch_lock); return NULL; @@ -1336,7 +1336,7 @@ static void load_patch(struct _mdi *mdi, unsigned short patchid) { } } - tmp_patch = get_patch_data(mdi, patchid); + tmp_patch = get_patch_data(patchid); if (tmp_patch == NULL) { return; } @@ -1530,8 +1530,7 @@ static void do_note_on(struct _mdi *mdi, struct _event_data *data) { } freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); } else { - patch = get_patch_data(mdi, - ((mdi->channel[ch].bank << 8) | note | 0x80)); + patch = get_patch_data(((mdi->channel[ch].bank << 8) | note | 0x80)); if (patch == NULL) { return; } @@ -1920,8 +1919,7 @@ static void do_patch(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch); if (!mdi->channel[ch].isdrum) { - mdi->channel[ch].patch = get_patch_data(mdi, - (unsigned short)(((mdi->channel[ch].bank << 8) | data->data))); + mdi->channel[ch].patch = get_patch_data((unsigned short)(((mdi->channel[ch].bank << 8) | data->data))); } else { mdi->channel[ch].bank = (unsigned char)data->data; } @@ -1986,7 +1984,7 @@ static void do_sysex_roland_drum_track(struct _mdi *mdi, mdi->channel[ch].patch = NULL; } else { mdi->channel[ch].isdrum = 0; - mdi->channel[ch].patch = get_patch_data(mdi, 0); + mdi->channel[ch].patch = get_patch_data(0); } } @@ -1995,7 +1993,7 @@ static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { for (i = 0; i < 16; i++) { mdi->channel[i].bank = 0; if (i != 9) { - mdi->channel[i].patch = get_patch_data(mdi, 0); + mdi->channel[i].patch = get_patch_data(0); } else { mdi->channel[i].patch = NULL; } @@ -2181,7 +2179,7 @@ static int midi_setup_patch(struct _mdi *mdi, unsigned char channel, mdi->channel[channel].bank = patch; } else { load_patch(mdi, ((mdi->channel[channel].bank << 8) | patch)); - mdi->channel[channel].patch = get_patch_data(mdi, + mdi->channel[channel].patch = get_patch_data( ((mdi->channel[channel].bank << 8) | patch)); } return 0; @@ -2614,7 +2612,7 @@ WM_ParseNewMidi(unsigned char *midi_data, unsigned int midi_size) { unsigned long int tmp_decay_samples = 0; struct _patch *tmp_patch = NULL; if (mdi->channel[current_event_ch].isdrum) { - tmp_patch = get_patch_data(mdi, + tmp_patch = get_patch_data( ((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80)); /* if (tmp_patch == NULL) @@ -2919,7 +2917,7 @@ WM_ParseNewMidi(unsigned char *midi_data, unsigned int midi_size) { struct _patch *tmp_patch = NULL; if (mdi->channel[current_event_ch].isdrum) { - tmp_patch = get_patch_data(mdi, + tmp_patch = get_patch_data( ((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80)); /* if (tmp_patch == NULL) From 9bfd67678330da477c3bf996536b6eaa2e33ff66 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 11:28:26 +0100 Subject: [PATCH 147/335] - allow setting the FloatbobPhase through UDMF. --- specs/udmf_zdoom.txt | 1 + src/doomdata.h | 1 + src/namedef.h | 1 + src/p_buildmap.cpp | 1 + src/p_mobj.cpp | 1 + src/p_setup.cpp | 2 ++ src/p_udmf.cpp | 6 ++++++ 7 files changed, 13 insertions(+) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 6541e9a02..d501cb884 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -237,6 +237,7 @@ Note: All fields default to false unless mentioned otherwise. scalex = ; // Vertical scaling on thing. Default = 0 (ignored). scaley = ; // Horizontal scaling on thing. Default = 0 (ignored). scale = ; // Vertical and horizontal scaling on thing. Default = 0 (ignored). + floatbobphase = ; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default). * Note about arg0str diff --git a/src/doomdata.h b/src/doomdata.h index 71e581e26..0877aee90 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -365,6 +365,7 @@ struct FMapThing short pitch; short roll; DWORD RenderStyle; + int FloatbobPhase; }; diff --git a/src/namedef.h b/src/namedef.h index 0d49bba76..22dbe1b51 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -396,6 +396,7 @@ xx(Roll) xx(Scale) xx(ScaleX) xx(ScaleY) +xx(Floatbobphase) xx(Blocking) xx(Blockmonsters) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 46c2b9f4c..670f53751 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -707,6 +707,7 @@ static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, mapthings[count].RenderStyle = STYLE_Count; mapthings[count].alpha = -1; mapthings[count].health = -1; + mapthings[count].FloatbobPhase = -1; if (xsprites != NULL && sprites[i].lotag == 710) { // Blood ambient sound diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d5c5eb5d9..ab89ae04c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4917,6 +4917,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->SpawnPoint[2] = mthing->z; mobj->SpawnAngle = mthing->angle; mobj->SpawnFlags = mthing->flags; + if (mthing->FloatbobPhase >= 0 && mthing->FloatbobPhase < 64) mobj->FloatBobPhase = mthing->FloatbobPhase; if (mthing->gravity < 0) mobj->gravity = -mthing->gravity; else if (mthing->gravity > 0) mobj->gravity = FixedMul(mobj->gravity, mthing->gravity); else mobj->flags &= ~MF_NOGRAVITY; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 311bf8fc4..50e7f41d6 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1758,6 +1758,7 @@ void P_LoadThings (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; + mti[i].FloatbobPhase = -1; flags &= ~MTF_SKILLMASK; mti[i].flags = (short)((flags & 0xf) | 0x7e0); if (gameinfo.gametype == GAME_Strife) @@ -1842,6 +1843,7 @@ void P_LoadThings2 (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; + mti[i].FloatbobPhase = -1; } delete[] mtp; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 0434d8bce..269ce7e3d 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -474,6 +474,7 @@ public: th->RenderStyle = STYLE_Count; th->alpha = -1; th->health = 1; + th->FloatbobPhase = -1; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { @@ -631,6 +632,11 @@ public: Flag(th->flags, MTF_SECRET, key); break; + case NAME_Floatbobphase: + CHECK_N(Zd | Zdt) + th->FloatbobPhase = CheckInt(key); + break; + case NAME_Renderstyle: { FName style = CheckString(key); From 5515cb02a6059155ce4c075d02aa69d785879b2d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 11:35:12 +0100 Subject: [PATCH 148/335] - fixed incorrect error method call in decal parser. --- src/decallib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decallib.cpp b/src/decallib.cpp index 0ea3423c4..08b4dfda2 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -432,7 +432,7 @@ WORD FDecalLib::GetDecalID (FScanner &sc) unsigned long num = strtoul (sc.String, NULL, 10); if (num < 1 || num > 65535) { - sc.MustGetStringName ("Decal ID must be between 1 and 65535"); + sc.ScriptError ("Decal ID must be between 1 and 65535"); } return (WORD)num; } From 1a0faf47619c15575109fd315e5770cd3862e89f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 11:41:14 +0100 Subject: [PATCH 149/335] - allow optional decal generator definitions. --- src/decallib.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/decallib.cpp b/src/decallib.cpp index 08b4dfda2..14b824a7b 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -603,16 +603,17 @@ void FDecalLib::ParseGenerator (FScanner &sc) { const PClass *type; FDecalBase *decal; - AActor *actor; + bool optional = false; // Get name of generator (actor) sc.MustGetString (); + optional = sc.Compare("optional"); + type = PClass::FindClass (sc.String); if (type == NULL || type->ActorInfo == NULL) { - sc.ScriptError ("%s is not an actor.", sc.String); + if (!optional) sc.ScriptError ("%s is not an actor.", sc.String); } - actor = (AActor *)type->Defaults; // Get name of generated decal sc.MustGetString (); @@ -628,11 +629,14 @@ void FDecalLib::ParseGenerator (FScanner &sc) sc.ScriptError ("%s has not been defined.", sc.String); } } - - actor->DecalGenerator = decal; - if (decal != NULL) + if (type != NULL) { - decal->Users.Push (type); + AActor *actor = (AActor *)type->Defaults; + actor->DecalGenerator = decal; + if (decal != NULL) + { + decal->Users.Push(type); + } } } From 1ad02a6ce8503341e57be1d4601f51cb45b17207 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 12:10:12 +0100 Subject: [PATCH 150/335] - allow specifying infighting through skills. --- src/g_level.h | 2 ++ src/g_skill.cpp | 17 +++++++++++++++++ src/p_interaction.cpp | 6 ++---- src/p_map.cpp | 5 +---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 496c5c0f4..60b371ba0 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -565,6 +565,7 @@ enum ESkillProperty SKILLP_ArmorFactor, SKILLP_EasyKey, SKILLP_SlowMonsters, + SKILLP_Infight, }; int G_SkillProperty(ESkillProperty prop); const char * G_SkillName(); @@ -602,6 +603,7 @@ struct FSkillInfo fixed_t MonsterHealth; fixed_t FriendlyHealth; bool NoPain; + int Infighting; fixed_t ArmorFactor; FSkillInfo() {} diff --git a/src/g_skill.cpp b/src/g_skill.cpp index ddfdbb4cc..718f1cd00 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -83,6 +83,7 @@ void FMapInfoParser::ParseSkill () skill.FriendlyHealth = FRACUNIT; skill.NoPain = false; skill.ArmorFactor = FRACUNIT; + skill.Infighting = 0; sc.MustGetString(); skill.Name = sc.String; @@ -266,6 +267,14 @@ void FMapInfoParser::ParseSkill () sc.MustGetFloat(); skill.ArmorFactor = FLOAT2FIXED(sc.Float); } + else if (sc.Compare("NoInfighting")) + { + skill.Infighting = LEVEL2_NOINFIGHTING; + } + else if (sc.Compare("TotalInfighting")) + { + skill.Infighting = LEVEL2_TOTALINFIGHTING; + } else if (sc.Compare("DefaultSkill")) { if (DefaultSkill >= 0) @@ -384,6 +393,14 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_ArmorFactor: return AllSkills[gameskill].ArmorFactor; + + case SKILLP_Infight: + // This property also needs to consider the level flags for the same info. + if (level.flags2 & LEVEL2_TOTALINFIGHTING) return 1; + if (level.flags2 & LEVEL2_NOINFIGHTING) return -1; + if (AllSkills[gameskill].Infighting == LEVEL2_TOTALINFIGHTING) return 1; + if (AllSkills[gameskill].Infighting == LEVEL2_NOINFIGHTING) return -1; + return infighting; } } return 0; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 25724172c..203d1688d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1639,10 +1639,8 @@ bool AActor::OkayToSwitchTarget (AActor *other) int infight; if (flags5 & MF5_NOINFIGHTING) infight=-1; - else if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight=1; - else if (level.flags2 & LEVEL2_NOINFIGHTING) infight=-1; - else infight = infighting; - + else infight = G_SkillProperty(SKILLP_Infight); + if (infight < 0 && other->player == NULL && !IsHostile (other)) { return false; // infighting off: Non-friendlies don't target other non-friendlies diff --git a/src/p_map.cpp b/src/p_map.cpp index e8e5d6c84..5dd0967b9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -938,10 +938,7 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // to harm / be harmed by anything. if (!victim->player && !shooter->player) { - int infight; - if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight = 1; - else if (level.flags2 & LEVEL2_NOINFIGHTING) infight = -1; - else infight = infighting; + int infight = G_SkillProperty(SKILLP_Infight); if (infight < 0) { From 106886a9bb995e6975163c60df20e4eb1429a0d5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 12:30:50 +0100 Subject: [PATCH 151/335] - allow setting the ice translation with Thing_SetTranslation. This requires passing a magic value because this translation is defined differently than all the rest which can be used in ACS. --- src/p_lnspec.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 26e736cb5..9c93ca15c 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1600,6 +1600,11 @@ FUNC(LS_Thing_Move) // [BC] return P_Thing_Move (arg0, it, arg1, arg2 ? false : true); } +enum +{ + TRANSLATION_ICE = 0x100007 +}; + FUNC(LS_Thing_SetTranslation) // Thing_SetTranslation (tid, range) { @@ -1616,6 +1621,10 @@ FUNC(LS_Thing_SetTranslation) { range = TRANSLATION(TRANSLATION_LevelScripted, (arg1-1)); } + else if (arg1 == TRANSLATION_ICE) + { + range = TRANSLATION(TRANSLATION_Standard, 7); + } else { range = 0; From f7cdb28eaccc4ece9869f400b0e710420852bc37 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 12:58:17 +0100 Subject: [PATCH 152/335] - added a HealthFactor skill property. --- src/g_level.h | 2 ++ src/g_shared/a_pickups.cpp | 4 +++- src/g_skill.cpp | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/g_level.h b/src/g_level.h index 60b371ba0..018737f09 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -563,6 +563,7 @@ enum ESkillProperty SKILLP_FriendlyHealth, SKILLP_NoPain, SKILLP_ArmorFactor, + SKILLP_HealthFactor, SKILLP_EasyKey, SKILLP_SlowMonsters, SKILLP_Infight, @@ -605,6 +606,7 @@ struct FSkillInfo bool NoPain; int Infighting; fixed_t ArmorFactor; + fixed_t HealthFactor; FSkillInfo() {} FSkillInfo(const FSkillInfo &other) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index e87929677..eb2831024 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -236,10 +236,12 @@ bool P_GiveBody (AActor *actor, int num, int max) return true; } } - else + else if (num > 0) { if (player->health < max) { + num = FixedMul(num, G_SkillProperty(SKILLP_HealthFactor)); + if (num < 1) num = 1; player->health += num; if (player->health > max) { diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 718f1cd00..bbee4ea11 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -84,6 +84,7 @@ void FMapInfoParser::ParseSkill () skill.NoPain = false; skill.ArmorFactor = FRACUNIT; skill.Infighting = 0; + skill.HealthFactor = FRACUNIT; sc.MustGetString(); skill.Name = sc.String; @@ -267,6 +268,12 @@ void FMapInfoParser::ParseSkill () sc.MustGetFloat(); skill.ArmorFactor = FLOAT2FIXED(sc.Float); } + else if (sc.Compare("HealthFactor")) + { + ParseAssign(); + sc.MustGetFloat(); + skill.HealthFactor = FLOAT2FIXED(sc.Float); + } else if (sc.Compare("NoInfighting")) { skill.Infighting = LEVEL2_NOINFIGHTING; From c9e4f120e721604939db490e1d3a91e6ef4657dc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Nov 2015 15:27:20 +0100 Subject: [PATCH 153/335] - forgot to save this before committing. --- src/g_skill.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index bbee4ea11..8f2cdc9f0 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -401,6 +401,9 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_ArmorFactor: return AllSkills[gameskill].ArmorFactor; + case SKILLP_HealthFactor: + return AllSkills[gameskill].HealthFactor; + case SKILLP_Infight: // This property also needs to consider the level flags for the same info. if (level.flags2 & LEVEL2_TOTALINFIGHTING) return 1; From f4a60f29f354e18d73f61dd53ca9eeee86a13d8e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 30 Nov 2015 09:21:45 +0100 Subject: [PATCH 154/335] - added missing sc.MustGetString() to 'optional' case of decal parser. --- src/decallib.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/decallib.cpp b/src/decallib.cpp index 14b824a7b..784998977 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -608,6 +608,7 @@ void FDecalLib::ParseGenerator (FScanner &sc) // Get name of generator (actor) sc.MustGetString (); optional = sc.Compare("optional"); + if (optional) sc.MustGetString(); type = PClass::FindClass (sc.String); if (type == NULL || type->ActorInfo == NULL) @@ -626,7 +627,7 @@ void FDecalLib::ParseGenerator (FScanner &sc) decal = ScanTreeForName (sc.String, Root); if (decal == NULL) { - sc.ScriptError ("%s has not been defined.", sc.String); + if (!optional) sc.ScriptError ("%s has not been defined.", sc.String); } } if (type != NULL) From 8594bfaa8ba5e6a5834ce41576a7394e8990fc82 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 30 Nov 2015 11:42:08 -0600 Subject: [PATCH 155/335] A_CustomPunch Extension - Added Melee/Miss parameters just like A_CustomMeleeAttack. --- src/thingdef/thingdef_codeptr.cpp | 11 +++++++++-- wadsrc/static/actors/shared/inventory.txt | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 14440d884..9fd631d16 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1414,6 +1414,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) ACTION_PARAM_FIXED(LifeSteal, 5); ACTION_PARAM_INT(lifestealmax, 6); ACTION_PARAM_CLASS(armorbonustype, 7); + ACTION_PARAM_SOUND(MeleeSound, 8); + ACTION_PARAM_SOUND(MissSound, 9); if (!self->player) return; @@ -1443,7 +1445,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget, &actualdamage); - if (linetarget) + if (!linetarget) + { + if (MissSound) S_Sound(self, CHAN_WEAPON, MissSound, 1, ATTN_NORM); + } + else { if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) { @@ -1474,7 +1480,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (weapon != NULL) { - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + if (MeleeSound) S_Sound(self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); + else S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); } if (!(flags & CPF_NOTURN)) diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 13ae00936..a44515efb 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -8,7 +8,7 @@ ACTOR Inventory native Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG" action native A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); + action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); From 724445354ca1e2bc0517a4a0cf8d0dae52c2a295 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Dec 2015 10:39:22 +0100 Subject: [PATCH 156/335] - add the WildMidiMIDIDevice CPP file. --- src/sound/music_midi_wildmidi.cpp | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 src/sound/music_midi_wildmidi.cpp diff --git a/src/sound/music_midi_wildmidi.cpp b/src/sound/music_midi_wildmidi.cpp new file mode 100644 index 000000000..f6df48459 --- /dev/null +++ b/src/sound/music_midi_wildmidi.cpp @@ -0,0 +1,163 @@ +#include "i_musicinterns.h" +#include "c_cvars.h" +#include "cmdlib.h" +#include "templates.h" +#include "version.h" + + +CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +static FString currentConfig; + +// added because Timidity's output is rather loud. +CUSTOM_CVAR (Float, wildmidi_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0.f) + self = 0.f; + else if (self > 1.f) + self = 1.f; +} + +CUSTOM_CVAR (Int, wildmidi_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ // Clamp frequency to Timidity's limits + if (self < 11000) + self = 11000; + else if (self > 65000) + self = 65000; +} + +//========================================================================== +// +// WildMidiMIDIDevice Constructor +// +//========================================================================== + +WildMidiMIDIDevice::WildMidiMIDIDevice() +{ + mMidi = NULL; + mLoop = false; +} + +//========================================================================== +// +// WildMidiMIDIDevice Destructor +// +//========================================================================== + +WildMidiMIDIDevice::~WildMidiMIDIDevice () +{ + if (mMidi != NULL) WildMidi_Close(mMidi); + // do not shut down the device so that it can be reused for the next song being played. +} + +//========================================================================== +// +// WildMidiMIDIDevice :: Preprocess +// +//========================================================================== + +bool WildMidiMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) +{ + TArray midi; + + // Write MIDI song to temporary file + song->CreateSMF(midi, looping ? 0 : 1); + + mMidi = WildMidi_OpenBuffer(&midi[0], midi.Size()); + if (mMidi == NULL) + { + Printf(PRINT_BOLD, "Could not open temp music file\n"); + } + mLoop = looping; + return false; +} + +//========================================================================== +// +// WildMidiMIDIDevice :: Open +// +//========================================================================== + +int WildMidiMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +{ + if (currentConfig.CompareNoCase(wildmidi_config) != 0) + { + if (currentConfig.IsNotEmpty()) WildMidi_Shutdown(); + currentConfig = ""; + if (!WildMidi_Init(wildmidi_config, wildmidi_frequency, WM_MO_ENHANCED_RESAMPLING)) + { + currentConfig = wildmidi_config; + } + else + { + return 1; + } + } + + Stream = GSnd->CreateStream(FillStream, 32 * 1024, 0, wildmidi_frequency, this); + if (Stream == NULL) + { + Printf(PRINT_BOLD, "Could not create music stream.\n"); + return 1; + } + + return 0; +} + + +//========================================================================== +// +// WildMidiMIDIDevice :: FillStream +// +//========================================================================== + +bool WildMidiMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +{ + char *buffer = (char*)buff; + WildMidiMIDIDevice *song = (WildMidiMIDIDevice *)userdata; + if (song->mMidi != NULL) + { + while (len > 0) + { + int written = WildMidi_GetOutput(song->mMidi, buffer, len); + if (written < 0) + { + // error + memset(buffer, 0, len); + return false; + } + buffer += written; + len -= written; + + if (len > 0) + { + if (!song->mLoop) + { + memset(buffer, 0, len); + return written > 0; + } + else + { + // loop the sound (i.e. go back to start.) + unsigned long spos = 0; + WildMidi_FastSeek(song->mMidi, &spos); + } + + } + } + } + + return true; +} + +//========================================================================== +// +// WildMidiMIDIDevice :: IsOpen +// +//========================================================================== + +bool WildMidiMIDIDevice::IsOpen() const +{ + return mMidi != NULL; +} + From 4adf421513ba7ebbeb81a2cb9ee9f149bf4446b8 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 1 Dec 2015 14:30:57 +0200 Subject: [PATCH 157/335] Fix incomplete assignment operator of FSkillInfo See http://forum.zdoom.org/viewtopic.php?t=50026 --- src/g_skill.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 8f2cdc9f0..f4cb63ea5 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -490,7 +490,9 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) MonsterHealth = other.MonsterHealth; FriendlyHealth = other.FriendlyHealth; NoPain = other.NoPain; + Infighting = other.Infighting; ArmorFactor = other.ArmorFactor; + HealthFactor = other.HealthFactor; return *this; } From 81f521fe562bd5e562ce08bf2dce33007dd6d9c6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 2 Dec 2015 22:31:27 +0100 Subject: [PATCH 158/335] - fixed: Texture precaching from MAPINFO was broken The code assumed that it had access to the texture manager but that gets initialized after MAPINFO, which means that MAPINFO can only store the texture names and let the precaching code resolve the actual textures. --- src/g_level.h | 2 +- src/g_mapinfo.cpp | 11 ++--------- src/textures/texturemanager.cpp | 3 ++- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 018737f09..2e8e8e4c5 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -339,7 +339,7 @@ struct level_info_t TArray specialactions; TArray PrecacheSounds; - TArray PrecacheTextures; + TArray PrecacheTextures; level_info_t() { diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index ac938797d..9dace3e23 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1077,15 +1077,8 @@ DEFINE_MAP_OPTION(PrecacheTextures, true) do { parse.sc.MustGetString(); - FTextureID tex = TexMan.CheckForTexture(parse.sc.String, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_ReturnFirst); - if (!tex.isValid()) - { - parse.sc.ScriptMessage("Unknown texture \"%s\"", parse.sc.String); - } - else - { - info->PrecacheTextures.Push(tex); - } + //the texture manager is not initialized here so all we can do is store the texture's name. + info->PrecacheTextures.Push(parse.sc.String); } while (parse.sc.CheckString(",")); } diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 2944e4200..4fc82ac0d 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -1246,7 +1246,8 @@ void FTextureManager::PrecacheLevel (void) for (unsigned i = 0; i < level.info->PrecacheTextures.Size(); i++) { - hitlist[level.info->PrecacheTextures[i].GetIndex()] |= FTextureManager::HIT_Wall; + FTextureID tex = TexMan.CheckForTexture(level.info->PrecacheTextures[i], FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_ReturnFirst); + if (tex.Exists()) hitlist[tex.GetIndex()] |= FTextureManager::HIT_Wall; } for (int i = cnt - 1; i >= 0; i--) From f90ce1308e0764ea8c8b3c9f3ca700942b592062 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 3 Dec 2015 16:40:47 +1300 Subject: [PATCH 159/335] Fix lost focus loosing network data - Prevented focus loss from dropping network data during level transitions - Fixed delay counter underflows --- src/d_net.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index e6b5713f2..780b89382 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -973,7 +973,7 @@ void NetUpdate (void) { I_StartTic (); D_ProcessEvents (); - if ((maketic - gametic) / ticdup >= BACKUPTICS/2-1) + if (pauseext || (maketic - gametic) / ticdup >= BACKUPTICS/2-1) break; // can't hold any more //Printf ("mk:%i ",maketic); @@ -1204,7 +1204,7 @@ void NetUpdate (void) // Send current network delay // The number of tics we just made should be removed from the count. - netbuffer[k++] = ((maketic - newtics - gametic) / ticdup); + netbuffer[k++] = ((maketic - numtics - gametic) / ticdup); if (numtics > 0) { @@ -1810,7 +1810,8 @@ void TryRunTics (void) // If paused, do not eat more CPU time than we need, because it // will all be wasted anyway. - if (pauseext) r_NoInterpolate = true; + if (pauseext) + r_NoInterpolate = true; bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/; // get real tics @@ -1828,6 +1829,9 @@ void TryRunTics (void) // get available tics NetUpdate (); + if (pauseext) + return; + lowtic = INT_MAX; numplaying = 0; for (i = 0; i < doomcom.numnodes; i++) @@ -1935,7 +1939,7 @@ void TryRunTics (void) C_Ticker (); M_Ticker (); I_GetTime (true); - if (!pauseext) G_Ticker(); + G_Ticker(); gametic++; NetUpdate (); // check for new console commands From 542a1089145f426ac6a5af74961ec3d98ec036dc Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Sat, 5 Dec 2015 00:26:39 +0100 Subject: [PATCH 160/335] 3D floor support for check switch range --- src/p_switch.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 1ca4654b5..984794c8a 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -177,10 +177,47 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) if ((TexMan.FindSwitch(side->GetTexture(side_t::top))) != NULL) { + + // Check 3D floors on back side + { + sector_t * back = line->sidedef[1 - sideno]->sector; + for (unsigned i = 0; i < back->e->XFloor.ffloors.Size(); i++) + { + F3DFloor *rover = back->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + if (!(rover->flags & FF_UPPERTEXTURE)) continue; + + if (user->z > rover->top.plane->ZatPoint(checkx, checky) || + user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky)) + continue; + + // This 3D floor depicts a switch texture in front of the player's eyes + return true; + } + } + return (user->z + user->height > open.top); } else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) { + // Check 3D floors on back side + { + sector_t * back = line->sidedef[1 - sideno]->sector; + for (unsigned i = 0; i < back->e->XFloor.ffloors.Size(); i++) + { + F3DFloor *rover = back->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + if (!(rover->flags & FF_LOWERTEXTURE)) continue; + + if (user->z > rover->top.plane->ZatPoint(checkx, checky) || + user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky)) + continue; + + // This 3D floor depicts a switch texture in front of the player's eyes + return true; + } + } + return (user->z < open.bottom); } else if ((flags & ML_3DMIDTEX) || (TexMan.FindSwitch(side->GetTexture(side_t::mid))) != NULL) From ad0e71942d15dc79f81e9c3d48ea78a9d8e89534 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Dec 2015 09:59:02 +0100 Subject: [PATCH 161/335] - added GetAspectRatio function to ACS. - added a sixth parameter for SetHUDClipRect so that the forced aspect ratio fudging this function performs can be disabled. --- src/g_shared/hudmessages.cpp | 11 ++++++++++- src/g_shared/sbar.h | 4 +++- src/p_acs.cpp | 9 ++++++++- src/p_acs.h | 1 + src/version.h | 2 +- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index f60c8a84e..997021c5f 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -134,6 +134,7 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h NoWrap = false; ClipX = ClipY = ClipWidth = ClipHeight = 0; WrapWidth = 0; + HandleAspect = true; Top = y; Next = NULL; Lines = NULL; @@ -196,6 +197,14 @@ void DHUDMessage::Serialize (FArchive &arc) NoWrap = false; ClipX = ClipY = ClipWidth = ClipHeight = WrapWidth = 0; } + if (SaveVersion >= 4525) + { + arc << HandleAspect; + } + else + { + HandleAspect = true; + } if (arc.IsLoading ()) { Lines = NULL; @@ -257,7 +266,7 @@ void DHUDMessage::CalcClipCoords(int hudheight) else { screen->VirtualToRealCoordsInt(x, y, w, h, - HUDWidth, hudheight, false, true); + HUDWidth, hudheight, false, HandleAspect); ClipLeft = x; ClipTop = y; ClipRight = x + w; diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index b8dde5850..b8416dd5d 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -94,12 +94,13 @@ public: NoWrap = nowrap; ResetText(SourceText); } - void SetClipRect(int x, int y, int width, int height) + void SetClipRect(int x, int y, int width, int height, bool aspect) { ClipX = x; ClipY = y; ClipWidth = width; ClipHeight = height; + HandleAspect = aspect; } void SetWrapWidth(int wrap) { @@ -119,6 +120,7 @@ protected: int HUDWidth, HUDHeight; int ClipX, ClipY, ClipWidth, ClipHeight, WrapWidth; // in HUD coords int ClipLeft, ClipTop, ClipRight, ClipBot; // in screen coords + bool HandleAspect; EColorRange TextColor; FFont *Font; FRenderStyle Style; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4f8a0c6c3..4f9e8fd2e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4442,6 +4442,7 @@ enum EACSFunctions ACSF_GetActorRoll, ACSF_QuakeEx, ACSF_Warp, // 92 + ACSF_GetAspectRatio, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5315,6 +5316,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const ClipRectWidth = argCount > 2 ? args[2] : 0; ClipRectHeight = argCount > 3 ? args[3] : 0; WrapWidth = argCount > 4 ? args[4] : 0; + HandleAspect = argCount > 5 ? !!args[5] : true; break; case ACSF_SetHUDWrapWidth: @@ -5915,10 +5917,14 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return false; } + case ACSF_GetAspectRatio: + return CheckRatio(screen->GetWidth(), screen->GetHeight()); + default: break; } + return 0; } @@ -7854,7 +7860,7 @@ scriptwait: } break; } - msg->SetClipRect(ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight); + msg->SetClipRect(ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight, HandleAspect); if (WrapWidth != 0) { msg->SetWrapWidth(WrapWidth); @@ -9466,6 +9472,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr activefont = SmallFont; hudwidth = hudheight = 0; ClipRectLeft = ClipRectTop = ClipRectWidth = ClipRectHeight = WrapWidth = 0; + HandleAspect = true; state = SCRIPT_Running; // Hexen waited one second before executing any open scripts. I didn't realize diff --git a/src/p_acs.h b/src/p_acs.h index d5971e349..3188e46aa 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -891,6 +891,7 @@ protected: int hudwidth, hudheight; int ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight; int WrapWidth; + bool HandleAspect; FBehavior *activeBehavior; int InModuleScriptNumber; diff --git a/src/version.h b/src/version.h index 913c9bd18..168cb7519 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4524 +#define SAVEVER 4525 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 0cb64dd4647603defa71b1e890eb686c662cb09f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Dec 2015 20:55:05 +0100 Subject: [PATCH 162/335] - made character encoding for UFMF/ZDoom namespaces explicit. --- specs/udmf_zdoom.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index d501cb884..e79ae196b 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -27,7 +27,8 @@ II. Implementation Semantics II.A : Storage and Retrieval of Data ------------------------------------ -No changes. +Any TEXTMAP lump in the described namespaces must be encoded in ISO 8859-1 which +as of this writing is the only character encoding supported by ZDoom. ----------------------------------- II.B : Storage Within Archive Files From 72d4c3345302a1a02459005c7f510c5aa1edec55 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 7 Dec 2015 01:18:56 -0500 Subject: [PATCH 163/335] - Removed GetAspectRatio as the implementation was highly fragile. Even if converted to giving the ratio, I have strong concerns about having this function built in without ZDoom supporting arbitrary aspect ratios as the odds of people checking against the hard coded constants seems high. The existing ACS version of this function returns fixed point ratios (because why not) and I fully expected people to use a switch statement when writing it. --- src/p_acs.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4f9e8fd2e..30733eac8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4442,7 +4442,6 @@ enum EACSFunctions ACSF_GetActorRoll, ACSF_QuakeEx, ACSF_Warp, // 92 - ACSF_GetAspectRatio, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5917,9 +5916,6 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return false; } - case ACSF_GetAspectRatio: - return CheckRatio(screen->GetWidth(), screen->GetHeight()); - default: break; } From 964ee6bb23b5b2cb722275cfdee9dd1a625f15cd Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 7 Dec 2015 04:49:40 -0500 Subject: [PATCH 164/335] - Worked around issue where stat doesn't work in v140_xp. Even though the bug was supposedly fixed for awhile now it didn't make it into Update 1. --- src/CMakeLists.txt | 5 +++++ src/win32/i_system.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 782e4bac0..bd353a2ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -496,6 +496,11 @@ if( NOT MSVC ) add_definitions( -D__forceinline=inline ) endif( NOT MSVC ) +# Fix stat in v140_xp (broken in RTM and Update 1 so far) +if( MSVC AND MSVC_VERSION EQUAL 1900 AND CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" ) + add_definitions( -D_stat64i32=VS14Stat ) +endif( MSVC AND MSVC_VERSION EQUAL 1900 AND CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" ) + if( UNIX ) CHECK_LIBRARY_EXISTS( rt clock_gettime "" CLOCK_GETTIME_IN_RT ) if( NOT CLOCK_GETTIME_IN_RT ) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index ef56c7050..133337af5 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1726,3 +1726,36 @@ FString I_GetLongPathName(FString shortpath) delete[] buff; return longpath; } + +#if _MSC_VER == 1900 && defined(_USING_V110_SDK71_) +//========================================================================== +// +// VS14Stat +// +// Work around an issue where stat doesn't work with v140_xp. This was +// supposedly fixed, but as of Update 1 continues to not function on XP. +// +//========================================================================== + +#include + +int VS14Stat(const char *path, struct _stat64i32 *buffer) +{ + WIN32_FILE_ATTRIBUTE_DATA data; + if(!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) + return -1; + + buffer->st_ino = 0; + buffer->st_mode = ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG)| + ((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE); + buffer->st_dev = buffer->st_rdev = 0; + buffer->st_nlink = 1; + buffer->st_uid = 0; + buffer->st_gid = 0; + buffer->st_size = data.nFileSizeLow; + buffer->st_atime = (*(QWORD*)&data.ftLastAccessTime) / 10000000 - 11644473600LL; + buffer->st_mtime = (*(QWORD*)&data.ftLastWriteTime) / 10000000 - 11644473600LL; + buffer->st_ctime = (*(QWORD*)&data.ftCreationTime) / 10000000 - 11644473600LL; + return 0; +} +#endif From 18de376edf8bb4e1d90f8b74c70f4f1080157669 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Mon, 7 Dec 2015 11:19:42 +0100 Subject: [PATCH 165/335] - Fixed lemon trying to free non-allocated memory. This is a regression from commit 24a096fb27eb0959366c605499c7819352cc501c . It happened only the input files were present in the same directory as the executable. --- tools/lemon/lemon.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index 5e8f03a8b..651e43f20 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -3061,6 +3061,7 @@ struct lemon *lemp; FILE *in; char *tpltname; char *cp; + Boolean tpltnameinbuf; cp = strrchr(lemp->filename,'.'); if( cp ){ @@ -3070,10 +3071,13 @@ struct lemon *lemp; } if( access(buf,004)==0 ){ tpltname = buf; + tpltnameinbuf = LEMON_TRUE; }else if( access(templatename,004)==0 ){ tpltname = templatename; + tpltnameinbuf = LEMON_TRUE; }else{ tpltname = pathsearch(lemp->argv0,templatename,0); + tpltnameinbuf = LEMON_FALSE; } if( tpltname==0 ){ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", @@ -3084,11 +3088,11 @@ struct lemon *lemp; in = fopen(tpltname,"rb"); if( in==0 ){ fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); - free(tpltname); + if (tpltnameinbuf == LEMON_FALSE) free(tpltname); lemp->errorcnt++; return 0; } - free(tpltname); + if (tpltnameinbuf == LEMON_FALSE) free(tpltname); return in; } From 7c6237e1343915f26c84010bf668e1133e7a8395 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 10 Dec 2015 21:24:37 -0600 Subject: [PATCH 166/335] has replaced on FreeBSD as well --- src/sound/fmodsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 33ca0495d..4042ca421 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -44,7 +44,7 @@ extern HWND Window; #define FALSE 0 #define TRUE 1 #endif -#ifdef __APPLE__ +#if defined(__FreeBSD__) || defined(__APPLE__) #include #elif __sun #include From af2ce6ef427d2d175bd5c19403f7bc26dcb5ad02 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 14 Dec 2015 09:06:13 +0100 Subject: [PATCH 167/335] - fixed: The 'mindefaults' game configuration must define the player starts 5-8. --- wadsrc/static/mapinfo/mindefaults.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wadsrc/static/mapinfo/mindefaults.txt b/wadsrc/static/mapinfo/mindefaults.txt index cbb3fa06b..0d7b16209 100644 --- a/wadsrc/static/mapinfo/mindefaults.txt +++ b/wadsrc/static/mapinfo/mindefaults.txt @@ -56,4 +56,12 @@ gameinfo statscreen_enteringpatch = "WIENTER" } +DoomEdNums +{ + 4001 = "$Player5Start" + 4002 = "$Player6Start" + 4003 = "$Player7Start" + 4004 = "$Player8Start" +} + include "mapinfo/common.txt" From 9176d75580d10a7d9ad4f8ab77ef18d6ffbe247e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 14 Dec 2015 11:47:46 +0200 Subject: [PATCH 168/335] Fix incorrect small font rendering with Hexen Mac IWAD Unused high resolution font lumps broke composite font logic Small font had doubled height because of that, at least alternate HUD and inter-hub text messages had noticeable visual issues --- src/w_wad.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/w_wad.h | 1 + 2 files changed, 37 insertions(+) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index efeb38571..552228557 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -184,6 +184,7 @@ void FWadCollection::InitMultipleFiles (TArray &filenames) } RenameNerve(); RenameSprites(); + FixMacHexen(); // [RH] Set up hash table FirstLumpIndex = new DWORD[NumLumps]; @@ -956,6 +957,41 @@ void FWadCollection::RenameNerve () } } +//========================================================================== +// +// FixMacHexen +// +// Rename unused high resolution font lumps because they are incorrectly +// treated as extended characters +// +//========================================================================== + +void FWadCollection::FixMacHexen() +{ + if (GAME_Hexen != gameinfo.gametype) + { + return; + } + + for (int i = GetFirstLump(IWAD_FILENUM), last = GetLastLump(IWAD_FILENUM); i <= last; ++i) + { + assert(IWAD_FILENUM == LumpInfo[i].wadnum); + + FResourceLump* const lump = LumpInfo[i].lump; + char* const name = lump->Name; + + // Unwanted lumps are named like FONTA??1 + + if (8 == strlen(name) + && MAKE_ID('F', 'O', 'N', 'T') == lump->dwName + && 'A' == name[4] && '1' == name[7] + && isdigit(name[5]) && isdigit(name[6])) + { + name[0] = '\0'; + } + } +} + //========================================================================== // // W_FindLump diff --git a/src/w_wad.h b/src/w_wad.h index 323f12df2..dcac6a1b2 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -238,6 +238,7 @@ protected: private: void RenameSprites(); void RenameNerve(); + void FixMacHexen(); void DeleteAll(); }; From 06bb75576c45ae315c2ab37745503eb08b65ab0a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 15 Dec 2015 14:13:54 -0600 Subject: [PATCH 169/335] Revert "Fixed timekeeping when starting a sigrenderer with a time offset" This reverts commit cf2577d4bc284fb5c5b71377413a47c72a1362dc. --- dumb/src/it/itrender.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 0491e7e59..fd8ccae13 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -5482,10 +5482,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_ while (pos > 0 && pos >= sigrenderer->time_left) { render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)sigrenderer->time_left << 16; -#endif - pos -= sigrenderer->time_left; sigrenderer->time_left = 0; @@ -5498,10 +5494,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_ render(sigrenderer, 0, 1.0f, 0, pos, NULL); sigrenderer->time_left -= pos; -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)pos << 16; -#endif - return sigrenderer; } From d3000fd838495bc1eb5a72def26172e374d1c3c9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 15 Dec 2015 14:16:34 -0600 Subject: [PATCH 170/335] Revert "Fixed timekeeping" This reverts commit 68f8a3aa8fb53b98625232d99cc5bd040e67dd96. Conflicts: dumb/src/it/itrender.c --- dumb/src/it/itrender.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index fd8ccae13..a82649268 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -4244,6 +4244,10 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) */ #endif bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); + if (sigrenderer->looped == 0) { + timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played); + } + timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); { int n; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) @@ -4413,13 +4417,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) } } -#ifdef BIT_ARRAY_BULLSHIT - if (sigrenderer->looped == 0) { - timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played); - } - timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); -#endif - if (!(sigdata->flags & IT_WAS_A_669)) reset_effects(sigrenderer); @@ -5510,7 +5507,7 @@ static int32 it_sigrenderer_get_samples( int dt; int32 todo; int ret; - LONG_LONG t; + LONG_LONG time_left, t; if (sigrenderer->order < 0) return 0; // problematic @@ -5523,7 +5520,8 @@ static int32 it_sigrenderer_get_samples( if (!samples) volume = 0; for (;;) { - todo = (int32)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt); + time_left = ((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left; + todo = (long)(time_left / dt); if (todo >= size) break; @@ -5538,7 +5536,7 @@ static int32 it_sigrenderer_get_samples( sigrenderer->time_left += (int32)(t >> 16); #ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)todo * dt; + sigrenderer->time_played += time_left; #endif ret = process_tick(sigrenderer); From d0f1df113223182b2ad75accfbb0dc3511cb996d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 15 Dec 2015 14:17:02 -0600 Subject: [PATCH 171/335] Revert "Fixed duplicating some timekeeping state variables" This reverts commit 381ce8ea4237a64d63ac447d1e42463edde356da. --- dumb/src/it/itrender.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index a82649268..99f8bdc13 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -353,8 +353,6 @@ static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_chan #ifdef BIT_ARRAY_BULLSHIT dst->played = bit_array_dup(src->played); - dst->looped = src->looped; - dst->time_played = src->time_played; dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper); #endif From 8a6dfabedb104e7ae37e0c4f03c7c3b44397b048 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 15 Dec 2015 14:29:51 -0600 Subject: [PATCH 172/335] Revert "- Implemented loop-accurate time position reporting into DUMB" This reverts commit 153721b1c9f4cde62fa17d6aef56f782b37384bf. Conflicts: dumb/include/dumb.h dumb/include/internal/tarray.h dumb/src/helpers/tarray.c dumb/src/it/itrender.c --- dumb/CMakeLists.txt | 1 - dumb/include/dumb.h | 5 - dumb/include/internal/it.h | 16 --- dumb/include/internal/tarray.h | 31 ----- dumb/prj/dumb/dumb.pro | 2 - dumb/src/core/rendsig.c | 10 +- dumb/src/helpers/tarray.c | 175 ----------------------------- dumb/src/it/itrender.c | 76 ++----------- dumb/vc6/dumb/dumb.vcxproj | 2 - dumb/vc6/dumb/dumb.vcxproj.filters | 6 - 10 files changed, 8 insertions(+), 316 deletions(-) delete mode 100644 dumb/include/internal/tarray.h delete mode 100644 dumb/src/helpers/tarray.c diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index e95c69154..b590aa165 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -39,7 +39,6 @@ add_library( dumb src/helpers/memfile.c src/helpers/clickrem.c src/helpers/barray.c - src/helpers/tarray.c src/it/xmeffect.c src/it/readxm2.c src/it/readxm.c diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index c2c0aaa32..2b6ac4879 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -606,10 +606,6 @@ typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)( sample_t *samples ); -typedef int32 (*DUH_SIGRENDERER_GET_POSITION)( - sigrenderer_t *sigrenderer -); - typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer); typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata); @@ -625,7 +621,6 @@ typedef struct DUH_SIGTYPE_DESC DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam; DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples; DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample; - DUH_SIGRENDERER_GET_POSITION sigrenderer_get_position; DUH_END_SIGRENDERER end_sigrenderer; DUH_UNLOAD_SIGDATA unload_sigdata; } diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 6defa759a..a9196b316 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -33,7 +33,6 @@ #include #include "barray.h" -#include "tarray.h" /** TO DO: THINK ABOUT THE FOLLOWING: @@ -724,21 +723,6 @@ struct DUMB_IT_SIGRENDERER #ifdef BIT_ARRAY_BULLSHIT /* bit array, which rows are played, only checked by pattern break or loop commands */ void * played; - - /* - Loop indicator for internal processes, may also be useful for external processes - 0 - Not looped - 1 - Looped - -1 - Continued past loop - */ - int looped; - - /* - Kept until looped - */ - LONG_LONG time_played; - - void * row_timekeeper; #endif int32 gvz_time; diff --git a/dumb/include/internal/tarray.h b/dumb/include/internal/tarray.h deleted file mode 100644 index 7eb3af7c6..000000000 --- a/dumb/include/internal/tarray.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _T_ARRAY_H_ -#define _T_ARRAY_H_ - -#include - -#ifndef LONG_LONG -#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__ -#define LONG_LONG long long -#elif defined _MSC_VER || defined __WATCOMC__ -#define LONG_LONG __int64 -#elif defined __sgi -#define LONG_LONG long long -#else -#error 64-bit integer type unknown -#endif -#endif - -void * timekeeping_array_create(size_t size); -void timekeeping_array_destroy(void * array); -void * timekeeping_array_dup(void * array); - -void timekeeping_array_reset(void * array, size_t loop_start); - -void timekeeping_array_push(void * array, size_t index, LONG_LONG time); -void timekeeping_array_bump(void * array, size_t index); - -unsigned int timekeeping_array_get_count(void * array, size_t index); - -LONG_LONG timekeeping_array_get_item(void * array, size_t index); - -#endif diff --git a/dumb/prj/dumb/dumb.pro b/dumb/prj/dumb/dumb.pro index 629a9294a..9244ce4bd 100644 --- a/dumb/prj/dumb/dumb.pro +++ b/dumb/prj/dumb/dumb.pro @@ -37,7 +37,6 @@ SOURCES += \ ../../src/helpers/memfile.c \ ../../src/helpers/clickrem.c \ ../../src/helpers/barray.c \ - ../../src/helpers/tarray.c \ ../../src/it/xmeffect.c \ ../../src/it/readxm2.c \ ../../src/it/readxm.c \ @@ -109,7 +108,6 @@ HEADERS += \ ../../include/internal/it.h \ ../../include/internal/dumb.h \ ../../include/internal/barray.h \ - ../../include/internal/tarray.h \ ../../include/internal/aldumb.h \ ../../include/internal/sinc_resampler.h \ ../../include/internal/stack_alloc.h \ diff --git a/dumb/src/core/rendsig.c b/dumb/src/core/rendsig.c index 053011a11..72da173c5 100644 --- a/dumb/src/core/rendsig.c +++ b/dumb/src/core/rendsig.c @@ -147,15 +147,7 @@ int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer) int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer) { - DUH_SIGRENDERER_GET_POSITION proc; - - if (!sigrenderer) return -1; - - proc = sigrenderer->desc->sigrenderer_get_position; - if (proc) - return (*proc)(sigrenderer->sigrenderer); - else - return sigrenderer->pos; + return sigrenderer ? sigrenderer->pos : -1; } diff --git a/dumb/src/helpers/tarray.c b/dumb/src/helpers/tarray.c deleted file mode 100644 index f3ba422d8..000000000 --- a/dumb/src/helpers/tarray.c +++ /dev/null @@ -1,175 +0,0 @@ -#include "internal/tarray.h" - -#include - - /* - Structures which contain the play times of each pattern and row combination in the song, - not guaranteed to be valid for the whole song until the loop status is no longer zero. - The initial count and restart count will both be zero on song start, then both will be - incremented until the song loops. Restart count will be reset to zero on loop for all - rows which have a time equal to or greater than the loop start point, so time keeping - functions will know which timestamp the song is currently located at. - - Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time. - */ - - /* - We don't need full timekeeping because the player loop only wants the first play time - of the loop start order/row. We also don't really want full timekeeping because it - involves a lot of memory allocations, which is also slow. - */ - -#undef FULL_TIMEKEEPING - -typedef struct DUMB_IT_ROW_TIME -{ - unsigned int count, restart_count; -#ifndef FULL_TIMEKEEPING - LONG_LONG first_time; -#else - LONG_LONG * times; -#endif -} DUMB_IT_ROW_TIME; - -void * timekeeping_array_create(size_t size) -{ - size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size ); - if ( _size ) { - *_size = size; - } - return _size; -} - -void timekeeping_array_destroy(void * array) -{ -#ifdef FULL_TIMEKEEPING - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - for (i = 0; i < *size; i++) { - if (s[i].times) free(s[i].times); - } -#endif - - free(array); -} - -void * timekeeping_array_dup(void * array) -{ - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size ); - if ( new_size ) { - DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1); - - *new_size = *size; - - for (i = 0; i < *size; i++) { - new_s[i].count = s[i].count; - new_s[i].restart_count = s[i].restart_count; - -#ifndef FULL_TIMEKEEPING - new_s[i].first_time = s[i].first_time; -#else - if ( s[i].times ) { - size_t time_count = ( s[i].count + 15 ) & ~15; - new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count ); - if ( new_s[i].times == (void *)0 ) { - timekeeping_array_destroy( new_size ); - return (void *) 0; - } - memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count ); - } -#endif - } - } - - return new_size; -} - -void timekeeping_array_reset(void * array, size_t loop_start) -{ - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - DUMB_IT_ROW_TIME * s_loop_start = s + loop_start; - LONG_LONG loop_start_time; - - if ( loop_start >= *size || s_loop_start->count < 1 ) return; - -#ifndef FULL_TIMEKEEPING - loop_start_time = s_loop_start->first_time; -#else - loop_start_time = s_loop_start->times[0]; -#endif - - for ( i = 0; i < *size; i++ ) { -#ifndef FULL_TIMEKEEPING - if ( s[i].count && s[i].first_time >= loop_start_time ) { -#else - if ( s[i].count && s[i].times[0] >= loop_start_time ) { -#endif - s[i].restart_count = 0; - } - } -} - -void timekeeping_array_push(void * array, size_t index, LONG_LONG time) -{ -#ifdef FULL_TIMEKEEPING - size_t i; - size_t time_count; -#endif - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return; - -#ifndef FULL_TIMEKEEPING - if ( !s[index].count++ ) - s[index].first_time = time; -#else - time_count = ( s[index].count + 16 ) & ~15; - - s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count ); - - s[index].times[s[index].count++] = time; -#endif -} - -void timekeeping_array_bump(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return; - - s[index].restart_count++; -} - -unsigned int timekeeping_array_get_count(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return 0; - - return s[index].count; -} - -LONG_LONG timekeeping_array_get_item(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size || s[index].restart_count >= s[index].count) return 0; - -#ifndef FULL_TIMEKEEPING - return s[index].first_time; -#else - return s[index].times[s[index].restart_count]; -#endif -} diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 99f8bdc13..0a7feae3c 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -352,8 +352,6 @@ static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_chan #ifdef BIT_ARRAY_BULLSHIT dst->played = bit_array_dup(src->played); - - dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper); #endif dst->gvz_time = src->gvz_time; @@ -2219,9 +2217,6 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); #endif sigrenderer->speed = 0; -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) return 1; } @@ -4242,10 +4237,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) */ #endif bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); - if (sigrenderer->looped == 0) { - timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played); - } - timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); { int n; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) @@ -4343,8 +4334,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) /* Fix play tracking and timekeeping for orders containing skip commands */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, sigrenderer->processorder * 256 + n); - timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n, sigrenderer->time_played); - timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n); } #endif } @@ -4369,9 +4358,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) && bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow) #endif ) { -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if (sigrenderer->callbacks->loop) { if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) return 1; @@ -4466,9 +4452,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) sigrenderer->gvz_time += (int)(t >> 16); sigrenderer->gvz_sub_time = (int)t & 65535; if (sigrenderer->gvz_time >= 65536 * 12) { -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data)) return 1; } @@ -5283,10 +5266,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha #ifdef BIT_ARRAY_BULLSHIT sigrenderer->played = bit_array_create(sigdata->n_orders * 256); - - sigrenderer->looped = 0; - sigrenderer->time_played = 0; - sigrenderer->row_timekeeper = timekeeping_array_create(sigdata->n_orders * 256); #endif { @@ -5305,8 +5284,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha /* Fix for played order detection for songs which have skips at the start of the orders list */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, order * 256 + n); - timekeeping_array_push(sigrenderer->row_timekeeper, order * 256 + n, 0); - timekeeping_array_bump(sigrenderer->row_timekeeper, order * 256 + n); } #endif } @@ -5319,6 +5296,10 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha sigrenderer->time_left = 0; sigrenderer->sub_time_left = 0; +#ifdef BIT_ARRAY_BULLSHIT + sigrenderer->played = bit_array_create(sigdata->n_orders * 256); +#endif + sigrenderer->gvz_time = 0; sigrenderer->gvz_sub_time = 0; @@ -5504,8 +5485,7 @@ static int32 it_sigrenderer_get_samples( int32 pos; int dt; int32 todo; - int ret; - LONG_LONG time_left, t; + LONG_LONG t; if (sigrenderer->order < 0) return 0; // problematic @@ -5518,8 +5498,7 @@ static int32 it_sigrenderer_get_samples( if (!samples) volume = 0; for (;;) { - time_left = ((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left; - todo = (long)(time_left / dt); + todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt); if (todo >= size) break; @@ -5533,28 +5512,9 @@ static int32 it_sigrenderer_get_samples( sigrenderer->sub_time_left = (int32)t & 65535; sigrenderer->time_left += (int32)(t >> 16); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += time_left; -#endif - - ret = process_tick(sigrenderer); - - if (ret) { + if (process_tick(sigrenderer)) { sigrenderer->order = -1; sigrenderer->row = -1; - } - -#ifdef BIT_ARRAY_BULLSHIT - if (sigrenderer->looped == 1) { - sigrenderer->looped = -1; - size = 0; - timekeeping_array_reset(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); - sigrenderer->time_played = timekeeping_array_get_item(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); - break; - } -#endif - - if (ret) { return pos; } } @@ -5567,10 +5527,6 @@ static int32 it_sigrenderer_get_samples( sigrenderer->sub_time_left = (int32)t & 65535; sigrenderer->time_left += (int32)(t >> 16); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)size * dt; -#endif - if (samples) dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta); @@ -5622,8 +5578,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) #ifdef BIT_ARRAY_BULLSHIT bit_array_destroy(sigrenderer->played); - - timekeeping_array_destroy(sigrenderer->row_timekeeper); #endif free(vsigrenderer); @@ -5632,17 +5586,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) -#ifdef BIT_ARRAY_BULLSHIT -static int32 it_sigrenderer_get_position(sigrenderer_t *vsigrenderer) -{ - DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer; - - return (int32)(sigrenderer->time_played >> 16); -} -#endif - - - DUH_SIGTYPE_DESC _dumb_sigtype_it = { SIGTYPE_IT, NULL, @@ -5650,11 +5593,6 @@ DUH_SIGTYPE_DESC _dumb_sigtype_it = { NULL, &it_sigrenderer_get_samples, &it_sigrenderer_get_current_sample, -#ifdef BIT_ARRAY_BULLSHIT - &it_sigrenderer_get_position, -#else - NULL, -#endif &_dumb_it_end_sigrenderer, &_dumb_it_unload_sigdata }; diff --git a/dumb/vc6/dumb/dumb.vcxproj b/dumb/vc6/dumb/dumb.vcxproj index 6e49557cf..ae8ebdb0b 100644 --- a/dumb/vc6/dumb/dumb.vcxproj +++ b/dumb/vc6/dumb/dumb.vcxproj @@ -118,7 +118,6 @@ - @@ -210,7 +209,6 @@ - diff --git a/dumb/vc6/dumb/dumb.vcxproj.filters b/dumb/vc6/dumb/dumb.vcxproj.filters index 167393748..422556dc2 100644 --- a/dumb/vc6/dumb/dumb.vcxproj.filters +++ b/dumb/vc6/dumb/dumb.vcxproj.filters @@ -279,9 +279,6 @@ src\helpers - - src\helpers - @@ -314,9 +311,6 @@ include\internal - - include\internal - From 3d83ed2ee5d7ff219a8f8895c148fe5ae2a040e0 Mon Sep 17 00:00:00 2001 From: Tuomas Virtanen Date: Thu, 25 Jun 2015 16:00:13 +0300 Subject: [PATCH 173/335] Change dumb.h version information to match release version Conflicts: dumb/include/dumb.h --- dumb/include/dumb.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index 2b6ac4879..385335da7 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -36,24 +36,24 @@ #endif -#define DUMB_MAJOR_VERSION 0 -#define DUMB_MINOR_VERSION 9 -#define DUMB_REVISION_VERSION 3 +#define DUMB_MAJOR_VERSION 1 +#define DUMB_MINOR_VERSION 0 +#define DUMB_REVISION_VERSION 0 #define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION) -#define DUMB_VERSION_STR "0.9.3" +#define DUMB_VERSION_STR "1.0.0" #define DUMB_NAME "DUMB v" DUMB_VERSION_STR -#define DUMB_YEAR 2005 -#define DUMB_MONTH 8 -#define DUMB_DAY 7 +#define DUMB_YEAR 2015 +#define DUMB_MONTH 1 +#define DUMB_DAY 17 -#define DUMB_YEAR_STR2 "05" -#define DUMB_YEAR_STR4 "2005" -#define DUMB_MONTH_STR1 "8" -#define DUMB_DAY_STR1 "7" +#define DUMB_YEAR_STR2 "15" +#define DUMB_YEAR_STR4 "2015" +#define DUMB_MONTH_STR1 "1" +#define DUMB_DAY_STR1 "17" #if DUMB_MONTH < 10 #define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1 From 865f083128744bbc02cb9b1164dae0d3a91f9fa7 Mon Sep 17 00:00:00 2001 From: Chris Spiegel Date: Mon, 10 Aug 2015 21:07:17 -0700 Subject: [PATCH 174/335] Fix memory leaks. --- dumb/src/it/readptm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dumb/src/it/readptm.c b/dumb/src/it/readptm.c index 885929e42..9b34861db 100644 --- a/dumb/src/it/readptm.c +++ b/dumb/src/it/readptm.c @@ -439,6 +439,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) } if (dumbfile_seek(f, 352, DFS_SEEK_SET)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } @@ -451,12 +452,14 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) } if (dumbfile_seek(f, 608, DFS_SEEK_SET)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } for (n = 0; n < sigdata->n_samples; n++) { if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } From 45e031170e55cd06ecd4ed657a3f458151669a48 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Sat, 8 Aug 2015 21:26:05 -0700 Subject: [PATCH 175/335] Implement missing n_pchannels for AMF format reader --- dumb/src/it/readamf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dumb/src/it/readamf.c b/dumb/src/it/readamf.c index 83f6075e7..820709e9d 100644 --- a/dumb/src/it/readamf.c +++ b/dumb/src/it/readamf.c @@ -320,6 +320,8 @@ static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version) free( sigdata ); return NULL; } + + sigdata->n_pchannels = nchannels; memset( sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS ); From e5a4031a7010ac42559bfbcab5ffb71d1440e805 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 14 Aug 2015 20:07:02 -0700 Subject: [PATCH 176/335] Fixed another memory leak in an error handler --- dumb/src/it/readxm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index a06fd1e99..0c838ade8 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -1197,6 +1197,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); if (!sigdata->instrument) { + free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; } From 17a216c832f1584355a777343b60202cff2342fa Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 9 Oct 2015 17:59:30 -0700 Subject: [PATCH 177/335] Fix issue #15 / CVE-2006-3668 --- dumb/src/it/itread.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index e8661807e..ca1dde55d 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -290,12 +290,15 @@ static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) envelope->flags = dumbfile_getc(f); envelope->n_nodes = dumbfile_getc(f); + if(envelope->n_nodes > 25) { + TRACE("IT error: wrong number of envelope nodes (%d)\n", envelope->n_nodes); + envelope->n_nodes = 0; + return -1; + } envelope->loop_start = dumbfile_getc(f); envelope->loop_end = dumbfile_getc(f); envelope->sus_loop_start = dumbfile_getc(f); envelope->sus_loop_end = dumbfile_getc(f); - if (envelope->n_nodes > 25) - envelope->n_nodes = 25; for (n = 0; n < envelope->n_nodes; n++) { envelope->node_y[n] = dumbfile_getc(f); envelope->node_t[n] = dumbfile_igetw(f); From 792d3906fd2be890a2f17c8a90f097981cdbc143 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Dec 2015 20:32:41 +0100 Subject: [PATCH 178/335] - fixed: line activation checks for monster activation could be skipped if the lines also were flagged for player activation. --- src/p_spec.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 9bc0d4a9b..e2cc0025b 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -288,16 +288,16 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType) } } + if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) + { + return true; + } + if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) + { + return true; + } if ((lineActivation & activationType) == 0) { - if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) - { - return true; - } - if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) - { - return true; - } if (activationType != SPAC_MCross || lineActivation != SPAC_Cross) { return false; From 03ccf03b8f3161a601cd223a3abfcf345da79f16 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Dec 2015 01:13:21 +0100 Subject: [PATCH 179/335] - fixed: UDMF with Doom format specials used the line's ID, not the first arg as the tag parameter for its special. --- src/p_udmf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 269ce7e3d..db0c952cf 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -785,7 +785,7 @@ public: bool strifetrans = false; bool strifetrans2 = false; FString arg0str, arg1str; - int lineid; // forZDoomTranslated namespace + int lineid = -1; // forZDoomTranslated namespace FString tagstring; memset(ld, 0, sizeof(*ld)); @@ -1082,7 +1082,7 @@ public: maplinedef_t mld; memset(&mld, 0, sizeof(mld)); mld.special = ld->special; - mld.tag = lineid; + mld.tag = ld->args[0]; P_TranslateLineDef(ld, &mld); ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY)); } From c51abb01610fc6eb399da8139eca83856fd3a5b5 Mon Sep 17 00:00:00 2001 From: Blue-Shadow Date: Tue, 22 Dec 2015 19:01:09 +0300 Subject: [PATCH 180/335] Added GetMaxInventory ACS function --- src/p_acs.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 30733eac8..b94d63b79 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1264,7 +1264,7 @@ static int UseInventory (AActor *activator, const char *type) // //============================================================================ -static int CheckInventory (AActor *activator, const char *type) +static int CheckInventory (AActor *activator, const char *type, bool max) { if (activator == NULL || type == NULL) return 0; @@ -1275,11 +1275,26 @@ static int CheckInventory (AActor *activator, const char *type) } else if (stricmp (type, "Health") == 0) { + if (max) + { + if (activator->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + return static_cast(activator)->MaxHealth; + else + return activator->SpawnHealth(); + } return activator->health; } const PClass *info = PClass::FindClass (type); AInventory *item = activator->FindInventory (info); + + if (max) + { + if (item) + return item->MaxAmount; + else + return ((AInventory *)GetDefaultByType (info))->MaxAmount; + } return item ? item->Amount : 0; } @@ -4442,6 +4457,7 @@ enum EACSFunctions ACSF_GetActorRoll, ACSF_QuakeEx, ACSF_Warp, // 92 + ACSF_GetMaxInventory, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5915,6 +5931,13 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } return false; } + case ACSF_GetMaxInventory: + actor = SingleActorFromTID(args[0], activator); + if (actor != NULL) + { + return CheckInventory(actor, FBehavior::StaticLookupString(args[1]), true); + } + break; default: break; @@ -8339,17 +8362,17 @@ scriptwait: break; case PCD_CHECKINVENTORY: - STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1))); + STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1)), false); break; case PCD_CHECKACTORINVENTORY: STACK(2) = CheckInventory (SingleActorFromTID(STACK(2), NULL), - FBehavior::StaticLookupString (STACK(1))); + FBehavior::StaticLookupString (STACK(1)), false); sp--; break; case PCD_CHECKINVENTORYDIRECT: - PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))))); + PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))), false)); pc += 1; break; From beb7a8e4a2ace28fda777d59f5fcbda785713e65 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Dec 2015 22:21:59 +0100 Subject: [PATCH 181/335] - added /LARGEADDRESSAWARE linker flag to CMake project. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd2c7730f..3e375a2df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME if( MSVC ) # Eliminate unreferenced functions and data # Perform identical COMDAT folding - set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE" ) + set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE /LARGEADDRESSAWARE" ) # String pooling # Function-level linking From 400038643cab557e828881c716d0f08820accd69 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Dec 2015 15:31:59 +0100 Subject: [PATCH 182/335] - fixed: Strife dialogues could crash on invalid links. --- src/p_conversation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 069fca6e1..85edc53ab 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1347,9 +1347,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply int rootnode = npc->ConversationRoot; if (reply->NextNode < 0) { - npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1]; - if (gameaction != ga_slideshow) + unsigned next = (unsigned)(rootnode - reply->NextNode - 1); + if (gameaction != ga_slideshow && next < StrifeDialogues.Size()) { + npc->Conversation = StrifeDialogues[next]; P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); return; } From 1070bd9beb9e17de359486fbed201dd330b29a6f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Dec 2015 16:17:56 +0100 Subject: [PATCH 183/335] - fixed: APlayerPawn::ViewHeight wasn't stored in savegames. --- src/p_user.cpp | 4 ++++ src/version.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 0d5cdce20..331a978b7 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -566,6 +566,10 @@ void APlayerPawn::Serialize (FArchive &arc) { arc << AirCapacity; } + if (SaveVersion >= 4526) + { + arc << ViewHeight; + } } //=========================================================================== diff --git a/src/version.h b/src/version.h index 168cb7519..c1288f02f 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4525 +#define SAVEVER 4526 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 5346b813da90a59d2a7a7c47195e9346fc6c23da Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sun, 27 Dec 2015 09:48:22 -0600 Subject: [PATCH 184/335] Re-do GTK2_LIBARY_DIRS inclusion on a separate branch --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd353a2ed..bd4f625dc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -187,6 +187,7 @@ else( WIN32 ) if( GTK2_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) include_directories( ${GTK2_INCLUDE_DIRS} ) + link_directories( ${GTK2_LIBRARY_DIRS} ) else( GTK2_FOUND ) set( NO_GTK ON ) endif( GTK2_FOUND ) From 33a252bf4bcd6189a655c4f44ab44f8aa9e95a7c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Dec 2015 21:52:44 -0600 Subject: [PATCH 185/335] Add /LARGEADDRESSAWARE to VC2005 project --- zdoom.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zdoom.vcproj b/zdoom.vcproj index d802fc61c..db4660d3b 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -106,6 +106,7 @@ MapExports="true" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" OptimizeReferences="2" EnableCOMDATFolding="2" @@ -223,6 +224,7 @@ MapExports="true" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" OptimizeReferences="2" EnableCOMDATFolding="2" @@ -332,6 +334,7 @@ ProgramDatabaseFile=".\Debug/zdoomd.pdb" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" SetChecksum="false" TargetMachine="0" @@ -440,6 +443,7 @@ ProgramDatabaseFile=".\Debug/zdoomd.pdb" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" SetChecksum="false" TargetMachine="17" From 060a6b2ff2b9716eee79f09187f59a41eacda616 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Dec 2015 21:23:21 +0100 Subject: [PATCH 186/335] - shut down WildMidi when exiting. The pointless error message in WildMidi_Shutdown was removed to keep the rest of the code simple and allowing to call this even when the device never was used. --- src/sound/i_music.cpp | 1 + src/wildmidi/wildmidi_lib.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 3f8fac0da..721be5192 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -189,6 +189,7 @@ void I_ShutdownMusic(void) assert (currSong == NULL); } Timidity::FreeAll(); + WildMidi_Shutdown(); #ifdef _WIN32 I_ShutdownMusicWin32(); #endif // _WIN32 diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 84c2f382a..b5ea6b887 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -4261,8 +4261,8 @@ WildMidi_GetInfo(midi * handle) { WM_SYMBOL int WildMidi_Shutdown(void) { if (!WM_Initialized) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); - return -1; + // No error if trying to shut down an uninitialized device. + return 0; } while (first_handle) { /* closes open handle and rotates the handles list. */ From a2ebf771d30ed75413e746128a6057ea249ddae9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 28 Dec 2015 19:13:34 -0600 Subject: [PATCH 187/335] Remove '\r' character from beginning of WildMidi error messages --- src/wildmidi/wm_error.cpp | 8 ++--- zdoom.vcproj | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/wildmidi/wm_error.cpp b/src/wildmidi/wm_error.cpp index 9fabdff84..eab56c437 100644 --- a/src/wildmidi/wm_error.cpp +++ b/src/wildmidi/wm_error.cpp @@ -67,18 +67,18 @@ void _WM_ERROR(const char * func, unsigned int lne, int wmerno, if (wmfor != NULL) { if (error != 0) { - Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s (%s)\n", func, + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s (%s)\n", func, lne, errors[wmerno], wmfor, strerror(error)); } else { - Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s\n", func, lne, + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s\n", func, lne, errors[wmerno], wmfor); } } else { if (error != 0) { - Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s (%s)\n", func, lne, + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s (%s)\n", func, lne, errors[wmerno], strerror(error)); } else { - Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s\n", func, lne, + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s\n", func, lne, errors[wmerno]); } } diff --git a/zdoom.vcproj b/zdoom.vcproj index db4660d3b..126efb7f5 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2553,6 +2553,10 @@ RelativePath="src\sound\music_midi_timidity.cpp" > + + @@ -2789,6 +2793,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Mon, 28 Dec 2015 20:33:41 -0600 Subject: [PATCH 188/335] Separate WildMidi mixing from event handling - In order to use ZDoom's own MIDI sequencer event handling must be completely separate from mixing, but WildMidi had them intertwined because it wasn't designed for external sequencers. - Also remove all 'long's defining the output buffers to avoid having something that's 32 bits wide on Windows and 64 bits wide on Linux. --- src/wildmidi/reverb.cpp | 32 +- src/wildmidi/reverb.h | 16 +- src/wildmidi/wildmidi_lib.cpp | 884 +++++++++++++++++----------------- 3 files changed, 473 insertions(+), 459 deletions(-) diff --git a/src/wildmidi/reverb.cpp b/src/wildmidi/reverb.cpp index d183a1c71..6c6af88d4 100644 --- a/src/wildmidi/reverb.cpp +++ b/src/wildmidi/reverb.cpp @@ -269,23 +269,23 @@ _WM_init_reverb(int rate, float room_x, float room_y, float listen_x, double a1 = -2 * cs; double a2 = 1 - (alpha / A); - rtn_rvb->coeff[j][i][0] = (signed long int) ((b0 / a0) * 1024.0); - rtn_rvb->coeff[j][i][1] = (signed long int) ((b1 / a0) * 1024.0); - rtn_rvb->coeff[j][i][2] = (signed long int) ((b2 / a0) * 1024.0); - rtn_rvb->coeff[j][i][3] = (signed long int) ((a1 / a0) * 1024.0); - rtn_rvb->coeff[j][i][4] = (signed long int) ((a2 / a0) * 1024.0); + rtn_rvb->coeff[j][i][0] = (signed int) ((b0 / a0) * 1024.0); + rtn_rvb->coeff[j][i][1] = (signed int) ((b1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][2] = (signed int) ((b2 / a0) * 1024.0); + rtn_rvb->coeff[j][i][3] = (signed int) ((a1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][4] = (signed int) ((a2 / a0) * 1024.0); } } /* init the reverb buffers */ rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29)); - rtn_rvb->l_buf = (long*)malloc( - sizeof(signed long int) * (rtn_rvb->l_buf_size + 1)); + rtn_rvb->l_buf = (int*)malloc( + sizeof(signed int) * (rtn_rvb->l_buf_size + 1)); rtn_rvb->l_out = 0; rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29)); - rtn_rvb->r_buf = (long*)malloc( - sizeof(signed long int) * (rtn_rvb->r_buf_size + 1)); + rtn_rvb->r_buf = (int*)malloc( + sizeof(signed int) * (rtn_rvb->r_buf_size + 1)); rtn_rvb->r_out = 0; for (i = 0; i < 4; i++) { @@ -313,17 +313,17 @@ void _WM_free_reverb(struct _rvb *rvb) { free(rvb); } -void _WM_do_reverb(struct _rvb *rvb, signed long int *buffer, int size) { +void _WM_do_reverb(struct _rvb *rvb, signed int *buffer, int size) { int i, j, k; - signed long int l_buf_flt = 0; - signed long int r_buf_flt = 0; - signed long int l_rfl = 0; - signed long int r_rfl = 0; + signed int l_buf_flt = 0; + signed int r_buf_flt = 0; + signed int l_rfl = 0; + signed int r_rfl = 0; int vol_div = 64; for (i = 0; i < size; i += 2) { - signed long int tmp_l_val = 0; - signed long int tmp_r_val = 0; + signed int tmp_l_val = 0; + signed int tmp_r_val = 0; /* add the initial reflections from each speaker, 4 to go the left, 4 go to the right buffers diff --git a/src/wildmidi/reverb.h b/src/wildmidi/reverb.h index b8f5a6333..162de61eb 100644 --- a/src/wildmidi/reverb.h +++ b/src/wildmidi/reverb.h @@ -29,14 +29,14 @@ struct _rvb { /* filter data */ - signed long int l_buf_flt_in[8][6][2]; - signed long int l_buf_flt_out[8][6][2]; - signed long int r_buf_flt_in[8][6][2]; - signed long int r_buf_flt_out[8][6][2]; - signed long int coeff[8][6][5]; + signed int l_buf_flt_in[8][6][2]; + signed int l_buf_flt_out[8][6][2]; + signed int r_buf_flt_in[8][6][2]; + signed int r_buf_flt_out[8][6][2]; + signed int coeff[8][6][5]; /* buffer data */ - signed long int *l_buf; - signed long int *r_buf; + signed int *l_buf; + signed int *r_buf; int l_buf_size; int r_buf_size; int l_out; @@ -52,6 +52,6 @@ struct _rvb { extern void _WM_reset_reverb (struct _rvb *rvb); extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y); extern void _WM_free_reverb (struct _rvb *rvb); - extern void _WM_do_reverb (struct _rvb *rvb, signed long int *buffer, int size); + extern void _WM_do_reverb (struct _rvb *rvb, signed int *buffer, int size); #endif /* __REVERB_H */ diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index b5ea6b887..b1ec8b459 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -182,7 +182,7 @@ struct _mdi { unsigned long int patch_count; signed short int amp; - signed long int *mix_buffer; + signed int *mix_buffer; unsigned long int mix_buffer_size; struct _rvb *reverb; @@ -3203,20 +3203,216 @@ _end: free(sysex_store); return NULL; } +static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) +{ + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int data_pos; + signed int premix, left_mix, right_mix; + signed int vol_mul; + struct _note *note_data = NULL; + + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((note_data != NULL), 1)) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + vol_mul = ((note_data->vol_lvl + * (note_data->env_level >> 12)) >> FPBITS); + + premix = (note_data->sample->data[data_pos] + + ((note_data->sample->data[data_pos + 1] + - note_data->sample->data[data_pos]) + * (signed long int) (note_data->sample_pos + & FPMASK)>> FPBITS)) * vol_mul + / 1024; + + left_mix += premix + * mdi->channel[note_data->noteid >> 8].left_adjust; + right_mix += premix + * mdi->channel[note_data->noteid >> 8].right_adjust; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (__builtin_expect( + (note_data->sample_pos > note_data->sample->loop_end), + 0)) { + if (note_data->modes & SAMPLE_LOOP) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } else if (__builtin_expect( + (note_data->sample_pos + >= note_data->sample->data_length), + 0)) { + if (__builtin_expect((note_data->replay == NULL), 1)) { + goto KILL_NOTE; + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect((note_data->env_inc == 0), 0)) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (__builtin_expect((note_data->env_level > 4194304), 0)) { + note_data->env_level = + note_data->sample->env_target[note_data->env]; + } + if (__builtin_expect( + ((note_data->env_inc < 0) + && (note_data->env_level + > note_data->sample->env_target[note_data->env])) + || ((note_data->env_inc > 0) + && (note_data->env_level + < note_data->sample->env_target[note_data->env])), + 1)) { + note_data = note_data->next; + continue; + } + + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: +#if 0 + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } +#endif + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (__builtin_expect((note_data->env_level == 0), 1)) { + goto KILL_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + if (__builtin_expect((note_data->replay != NULL), 1)) { + RESTART_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + KILL_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + left_mix /= 1024; + right_mix /= 1024; + } + + *buffer++ = left_mix; + *buffer++ = right_mix; + } while (--count); + return buffer; +} + static int WM_GetOutput_Linear(midi * handle, char * buffer, unsigned long int size) { unsigned long int buffer_used = 0; unsigned long int i; struct _mdi *mdi = (struct _mdi *) handle; unsigned long int real_samples_to_mix = 0; - unsigned long int data_pos; - signed long int premix, left_mix, right_mix; - signed long int vol_mul; - struct _note *note_data = NULL; - unsigned long int count; struct _event *event = mdi->current_event; - signed long int *tmp_buffer; - signed long int *out_buffer; + int *tmp_buffer; + int *out_buffer; + int left_mix, right_mix; _WM_Lock(&mdi->lock); @@ -3229,7 +3425,7 @@ static int WM_GetOutput_Linear(midi * handle, char * buffer, } else { mdi->mix_buffer_size = size / 2; } - mdi->mix_buffer = (long*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed long int)); + mdi->mix_buffer = (int*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed int)); } tmp_buffer = mdi->mix_buffer; @@ -3269,196 +3465,7 @@ static int WM_GetOutput_Linear(midi * handle, char * buffer, } /* do mixing here */ - count = real_samples_to_mix; - do { - note_data = mdi->note; - left_mix = right_mix = 0; - if (__builtin_expect((note_data != NULL), 1)) { - while (note_data) { - /* - * =================== - * resample the sample - * =================== - */ - data_pos = note_data->sample_pos >> FPBITS; - vol_mul = ((note_data->vol_lvl - * (note_data->env_level >> 12)) >> FPBITS); - - premix = (note_data->sample->data[data_pos] - + ((note_data->sample->data[data_pos + 1] - - note_data->sample->data[data_pos]) - * (signed long int) (note_data->sample_pos - & FPMASK)>> FPBITS)) * vol_mul - / 1024; - - left_mix += premix - * mdi->channel[note_data->noteid >> 8].left_adjust; - right_mix += premix - * mdi->channel[note_data->noteid >> 8].right_adjust; - - /* - * ======================== - * sample position checking - * ======================== - */ - note_data->sample_pos += note_data->sample_inc; - if (__builtin_expect( - (note_data->sample_pos > note_data->sample->loop_end), - 0)) { - if (note_data->modes & SAMPLE_LOOP) { - note_data->sample_pos = - note_data->sample->loop_start - + ((note_data->sample_pos - - note_data->sample->loop_start) - % note_data->sample->loop_size); - } else if (__builtin_expect( - (note_data->sample_pos - >= note_data->sample->data_length), - 0)) { - if (__builtin_expect((note_data->replay == NULL), 1)) { - goto KILL_NOTE; - } - goto RESTART_NOTE; - } - } - - if (__builtin_expect((note_data->env_inc == 0), 0)) { - note_data = note_data->next; - continue; - } - - note_data->env_level += note_data->env_inc; - if (__builtin_expect((note_data->env_level > 4194304), 0)) { - note_data->env_level = - note_data->sample->env_target[note_data->env]; - } - if (__builtin_expect( - ((note_data->env_inc < 0) - && (note_data->env_level - > note_data->sample->env_target[note_data->env])) - || ((note_data->env_inc > 0) - && (note_data->env_level - < note_data->sample->env_target[note_data->env])), - 1)) { - note_data = note_data->next; - continue; - } - - note_data->env_level = - note_data->sample->env_target[note_data->env]; - switch (note_data->env) { - case 0: -#if 0 - if (!(note_data->modes & SAMPLE_ENVELOPE)) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } -#endif - break; - case 2: - if (note_data->modes & SAMPLE_SUSTAIN) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } else if (note_data->modes & SAMPLE_CLAMPED) { - note_data->env = 5; - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - continue; - } - break; - case 5: - if (__builtin_expect((note_data->env_level == 0), 1)) { - goto KILL_NOTE; - } - /* sample release */ - if (note_data->modes & SAMPLE_LOOP) - note_data->modes ^= SAMPLE_LOOP; - note_data->env_inc = 0; - note_data = note_data->next; - continue; - case 6: - if (__builtin_expect((note_data->replay != NULL), 1)) { - RESTART_NOTE: note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while (nte_array != note_data); - } - if (prev_note) { - prev_note->next = note_data->replay; - } else { - mdi->note = note_data->replay; - } - note_data->replay->next = note_data->next; - note_data = note_data->replay; - note_data->active = 1; - } - } else { - KILL_NOTE: note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while ((nte_array != note_data) - && (nte_array)); - } - if (prev_note) { - prev_note->next = note_data->next; - } else { - mdi->note = note_data->next; - } - note_data = note_data->next; - } - } - continue; - } - note_data->env++; - - if (note_data->is_off == 1) { - do_note_off_extra(note_data); - } - - if (note_data->env_level - > note_data->sample->env_target[note_data->env]) { - note_data->env_inc = - -note_data->sample->env_rate[note_data->env]; - } else { - note_data->env_inc = - note_data->sample->env_rate[note_data->env]; - } - note_data = note_data->next; - continue; - } - - /* - * ========================= - * mix the channels together - * ========================= - */ - left_mix /= 1024; - right_mix /= 1024; - } - - *tmp_buffer++ = left_mix; - *tmp_buffer++ = right_mix; - } while (--count); + tmp_buffer = WM_Mix_Linear(handle, tmp_buffer, real_samples_to_mix); buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); @@ -3503,25 +3510,254 @@ static int WM_GetOutput_Linear(midi * handle, char * buffer, return buffer_used; } +static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) +{ + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int data_pos; + signed int premix, left_mix, right_mix; + signed int vol_mul; + struct _note *note_data = NULL; + signed short int *sptr; + double y, xd; + double *gptr, *gend; + int left, right, temp_n; + int ii, jj; + + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((note_data != NULL), 1)) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + vol_mul = ((note_data->vol_lvl + * (note_data->env_level >> 12)) >> FPBITS); + + /* check to see if we're near one of the ends */ + left = data_pos; + right = (note_data->sample->data_length >> FPBITS) - left + - 1; + temp_n = (right << 1) - 1; + if (temp_n <= 0) + temp_n = 1; + if (temp_n > (left << 1) + 1) + temp_n = (left << 1) + 1; + + /* use Newton if we can't fill the window */ + if (temp_n < gauss_n) { + xd = note_data->sample_pos & FPMASK; + xd /= (1L << FPBITS); + xd += temp_n >> 1; + y = 0; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (temp_n >> 1); + for (ii = temp_n; ii;) { + for (jj = 0; jj <= ii; jj++) + y += sptr[jj] * newt_coeffs[ii][jj]; + y *= xd - --ii; + } + y += *sptr; + } else { /* otherwise, use Gauss as usual */ + y = 0; + gptr = &gauss_table[(note_data->sample_pos & FPMASK) * + (gauss_n + 1)]; + gend = gptr + gauss_n; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (gauss_n >> 1); + do { + y += *(sptr++) * *(gptr++); + } while (gptr <= gend); + } + + premix = (long) (y * vol_mul / 1024); + + left_mix += premix + * mdi->channel[note_data->noteid >> 8].left_adjust; + right_mix += premix + * mdi->channel[note_data->noteid >> 8].right_adjust; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (__builtin_expect( + (note_data->sample_pos > note_data->sample->loop_end), + 0)) { + if (note_data->modes & SAMPLE_LOOP) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } else if (__builtin_expect( + (note_data->sample_pos + >= note_data->sample->data_length), + 0)) { + if (__builtin_expect((note_data->replay == NULL), 1)) { + goto KILL_NOTE; + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect((note_data->env_inc == 0), 0)) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (__builtin_expect((note_data->env_level > 4194304), 0)) { + note_data->env_level = + note_data->sample->env_target[note_data->env]; + } + if (__builtin_expect( + ((note_data->env_inc < 0) + && (note_data->env_level + > note_data->sample->env_target[note_data->env])) + || ((note_data->env_inc > 0) + && (note_data->env_level + < note_data->sample->env_target[note_data->env])), + 1)) { + note_data = note_data->next; + continue; + } + + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: +#if 0 + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } +#endif + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (__builtin_expect((note_data->env_level == 0), 1)) { + goto KILL_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + if (__builtin_expect((note_data->replay != NULL), 1)) { + RESTART_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + KILL_NOTE: note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + left_mix /= 1024; + right_mix /= 1024; + } + + *buffer++ = left_mix; + *buffer++ = right_mix; + } while (--count); + return buffer; +} + static int WM_GetOutput_Gauss(midi * handle, char * buffer, unsigned long int size) { unsigned long int buffer_used = 0; unsigned long int i; struct _mdi *mdi = (struct _mdi *) handle; unsigned long int real_samples_to_mix = 0; - unsigned long int data_pos; - signed long int premix, left_mix, right_mix; - signed long int vol_mul; - struct _note *note_data = NULL; - unsigned long int count; - signed short int *sptr; - double y, xd; - double *gptr, *gend; - int left, right, temp_n; - int ii, jj; struct _event *event = mdi->current_event; - signed long int *tmp_buffer; - signed long int *out_buffer; + signed int *tmp_buffer; + signed int *out_buffer; + signed int left_mix, right_mix; _WM_Lock(&mdi->lock); @@ -3533,7 +3769,7 @@ static int WM_GetOutput_Gauss(midi * handle, char * buffer, } else { mdi->mix_buffer_size = size / 2; } - mdi->mix_buffer = (long*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed long int)); + mdi->mix_buffer = (int*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed int)); } tmp_buffer = mdi->mix_buffer; memset(tmp_buffer, 0, ((size / 2) * sizeof(signed long int))); @@ -3571,229 +3807,7 @@ static int WM_GetOutput_Gauss(midi * handle, char * buffer, } /* do mixing here */ - count = real_samples_to_mix; - do { - note_data = mdi->note; - left_mix = right_mix = 0; - if (__builtin_expect((note_data != NULL), 1)) { - while (note_data) { - /* - * =================== - * resample the sample - * =================== - */ - data_pos = note_data->sample_pos >> FPBITS; - vol_mul = ((note_data->vol_lvl - * (note_data->env_level >> 12)) >> FPBITS); - - /* check to see if we're near one of the ends */ - left = data_pos; - right = (note_data->sample->data_length >> FPBITS) - left - - 1; - temp_n = (right << 1) - 1; - if (temp_n <= 0) - temp_n = 1; - if (temp_n > (left << 1) + 1) - temp_n = (left << 1) + 1; - - /* use Newton if we can't fill the window */ - if (temp_n < gauss_n) { - xd = note_data->sample_pos & FPMASK; - xd /= (1L << FPBITS); - xd += temp_n >> 1; - y = 0; - sptr = note_data->sample->data - + (note_data->sample_pos >> FPBITS) - - (temp_n >> 1); - for (ii = temp_n; ii;) { - for (jj = 0; jj <= ii; jj++) - y += sptr[jj] * newt_coeffs[ii][jj]; - y *= xd - --ii; - } - y += *sptr; - } else { /* otherwise, use Gauss as usual */ - y = 0; - gptr = &gauss_table[(note_data->sample_pos & FPMASK) * - (gauss_n + 1)]; - gend = gptr + gauss_n; - sptr = note_data->sample->data - + (note_data->sample_pos >> FPBITS) - - (gauss_n >> 1); - do { - y += *(sptr++) * *(gptr++); - } while (gptr <= gend); - } - - premix = (long) (y * vol_mul / 1024); - - left_mix += premix - * mdi->channel[note_data->noteid >> 8].left_adjust; - right_mix += premix - * mdi->channel[note_data->noteid >> 8].right_adjust; - - /* - * ======================== - * sample position checking - * ======================== - */ - note_data->sample_pos += note_data->sample_inc; - if (__builtin_expect( - (note_data->sample_pos > note_data->sample->loop_end), - 0)) { - if (note_data->modes & SAMPLE_LOOP) { - note_data->sample_pos = - note_data->sample->loop_start - + ((note_data->sample_pos - - note_data->sample->loop_start) - % note_data->sample->loop_size); - } else if (__builtin_expect( - (note_data->sample_pos - >= note_data->sample->data_length), - 0)) { - if (__builtin_expect((note_data->replay == NULL), 1)) { - goto KILL_NOTE; - } - goto RESTART_NOTE; - } - } - - if (__builtin_expect((note_data->env_inc == 0), 0)) { - note_data = note_data->next; - continue; - } - - note_data->env_level += note_data->env_inc; - if (__builtin_expect((note_data->env_level > 4194304), 0)) { - note_data->env_level = - note_data->sample->env_target[note_data->env]; - } - if (__builtin_expect( - ((note_data->env_inc < 0) - && (note_data->env_level - > note_data->sample->env_target[note_data->env])) - || ((note_data->env_inc > 0) - && (note_data->env_level - < note_data->sample->env_target[note_data->env])), - 1)) { - note_data = note_data->next; - continue; - } - - note_data->env_level = - note_data->sample->env_target[note_data->env]; - switch (note_data->env) { - case 0: -#if 0 - if (!(note_data->modes & SAMPLE_ENVELOPE)) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } -#endif - break; - case 2: - if (note_data->modes & SAMPLE_SUSTAIN) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } else if (note_data->modes & SAMPLE_CLAMPED) { - note_data->env = 5; - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - continue; - } - break; - case 5: - if (__builtin_expect((note_data->env_level == 0), 1)) { - goto KILL_NOTE; - } - /* sample release */ - if (note_data->modes & SAMPLE_LOOP) - note_data->modes ^= SAMPLE_LOOP; - note_data->env_inc = 0; - note_data = note_data->next; - continue; - case 6: - if (__builtin_expect((note_data->replay != NULL), 1)) { - RESTART_NOTE: note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while (nte_array != note_data); - } - if (prev_note) { - prev_note->next = note_data->replay; - } else { - mdi->note = note_data->replay; - } - note_data->replay->next = note_data->next; - note_data = note_data->replay; - note_data->active = 1; - } - } else { - KILL_NOTE: note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while ((nte_array != note_data) - && (nte_array)); - } - if (prev_note) { - prev_note->next = note_data->next; - } else { - mdi->note = note_data->next; - } - note_data = note_data->next; - } - } - continue; - } - note_data->env++; - - if (note_data->is_off == 1) { - do_note_off_extra(note_data); - } - - if (note_data->env_level - > note_data->sample->env_target[note_data->env]) { - note_data->env_inc = - -note_data->sample->env_rate[note_data->env]; - } else { - note_data->env_inc = - note_data->sample->env_rate[note_data->env]; - } - note_data = note_data->next; - continue; - } - - /* - * ========================= - * mix the channels together - * ========================= - */ - left_mix /= 1024; - right_mix /= 1024; - } - - *tmp_buffer++ = left_mix; - *tmp_buffer++ = right_mix; - } while (--count); + tmp_buffer = WM_Mix_Gauss(handle, tmp_buffer, real_samples_to_mix); buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); From b1405921bf0503895ef25439e5ffbd1b5a293936 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 28 Dec 2015 20:44:10 -0600 Subject: [PATCH 189/335] Merged WM_GetOutput_Linear and WM_GetOutput_Gauss into WM_DoGetOutput - With mixing moved into separate functions, these two functions became identical except for the function they called to do mixing. --- src/wildmidi/wildmidi_lib.cpp | 126 ++++------------------------------ 1 file changed, 12 insertions(+), 114 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index b1ec8b459..6adaa0421 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -3403,115 +3403,10 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) return buffer; } -static int WM_GetOutput_Linear(midi * handle, char * buffer, - unsigned long int size) { - unsigned long int buffer_used = 0; - unsigned long int i; - struct _mdi *mdi = (struct _mdi *) handle; - unsigned long int real_samples_to_mix = 0; - struct _event *event = mdi->current_event; - int *tmp_buffer; - int *out_buffer; - int left_mix, right_mix; - - _WM_Lock(&mdi->lock); - - buffer_used = 0; - memset(buffer, 0, size); - - if ( (size / 2) > mdi->mix_buffer_size) { - if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { - mdi->mix_buffer_size += MEM_CHUNK; - } else { - mdi->mix_buffer_size = size / 2; - } - mdi->mix_buffer = (int*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed int)); - } - - tmp_buffer = mdi->mix_buffer; - - memset(tmp_buffer, 0, ((size / 2) * sizeof(signed long int))); - out_buffer = tmp_buffer; - - do { - if (__builtin_expect((!mdi->samples_to_mix), 0)) { - while ((!mdi->samples_to_mix) && (event->do_event)) { - event->do_event(mdi, &event->event_data); - event++; - mdi->samples_to_mix = event->samples_to_next; - mdi->current_event = event; - } - - if (!mdi->samples_to_mix) { - if (mdi->info.current_sample - >= mdi->info.approx_total_samples) { - break; - } else if ((mdi->info.approx_total_samples - - mdi->info.current_sample) > (size >> 2)) { - mdi->samples_to_mix = size >> 2; - } else { - mdi->samples_to_mix = mdi->info.approx_total_samples - - mdi->info.current_sample; - } - } - } - if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { - real_samples_to_mix = size >> 2; - } else { - real_samples_to_mix = mdi->samples_to_mix; - if (real_samples_to_mix == 0) { - continue; - } - } - - /* do mixing here */ - tmp_buffer = WM_Mix_Linear(handle, tmp_buffer, real_samples_to_mix); - - buffer_used += real_samples_to_mix * 4; - size -= (real_samples_to_mix << 2); - mdi->info.current_sample += real_samples_to_mix; - mdi->samples_to_mix -= real_samples_to_mix; - } while (size); - - tmp_buffer = out_buffer; - - if (mdi->info.mixer_options & WM_MO_REVERB) { - _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); - } - - for (i = 0; i < buffer_used; i += 4) { - left_mix = *tmp_buffer++; - right_mix = *tmp_buffer++; - - if (left_mix > 32767) { - left_mix = 32767; - } else if (left_mix < -32768) { - left_mix = -32768; - } - - if (right_mix > 32767) { - right_mix = 32767; - } else if (right_mix < -32768) { - right_mix = -32768; - } - - /* - * =================== - * Write to the buffer - * =================== - */ - (*buffer++) = left_mix & 0xff; - (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); - (*buffer++) = right_mix & 0xff; - (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); - } - - _WM_Unlock(&mdi->lock); - return buffer_used; -} - static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) { + if (!gauss_table) init_gauss(); + struct _mdi *mdi = (struct _mdi *)handle; unsigned long int data_pos; signed int premix, left_mix, right_mix; @@ -3748,7 +3643,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) return buffer; } -static int WM_GetOutput_Gauss(midi * handle, char * buffer, +static int WM_DoGetOutput(midi * handle, char * buffer, unsigned long int size) { unsigned long int buffer_used = 0; unsigned long int i; @@ -3807,7 +3702,14 @@ static int WM_GetOutput_Gauss(midi * handle, char * buffer, } /* do mixing here */ - tmp_buffer = WM_Mix_Gauss(handle, tmp_buffer, real_samples_to_mix); + if (mdi->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) + { + tmp_buffer = WM_Mix_Gauss(handle, tmp_buffer, real_samples_to_mix); + } + else + { + tmp_buffer = WM_Mix_Linear(handle, tmp_buffer, real_samples_to_mix); + } buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); @@ -4172,11 +4074,7 @@ WM_SYMBOL int WildMidi_GetOutput(midi * handle, char *buffer, unsigned long int "(size not a multiple of 4)", 0); return -1; } - if (((struct _mdi *) handle)->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) { - if (!gauss_table) init_gauss(); - return WM_GetOutput_Gauss(handle, buffer, size); - } - return WM_GetOutput_Linear(handle, buffer, size); + return WM_DoGetOutput(handle, buffer, size); } WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, From ee46799d9ea7adec7aea5dee4e32df10bca4de96 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 28 Dec 2015 20:51:53 -0600 Subject: [PATCH 190/335] Fix WM_DoGetOutput for big-endian machines - Besides being little-endian centric, this bit shifting madness was unneccessary since the values were already clamped to a 16-bit range, so all we need to do is cast them to a short. --- src/wildmidi/wildmidi_lib.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 6adaa0421..385ac6c1d 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -3744,10 +3744,9 @@ static int WM_DoGetOutput(midi * handle, char * buffer, * Write to the buffer * =================== */ - (*buffer++) = left_mix & 0xff; - (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); - (*buffer++) = right_mix & 0xff; - (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); + ((short *)buffer)[0] = (short)left_mix; + ((short *)buffer)[1] = (short)right_mix; + buffer += 4; } _WM_Unlock(&mdi->lock); return buffer_used; From afc36544b7e3ffdfe378343b42e2c6773a3514a5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 28 Dec 2015 22:07:51 -0600 Subject: [PATCH 191/335] Add a WildMidi softsynth device - This removes the preceding psuedo MIDI device for WildMidi. --- src/CMakeLists.txt | 2 +- src/sound/i_musicinterns.h | 39 ++--- src/sound/music_midi_wildmidi.cpp | 163 ------------------- src/sound/music_midistream.cpp | 2 +- src/sound/music_wildmidi_mididevice.cpp | 206 ++++++++++++++++++++++++ src/wildmidi/wildmidi_lib.cpp | 150 ++++++++++++++++- src/wildmidi/wildmidi_lib.h | 16 ++ zdoom.vcproj | 8 +- 8 files changed, 390 insertions(+), 196 deletions(-) delete mode 100644 src/sound/music_midi_wildmidi.cpp create mode 100644 src/sound/music_wildmidi_mididevice.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a86e96f01..18fdb992c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1086,12 +1086,12 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE sound/music_midistream.cpp sound/music_midi_base.cpp sound/music_midi_timidity.cpp - sound/music_midi_wildmidi.cpp sound/music_mus_opl.cpp sound/music_stream.cpp sound/music_fluidsynth_mididevice.cpp sound/music_softsynth_mididevice.cpp sound/music_timidity_mididevice.cpp + sound/music_wildmidi_mididevice.cpp sound/music_win_mididevice.cpp sound/oalsound.cpp sound/sndfile_decoder.cpp diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 4aa5f8254..03282ef37 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -219,25 +219,6 @@ protected: #endif }; -class WildMidiMIDIDevice : public PseudoMIDIDevice -{ -public: - WildMidiMIDIDevice(); - ~WildMidiMIDIDevice(); - - int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); - bool Preprocess(MIDIStreamer *song, bool looping); - bool IsOpen() const; - -protected: - - midi *mMidi; - bool mLoop; - - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); -}; - - // Base class for software synthesizer MIDI output devices ------------------ class SoftSynthMIDIDevice : public MIDIDevice @@ -350,6 +331,26 @@ protected: FILE *File; }; +// WildMidi implementation of a MIDI device --------------------------------- + +class WildMIDIDevice : public SoftSynthMIDIDevice +{ +public: + WildMIDIDevice(); + ~WildMIDIDevice(); + + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + void PrecacheInstruments(const WORD *instruments, int count); + FString GetStats(); + +protected: + WildMidi_Renderer *Renderer; + + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const BYTE *data, int len); + void ComputeOutput(float *buffer, int len); +}; + // FluidSynth implementation of a MIDI device ------------------------------- #ifdef HAVE_FLUIDSYNTH diff --git a/src/sound/music_midi_wildmidi.cpp b/src/sound/music_midi_wildmidi.cpp deleted file mode 100644 index f6df48459..000000000 --- a/src/sound/music_midi_wildmidi.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "i_musicinterns.h" -#include "c_cvars.h" -#include "cmdlib.h" -#include "templates.h" -#include "version.h" - - -CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - -static FString currentConfig; - -// added because Timidity's output is rather loud. -CUSTOM_CVAR (Float, wildmidi_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self < 0.f) - self = 0.f; - else if (self > 1.f) - self = 1.f; -} - -CUSTOM_CVAR (Int, wildmidi_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ // Clamp frequency to Timidity's limits - if (self < 11000) - self = 11000; - else if (self > 65000) - self = 65000; -} - -//========================================================================== -// -// WildMidiMIDIDevice Constructor -// -//========================================================================== - -WildMidiMIDIDevice::WildMidiMIDIDevice() -{ - mMidi = NULL; - mLoop = false; -} - -//========================================================================== -// -// WildMidiMIDIDevice Destructor -// -//========================================================================== - -WildMidiMIDIDevice::~WildMidiMIDIDevice () -{ - if (mMidi != NULL) WildMidi_Close(mMidi); - // do not shut down the device so that it can be reused for the next song being played. -} - -//========================================================================== -// -// WildMidiMIDIDevice :: Preprocess -// -//========================================================================== - -bool WildMidiMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) -{ - TArray midi; - - // Write MIDI song to temporary file - song->CreateSMF(midi, looping ? 0 : 1); - - mMidi = WildMidi_OpenBuffer(&midi[0], midi.Size()); - if (mMidi == NULL) - { - Printf(PRINT_BOLD, "Could not open temp music file\n"); - } - mLoop = looping; - return false; -} - -//========================================================================== -// -// WildMidiMIDIDevice :: Open -// -//========================================================================== - -int WildMidiMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) -{ - if (currentConfig.CompareNoCase(wildmidi_config) != 0) - { - if (currentConfig.IsNotEmpty()) WildMidi_Shutdown(); - currentConfig = ""; - if (!WildMidi_Init(wildmidi_config, wildmidi_frequency, WM_MO_ENHANCED_RESAMPLING)) - { - currentConfig = wildmidi_config; - } - else - { - return 1; - } - } - - Stream = GSnd->CreateStream(FillStream, 32 * 1024, 0, wildmidi_frequency, this); - if (Stream == NULL) - { - Printf(PRINT_BOLD, "Could not create music stream.\n"); - return 1; - } - - return 0; -} - - -//========================================================================== -// -// WildMidiMIDIDevice :: FillStream -// -//========================================================================== - -bool WildMidiMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) -{ - char *buffer = (char*)buff; - WildMidiMIDIDevice *song = (WildMidiMIDIDevice *)userdata; - if (song->mMidi != NULL) - { - while (len > 0) - { - int written = WildMidi_GetOutput(song->mMidi, buffer, len); - if (written < 0) - { - // error - memset(buffer, 0, len); - return false; - } - buffer += written; - len -= written; - - if (len > 0) - { - if (!song->mLoop) - { - memset(buffer, 0, len); - return written > 0; - } - else - { - // loop the sound (i.e. go back to start.) - unsigned long spos = 0; - WildMidi_FastSeek(song->mMidi, &spos); - } - - } - } - } - - return true; -} - -//========================================================================== -// -// WildMidiMIDIDevice :: IsOpen -// -//========================================================================== - -bool WildMidiMIDIDevice::IsOpen() const -{ - return mMidi != NULL; -} - diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 42e8b5926..37616b9a6 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -294,7 +294,7 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const return new TimidityPPMIDIDevice; case MDEV_WILDMIDI: - return new WildMidiMIDIDevice; + return new WildMIDIDevice; default: return NULL; diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp new file mode 100644 index 000000000..44c060f26 --- /dev/null +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -0,0 +1,206 @@ +/* +** music_wildmidi_mididevice.cpp +** Provides access to WildMidi as a generic MIDI device. +** +**--------------------------------------------------------------------------- +** Copyright 2015 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "i_musicinterns.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "w_wad.h" +#include "v_text.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static FString CurrentConfig; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// WildMIDIDevice Constructor +// +//========================================================================== + +WildMIDIDevice::WildMIDIDevice() +{ + Renderer = NULL; + + if (wildmidi_frequency >= 11025 && wildmidi_frequency < 65536) + { // Use our own sample rate instead of the global one + SampleRate = wildmidi_frequency; + } + else + { // Else make sure we're not outside of WildMidi's range + SampleRate = clamp(SampleRate, 11025, 65535); + } + + if (CurrentConfig.CompareNoCase(wildmidi_config) != 0 || SampleRate != WildMidi_GetSampleRate()) + { + if (CurrentConfig.IsNotEmpty()) + { + WildMidi_Shutdown(); + CurrentConfig = ""; + } + if (!WildMidi_Init(wildmidi_config, SampleRate, WM_MO_ENHANCED_RESAMPLING)) + { + CurrentConfig = wildmidi_config; + } + } + if (CurrentConfig.IsNotEmpty()) + { + Renderer = new WildMidi_Renderer(); + } +} + +//========================================================================== +// +// WildMIDIDevice Destructor +// +//========================================================================== + +WildMIDIDevice::~WildMIDIDevice() +{ + Close(); + if (Renderer != NULL) + { + delete Renderer; + } + // Do not shut down the device so that it can be reused for the next song being played. +} + +//========================================================================== +// +// WildMIDIDevice :: Open +// +// Returns 0 on success. +// +//========================================================================== + +int WildMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +{ + if (Renderer == NULL) + { + return 1; + } + int ret = OpenStream(2, 0, callback, userdata); + if (ret == 0) + { +// Renderer->Reset(); + } + return ret; +} + +//========================================================================== +// +// WildMIDIDevice :: PrecacheInstruments +// +// Each entry is packed as follows: +// Bits 0- 6: Instrument number +// Bits 7-13: Bank number +// Bit 14: Select drum set if 1, tone bank if 0 +// +//========================================================================== + +void WildMIDIDevice::PrecacheInstruments(const WORD *instruments, int count) +{ + for (int i = 0; i < count; ++i) + { + Renderer->LoadInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); + } +} + + +//========================================================================== +// +// WildMIDIDevice :: HandleEvent +// +//========================================================================== + +void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2) +{ + Renderer->ShortEvent(status, parm1, parm2); +} + +//========================================================================== +// +// WildMIDIDevice :: HandleLongEvent +// +//========================================================================== + +void WildMIDIDevice::HandleLongEvent(const BYTE *data, int len) +{ + Renderer->LongEvent((const char *)data, len); +} + +//========================================================================== +// +// WildMIDIDevice :: ComputeOutput +// +//========================================================================== + +void WildMIDIDevice::ComputeOutput(float *buffer, int len) +{ + Renderer->ComputeOutput(buffer, len); +} + +//========================================================================== +// +// WildMIDIDevice :: GetStats +// +//========================================================================== + +FString WildMIDIDevice::GetStats() +{ + FString out; + out.Format("%3d voices", Renderer->GetVoiceCount()); + return out; +} diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 385ac6c1d..f20420e75 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -3643,6 +3643,18 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) return buffer; } +int *WM_Mix(midi *handle, int *buffer, unsigned long count) +{ + if (((struct _mdi *)handle)->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) + { + return WM_Mix_Gauss(handle, buffer, count); + } + else + { + return WM_Mix_Linear(handle, buffer, count); + } +} + static int WM_DoGetOutput(midi * handle, char * buffer, unsigned long int size) { unsigned long int buffer_used = 0; @@ -3702,14 +3714,7 @@ static int WM_DoGetOutput(midi * handle, char * buffer, } /* do mixing here */ - if (mdi->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) - { - tmp_buffer = WM_Mix_Gauss(handle, tmp_buffer, real_samples_to_mix); - } - else - { - tmp_buffer = WM_Mix_Linear(handle, tmp_buffer, real_samples_to_mix); - } + tmp_buffer = WM_Mix(handle, tmp_buffer, real_samples_to_mix); buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); @@ -3807,6 +3812,11 @@ WM_SYMBOL int WildMidi_Init(const char * config_file, unsigned short int rate, return 0; } +WM_SYMBOL int WildMidi_GetSampleRate(void) +{ + return _WM_SampleRate; +} + WM_SYMBOL int WildMidi_MasterVolume(unsigned char master_volume) { struct _mdi *mdi = NULL; struct _hndl * tmp_handle = first_handle; @@ -3947,6 +3957,23 @@ WildMidi_OpenBuffer(unsigned char *midibuffer, unsigned long int size) { return ret; } +midi *WildMidi_NewMidi() { + midi * ret = NULL; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + ret = Init_MDI(); + if (ret) { + if (add_handle(ret) != 0) { + WildMidi_Close(ret); + ret = NULL; + } + } + return ret; +} + WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { struct _mdi *mdi; struct _event *event; @@ -4197,3 +4224,110 @@ WM_SYMBOL int WildMidi_Shutdown(void) { return 0; } + +WildMidi_Renderer::WildMidi_Renderer() +{ + handle = WildMidi_NewMidi(); +} + +WildMidi_Renderer::~WildMidi_Renderer() +{ + WildMidi_Close((midi *)handle); +} + +void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2) +{ + _mdi *mdi = (_mdi *)handle; + _event_data ev; + + ev.channel = status & 0x0F; + switch ((status & 0xF0) >> 4) // command + { + case 0x8: + ev.data = (parm1 << 8) | parm2; + do_note_off(mdi, &ev); + break; + + case 0x9: + ev.data = (parm1 << 8) | parm2; + do_note_on(mdi, &ev); + break; + + case 0xA: + ev.data = (parm1 << 8) | parm2; + do_aftertouch(mdi, &ev); + break; + + case 0xC: + ev.data = parm1; + do_patch(mdi, &ev); + break; + + case 0xD: + ev.data = parm1; + do_channel_pressure(mdi, &ev); + break; + + case 0xE: + ev.data = parm1 | (parm2 << 7); + do_pitch(mdi, &ev); + break; + + case 0xB: // Controllers + ev.data = parm2; + switch (parm1) + { + case 0: do_control_bank_select(mdi, &ev); break; + case 6: do_control_data_entry_course(mdi, &ev); break; // [sic] + case 7: do_control_channel_volume(mdi, &ev); break; + case 8: do_control_channel_balance(mdi, &ev); break; + case 10: do_control_channel_pan(mdi, &ev); break; + case 11: do_control_channel_expression(mdi, &ev); break; + case 38: do_control_data_entry_fine(mdi, &ev); break; + case 64: do_control_channel_hold(mdi, &ev); break; + case 96: do_control_data_increment(mdi, &ev); break; + case 97: do_control_data_decrement(mdi, &ev); break; + case 98: + case 99: do_control_non_registered_param(mdi, &ev); break; + case 100: do_control_registered_param_fine(mdi, &ev); break; + case 101: do_control_registered_param_course(mdi, &ev); break; // [sic] + case 120: do_control_channel_sound_off(mdi, &ev); break; + case 121: do_control_channel_controllers_off(mdi, &ev); break; + case 123: do_control_channel_notes_off(mdi, &ev); break; + } + } +} + +void WildMidi_Renderer::LongEvent(const char *data, int len) +{ +} + +void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len) +{ + _mdi *mdi = (_mdi *)handle; + int *buffer = (int *)fbuffer; + int *newbuf = WM_Mix(handle, buffer, len); +// assert(newbuf - buffer == len); + if (mdi->info.mixer_options & WM_MO_REVERB) { + _WM_do_reverb(mdi->reverb, buffer, len * 2); + } + for (; buffer < newbuf; ++buffer) + { + *(float *)buffer = (float)*buffer / 32768.f; + } +} + +void WildMidi_Renderer::LoadInstrument(int bank, int percussion, int instr) +{ + load_patch((_mdi *)handle, (bank << 8) | instr | (percussion ? 0x80 : 0)); +} + +int WildMidi_Renderer::GetVoiceCount() +{ + int count = 0; + for (_note *note_data = ((_mdi *)handle)->note; note_data != NULL; note_data = note_data->next) + { + count++; + } + return count; +} diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h index e6317a271..46a517d90 100644 --- a/src/wildmidi/wildmidi_lib.h +++ b/src/wildmidi/wildmidi_lib.h @@ -64,6 +64,7 @@ WM_SYMBOL struct _WM_Info * WildMidi_GetInfo (midi * handle); WM_SYMBOL int WildMidi_FastSeek (midi * handle, unsigned long int *sample_pos); WM_SYMBOL int WildMidi_Close (midi * handle); WM_SYMBOL int WildMidi_Shutdown (void); +WM_SYMBOL int WildMidi_GetSampleRate (void); /* #if defined(__cplusplus) @@ -71,5 +72,20 @@ WM_SYMBOL int WildMidi_Shutdown (void); #endif */ +class WildMidi_Renderer +{ +public: + WildMidi_Renderer(); + ~WildMidi_Renderer(); + + void ShortEvent(int status, int parm1, int parm2); + void LongEvent(const char *data, int len); + void ComputeOutput(float *buffer, int len); + void LoadInstrument(int bank, int percussion, int instr); + int GetVoiceCount(); +private: + void *handle; +}; + #endif /* WILDMIDI_LIB_H */ diff --git a/zdoom.vcproj b/zdoom.vcproj index 126efb7f5..a5d7bfb8e 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2553,10 +2553,6 @@ RelativePath="src\sound\music_midi_timidity.cpp" > - - @@ -2597,6 +2593,10 @@ RelativePath=".\src\sound\music_timidity_mididevice.cpp" > + + From 7c82c576a3e3e4522dd528c3643a2396b9bee2eb Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 29 Dec 2015 10:33:20 +0100 Subject: [PATCH 192/335] - Fixed Linux compiler errors and snd_mididevice. -- errno.h is required for 'errno'; -- don't use str(n)casecmp and rely on ZDoom CMake handling; -- add a missing parenthesis around a 'signed char' cast; -- remove an unneeded GNU_SOURCE redefinition; -- the non-MSVC side of snd_mididevice was not adapted to the new code, making wildmidi unavailable through the menu. --- src/sound/music_midi_base.cpp | 4 ++-- src/wildmidi/file_io.cpp | 2 ++ src/wildmidi/lock.cpp | 1 - src/wildmidi/wildmidi_lib.cpp | 44 +++++++++++++++++------------------ 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index e1afa09a8..048e52e3f 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -198,8 +198,8 @@ CCMD (snd_listmididevices) CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { - if (self < -5) - self = -5; + if (self < -6) + self = -6; else if (self > -1) self = -1; else diff --git a/src/wildmidi/file_io.cpp b/src/wildmidi/file_io.cpp index f14e22bbf..c2ef55715 100644 --- a/src/wildmidi/file_io.cpp +++ b/src/wildmidi/file_io.cpp @@ -33,6 +33,8 @@ ** */ +#include + #include "../files.h" #include "wm_error.h" #include "file_io.h" diff --git a/src/wildmidi/lock.cpp b/src/wildmidi/lock.cpp index f8abfe926..c5d3fc7da 100644 --- a/src/wildmidi/lock.cpp +++ b/src/wildmidi/lock.cpp @@ -29,7 +29,6 @@ #ifdef _WIN32 #include #else -#define _GNU_SOURCE #include #endif diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index f20420e75..8f8d558b9 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -47,11 +47,11 @@ #ifdef _WIN32 #include #include -*/ #undef strcasecmp #define strcasecmp _stricmp #undef strncasecmp #define strncasecmp _strnicmp +*/ @@ -699,7 +699,7 @@ static int WM_LoadConfig(const char *config_file) { if (config_ptr != line_start_ptr) { line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]); if (line_tokens) { - if (strcasecmp(line_tokens[0], "dir") == 0) { + if (stricmp(line_tokens[0], "dir") == 0) { free(config_dir); if (!line_tokens[1]) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, @@ -724,7 +724,7 @@ static int WM_LoadConfig(const char *config_file) { config_dir[strlen(config_dir) + 1] = '\0'; config_dir[strlen(config_dir)] = '/'; } - } else if (strcasecmp(line_tokens[0], "source") == 0) { + } else if (stricmp(line_tokens[0], "source") == 0) { char *new_config = NULL; if (!line_tokens[1]) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, @@ -772,7 +772,7 @@ static int WM_LoadConfig(const char *config_file) { return -1; } free(new_config); - } else if (strcasecmp(line_tokens[0], "bank") == 0) { + } else if (stricmp(line_tokens[0], "bank") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in bank line)", 0); @@ -785,7 +785,7 @@ static int WM_LoadConfig(const char *config_file) { return -1; } patchid = (atoi(line_tokens[1]) & 0xFF) << 8; - } else if (strcasecmp(line_tokens[0], "drumset") == 0) { + } else if (stricmp(line_tokens[0], "drumset") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in drumset line)", 0); @@ -798,7 +798,7 @@ static int WM_LoadConfig(const char *config_file) { return -1; } patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80; - } else if (strcasecmp(line_tokens[0], "reverb_room_width") == 0) { + } else if (stricmp(line_tokens[0], "reverb_room_width") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_room_width line)", @@ -823,7 +823,7 @@ static int WM_LoadConfig(const char *config_file) { 0); reverb_room_width = 100.0f; } - } else if (strcasecmp(line_tokens[0], "reverb_room_length") == 0) { + } else if (stricmp(line_tokens[0], "reverb_room_length") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_room_length line)", @@ -848,7 +848,7 @@ static int WM_LoadConfig(const char *config_file) { 0); reverb_room_length = 100.0f; } - } else if (strcasecmp(line_tokens[0], "reverb_listener_posx") == 0) { + } else if (stricmp(line_tokens[0], "reverb_listener_posx") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_listen_posx line)", @@ -869,7 +869,7 @@ static int WM_LoadConfig(const char *config_file) { 0); reverb_listen_posx = reverb_room_width / 2.0f; } - } else if (strcasecmp(line_tokens[0], + } else if (stricmp(line_tokens[0], "reverb_listener_posy") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, @@ -891,13 +891,13 @@ static int WM_LoadConfig(const char *config_file) { 0); reverb_listen_posy = reverb_room_length * 0.75f; } - } else if (strcasecmp(line_tokens[0], + } else if (stricmp(line_tokens[0], "guspat_editor_author_cant_read_so_fix_release_time_for_me") == 0) { fix_release = 1; - } else if (strcasecmp(line_tokens[0], "auto_amp") == 0) { + } else if (stricmp(line_tokens[0], "auto_amp") == 0) { auto_amp = 1; - } else if (strcasecmp(line_tokens[0], "auto_amp_with_amp") + } else if (stricmp(line_tokens[0], "auto_amp_with_amp") == 0) { auto_amp = 1; auto_amp_with_amp = 1; @@ -1038,7 +1038,7 @@ static int WM_LoadConfig(const char *config_file) { return -1; } } - if (strncasecmp( + if (strnicmp( &tmp_patch->filename[strlen(tmp_patch->filename) - 4], ".pat", 4) != 0) { strcat(tmp_patch->filename, ".pat"); @@ -1054,7 +1054,7 @@ static int WM_LoadConfig(const char *config_file) { token_count = 0; while (line_tokens[token_count]) { - if (strncasecmp(line_tokens[token_count], "amp=", 4) + if (strnicmp(line_tokens[token_count], "amp=", 4) == 0) { if (!wm_isdigit(line_tokens[token_count][4])) { _WM_ERROR(__FUNCTION__, __LINE__, @@ -1065,7 +1065,7 @@ static int WM_LoadConfig(const char *config_file) { &line_tokens[token_count][4]) << 10) / 100; } - } else if (strncasecmp(line_tokens[token_count], + } else if (strnicmp(line_tokens[token_count], "note=", 5) == 0) { if (!wm_isdigit(line_tokens[token_count][5])) { _WM_ERROR(__FUNCTION__, __LINE__, @@ -1075,7 +1075,7 @@ static int WM_LoadConfig(const char *config_file) { tmp_patch->note = atoi( &line_tokens[token_count][5]); } - } else if (strncasecmp(line_tokens[token_count], + } else if (strnicmp(line_tokens[token_count], "env_time", 8) == 0) { if ((!wm_isdigit(line_tokens[token_count][8])) || (!wm_isdigit( @@ -1110,7 +1110,7 @@ static int WM_LoadConfig(const char *config_file) { } } } - } else if (strncasecmp(line_tokens[token_count], + } else if (strnicmp(line_tokens[token_count], "env_level", 9) == 0) { if ((!wm_isdigit(line_tokens[token_count][9])) || (!wm_isdigit( @@ -1144,16 +1144,16 @@ static int WM_LoadConfig(const char *config_file) { } } } - } else if (strcasecmp(line_tokens[token_count], + } else if (stricmp(line_tokens[token_count], "keep=loop") == 0) { tmp_patch->keep |= SAMPLE_LOOP; - } else if (strcasecmp(line_tokens[token_count], + } else if (stricmp(line_tokens[token_count], "keep=env") == 0) { tmp_patch->keep |= SAMPLE_ENVELOPE; - } else if (strcasecmp(line_tokens[token_count], + } else if (stricmp(line_tokens[token_count], "remove=sustain") == 0) { tmp_patch->remove |= SAMPLE_SUSTAIN; - } else if (strcasecmp(line_tokens[token_count], + } else if (stricmp(line_tokens[token_count], "remove=clamped") == 0) { tmp_patch->remove |= SAMPLE_CLAMPED; } @@ -1695,7 +1695,7 @@ static void do_control_channel_balance(struct _mdi *mdi, static void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; - mdi->channel[ch].pan = signed char(data->data - 64); + mdi->channel[ch].pan = (signed char)(data->data - 64); do_pan_adjust(mdi, ch); } From 944360557f79480b4b39571d06fbe4b97e58b87e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 11:23:43 +0100 Subject: [PATCH 193/335] - removed unused header stuff. --- src/wildmidi/wildmidi_lib.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 8f8d558b9..1e78f7feb 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -43,18 +43,6 @@ #include #include -/* -#ifdef _WIN32 -#include -#include -#undef strcasecmp -#define strcasecmp _stricmp -#undef strncasecmp -#define strncasecmp _strnicmp -*/ - - - #include "common.h" #include "wm_error.h" #include "file_io.h" From 7fa289109b9fdcdd1cecf3f72708b7ea4ee95820 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 11:36:56 +0100 Subject: [PATCH 194/335] - removed all uses of __builtin_expect from WildMidi code. --- src/wildmidi/wildmidi_lib.cpp | 91 +++++++++++++++-------------------- 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 1e78f7feb..26e4965ba 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -60,9 +60,6 @@ #define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC((f))) -// Why is this shit even being used...? :( -#define __builtin_expect(a, b) a - /* * ========================= * Global Data and Data Structs @@ -1459,15 +1456,15 @@ static inline unsigned long int get_inc(struct _mdi *mdi, struct _note *nte) { signed long int note_f; unsigned long int freq; - if (__builtin_expect((nte->patch->note != 0), 0)) { + if (nte->patch->note != 0) { note_f = nte->patch->note * 100; } else { note_f = (nte->noteid & 0x7f) * 100; } note_f += mdi->channel[ch].pitch_adjust; - if (__builtin_expect((note_f < 0), 0)) { + if (note_f < 0) { note_f = 0; - } else if (__builtin_expect((note_f > 12700), 0)) { + } else if (note_f > 12700) { note_f = 12700; } freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); @@ -3202,7 +3199,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) do { note_data = mdi->note; left_mix = right_mix = 0; - if (__builtin_expect((note_data != NULL), 1)) { + if (note_data != NULL) { while (note_data) { /* * =================== @@ -3231,44 +3228,38 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) * ======================== */ note_data->sample_pos += note_data->sample_inc; - if (__builtin_expect( - (note_data->sample_pos > note_data->sample->loop_end), - 0)) { + if (note_data->sample_pos > note_data->sample->loop_end) { if (note_data->modes & SAMPLE_LOOP) { note_data->sample_pos = note_data->sample->loop_start + ((note_data->sample_pos - note_data->sample->loop_start) % note_data->sample->loop_size); - } else if (__builtin_expect( - (note_data->sample_pos - >= note_data->sample->data_length), - 0)) { - if (__builtin_expect((note_data->replay == NULL), 1)) { + } else if (note_data->sample_pos >= note_data->sample->data_length) { + if (note_data->replay == NULL) { goto KILL_NOTE; } goto RESTART_NOTE; } } - if (__builtin_expect((note_data->env_inc == 0), 0)) { + if (note_data->env_inc == 0) { note_data = note_data->next; continue; } note_data->env_level += note_data->env_inc; - if (__builtin_expect((note_data->env_level > 4194304), 0)) { + if (note_data->env_level > 4194304) { note_data->env_level = note_data->sample->env_target[note_data->env]; } - if (__builtin_expect( - ((note_data->env_inc < 0) - && (note_data->env_level - > note_data->sample->env_target[note_data->env])) - || ((note_data->env_inc > 0) - && (note_data->env_level - < note_data->sample->env_target[note_data->env])), - 1)) { + if (((note_data->env_inc < 0) + && (note_data->env_level + > note_data->sample->env_target[note_data->env])) + || ((note_data->env_inc > 0) + && (note_data->env_level + < note_data->sample->env_target[note_data->env]))) + { note_data = note_data->next; continue; } @@ -3304,7 +3295,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) } break; case 5: - if (__builtin_expect((note_data->env_level == 0), 1)) { + if (note_data->env_level == 0) { goto KILL_NOTE; } /* sample release */ @@ -3314,7 +3305,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) note_data = note_data->next; continue; case 6: - if (__builtin_expect((note_data->replay != NULL), 1)) { + if (note_data->replay != NULL) { RESTART_NOTE: note_data->active = 0; { struct _note *prev_note = NULL; @@ -3409,7 +3400,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) do { note_data = mdi->note; left_mix = right_mix = 0; - if (__builtin_expect((note_data != NULL), 1)) { + if (note_data != NULL) { while (note_data) { /* * =================== @@ -3471,44 +3462,40 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) * ======================== */ note_data->sample_pos += note_data->sample_inc; - if (__builtin_expect( - (note_data->sample_pos > note_data->sample->loop_end), - 0)) { + if (note_data->sample_pos > note_data->sample->loop_end) + { if (note_data->modes & SAMPLE_LOOP) { note_data->sample_pos = note_data->sample->loop_start + ((note_data->sample_pos - note_data->sample->loop_start) % note_data->sample->loop_size); - } else if (__builtin_expect( - (note_data->sample_pos - >= note_data->sample->data_length), - 0)) { - if (__builtin_expect((note_data->replay == NULL), 1)) { + } else if (note_data->sample_pos >= note_data->sample->data_length) { + if (note_data->replay == NULL) { goto KILL_NOTE; } goto RESTART_NOTE; } } - if (__builtin_expect((note_data->env_inc == 0), 0)) { + if (note_data->env_inc == 0) { note_data = note_data->next; continue; } note_data->env_level += note_data->env_inc; - if (__builtin_expect((note_data->env_level > 4194304), 0)) { + if (note_data->env_level > 4194304) { note_data->env_level = note_data->sample->env_target[note_data->env]; } - if (__builtin_expect( + if ( ((note_data->env_inc < 0) && (note_data->env_level > note_data->sample->env_target[note_data->env])) || ((note_data->env_inc > 0) && (note_data->env_level - < note_data->sample->env_target[note_data->env])), - 1)) { + < note_data->sample->env_target[note_data->env])) + ) { note_data = note_data->next; continue; } @@ -3544,7 +3531,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) } break; case 5: - if (__builtin_expect((note_data->env_level == 0), 1)) { + if (note_data->env_level == 0) { goto KILL_NOTE; } /* sample release */ @@ -3554,7 +3541,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) note_data = note_data->next; continue; case 6: - if (__builtin_expect((note_data->replay != NULL), 1)) { + if (note_data->replay != NULL) { RESTART_NOTE: note_data->active = 0; { struct _note *prev_note = NULL; @@ -3671,7 +3658,7 @@ static int WM_DoGetOutput(midi * handle, char * buffer, out_buffer = tmp_buffer; do { - if (__builtin_expect((!mdi->samples_to_mix), 0)) { + if (!mdi->samples_to_mix) { while ((!mdi->samples_to_mix) && (event->do_event)) { event->do_event(mdi, &event->event_data); event++; @@ -3692,7 +3679,7 @@ static int WM_DoGetOutput(midi * handle, char * buffer, } } } - if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { + if (mdi->samples_to_mix > (size >> 2)) { real_samples_to_mix = size >> 2; } else { real_samples_to_mix = mdi->samples_to_mix; @@ -4016,7 +4003,7 @@ WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { _WM_reset_reverb(mdi->reverb); while (count) { - if (__builtin_expect((!mdi->samples_to_mix), 0)) { + if (!mdi->samples_to_mix) { while ((!mdi->samples_to_mix) && (event->do_event)) { event->do_event(mdi, &event->event_data); event++; @@ -4034,7 +4021,7 @@ WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { } } - if (__builtin_expect((mdi->samples_to_mix > count), 0)) { + if (mdi->samples_to_mix > count) { real_samples_to_mix = count; } else { real_samples_to_mix = mdi->samples_to_mix; @@ -4066,24 +4053,24 @@ WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { } WM_SYMBOL int WildMidi_GetOutput(midi * handle, char *buffer, unsigned long int size) { - if (__builtin_expect((!WM_Initialized), 0)) { + if (!WM_Initialized) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return -1; } - if (__builtin_expect((handle == NULL), 0)) { + if (handle == NULL) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return -1; } - if (__builtin_expect((buffer == NULL), 0)) { + if (buffer == NULL) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); return -1; } - if (__builtin_expect((size == 0), 0)) { + if (size == 0) { return 0; } - if (__builtin_expect((!!(size % 4)), 0)) { + if (!!(size % 4)) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0); return -1; From 6f3e04785d9fe8dd68d7d6c2b6d1494aa67046c9 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 27 Dec 2015 11:10:00 +0200 Subject: [PATCH 195/335] Added preprocessor macros for AppKit framework versions These macros are needed to build with earlier OS X SDKs --- src/posix/cocoa/i_common.h | 14 ++++++++++---- src/posix/cocoa/i_video.mm | 5 +---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 545540b2f..dc1e12121 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -50,12 +50,18 @@ struct RenderBufferOptions extern RenderBufferOptions rbOpts; +// Version of AppKit framework we are interested in +// The following values are needed to build with earlier SDKs + +#define AppKit10_4 824 +#define AppKit10_5 949 +#define AppKit10_6 1038 +#define AppKit10_7 1138 + + inline bool I_IsHiDPISupported() { - // The following value shoud be equal to NSAppKitVersionNumber10_7 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1138; + return NSAppKitVersionNumber >= AppKit10_7; } void I_ProcessEvent(NSEvent* event); diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3fc2b2aed..a47a1f1a8 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -561,10 +561,7 @@ void CocoaVideo::SetWindowVisible(bool visible) static bool HasModernFullscreenAPI() { - // The following value shoud be equal to NSAppKitVersionNumber10_6 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1038; + return NSAppKitVersionNumber >= AppKit10_6; } void CocoaVideo::SetStyleMask(const NSUInteger styleMask) From 0efdccd942c29b235825cb09cbc566dc18d89444 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 27 Dec 2015 12:05:04 +0200 Subject: [PATCH 196/335] Separated POSIX's i_system.cpp from native OS X implementation --- src/CMakeLists.txt | 3 +- src/posix/cocoa/i_system.mm | 381 ++++++++++++++++++++++++++++++ src/posix/osx/iwadpicker_cocoa.mm | 6 - src/posix/sdl/i_gui.cpp | 5 - src/posix/{ => sdl}/i_system.cpp | 0 5 files changed, 383 insertions(+), 12 deletions(-) create mode 100644 src/posix/cocoa/i_system.mm rename src/posix/{ => sdl}/i_system.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18fdb992c..25eb25ea4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -592,7 +592,6 @@ set( PLAT_POSIX_SOURCES posix/i_cd.cpp posix/i_movie.cpp posix/i_steam.cpp - posix/i_system.cpp posix/st_start.cpp ) set( PLAT_SDL_SOURCES posix/sdl/crashcatcher.c @@ -601,6 +600,7 @@ set( PLAT_SDL_SOURCES posix/sdl/i_input.cpp posix/sdl/i_joystick.cpp posix/sdl/i_main.cpp + posix/sdl/i_system.cpp posix/sdl/i_timer.cpp posix/sdl/sdlvideo.cpp ) set( PLAT_OSX_SOURCES @@ -611,6 +611,7 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_input.mm posix/cocoa/i_joystick.cpp posix/cocoa/i_main.mm + posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp posix/cocoa/i_video.mm ) diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm new file mode 100644 index 000000000..c9471f8e6 --- /dev/null +++ b/src/posix/cocoa/i_system.mm @@ -0,0 +1,381 @@ +/* + ** i_system.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2012-2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include +#include +#include + +#include "d_ticcmd.h" +#include "doomdef.h" +#include "doomerrors.h" +#include "doomstat.h" +#include "g_game.h" +#include "gameconfigfile.h" +#include "i_sound.h" +#include "i_system.h" +#include "v_text.h" +#include "x86.h" + + +EXTERN_CVAR(String, language) + +DWORD LanguageIDs[4]; + + +int (*I_GetTime)(bool saveMS); +int (*I_WaitForTic)(int); +void (*I_FreezeTime)(bool frozen); + + +void I_Tactile(int /*on*/, int /*off*/, int /*total*/) +{ +} + + +ticcmd_t* I_BaseTiccmd() +{ + static ticcmd_t emptycmd; + return &emptycmd; +} + + +void I_WaitVBL(const int count) +{ + // I_WaitVBL is never used to actually synchronize to the + // vertical blank. Instead, it's used for delay purposes. + usleep(1000000 * count / 70); +} + + +// +// SetLanguageIDs +// +void SetLanguageIDs() +{ + size_t langlen = strlen(language); + + DWORD lang = (langlen < 2 || langlen > 3) + ? MAKE_ID('e', 'n', 'u', '\0') + : MAKE_ID(language[0], language[1], language[2], '\0'); + + LanguageIDs[3] = LanguageIDs[2] = LanguageIDs[1] = LanguageIDs[0] = lang; +} + + +void I_InitTimer(); +void I_ShutdownTimer(); + +void I_Init(void) +{ + CheckCPUID(&CPU); + DumpCPUInfo(&CPU); + + atterm(I_ShutdownSound); + I_InitSound(); + I_InitTimer(); +} + +static int has_exited; + +void I_Quit() +{ + has_exited = 1; // Prevent infinitely recursive exits -- killough + + if (demorecording) + { + G_CheckDemoStatus(); + } + + C_DeinitConsole(); + + I_ShutdownTimer(); +} + + +extern FILE* Logfile; +bool gameisdead; + +void STACK_ARGS I_FatalError(const char* const error, ...) +{ + static bool alreadyThrown = false; + gameisdead = true; + + if (!alreadyThrown) // ignore all but the first message -- killough + { + alreadyThrown = true; + + char errortext[MAX_ERRORTEXT]; + int index; + va_list argptr; + va_start(argptr, error); + index = vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + extern void Mac_I_FatalError(const char*); + Mac_I_FatalError(errortext); + + // Record error to log (if logging) + if (Logfile) + { + fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext); + fflush(Logfile); + } + + fprintf(stderr, "%s\n", errortext); + exit(-1); + } + + if (!has_exited) // If it hasn't exited yet, exit now -- killough + { + has_exited = 1; // Prevent infinitely recursive exits -- killough + exit(-1); + } +} + +void STACK_ARGS I_Error(const char* const error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + throw CRecoverableError(errortext); +} + + +void I_SetIWADInfo() +{ +} + + +void I_PrintStr(const char* const message) +{ + // Strip out any color escape sequences before writing to output + char* const copy = new char[strlen(message) + 1]; + const char* srcp = message; + char* dstp = copy; + + while ('\0' != *srcp) + { + if (TEXTCOLOR_ESCAPE == *srcp) + { + if ('\0' != srcp[1]) + { + srcp += 2; + } + else + { + break; + } + } + else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character + { + *dstp++ = '-'; + *srcp++; + } + else if (0x1e == *srcp) // Middle bar character + { + *dstp++ = '='; + *srcp++; + } + else + { + *dstp++ = *srcp++; + } + } + + *dstp = '\0'; + + fputs(copy, stdout); + delete[] copy; + fflush(stdout); +} + + +int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad) +{ + if (!showwin) + { + return defaultiwad; + } + + I_SetMainWindowVisible(false); + + extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int); + const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad); + + I_SetMainWindowVisible(true); + + return result; +} + + +bool I_WriteIniFailed() +{ + printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno)); + return false; // return true to retry +} + + +static const char *pattern; + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 +static int matchfile(struct dirent *ent) +#else +static int matchfile(const struct dirent *ent) +#endif +{ + return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0; +} + +void* I_FindFirst(const char* const filespec, findstate_t* const fileinfo) +{ + FString dir; + + const char* const slash = strrchr(filespec, '/'); + + if (slash) + { + pattern = slash+1; + dir = FString(filespec, slash - filespec + 1); + } + else + { + pattern = filespec; + dir = "."; + } + + fileinfo->current = 0; + fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort); + + if (fileinfo->count > 0) + { + return fileinfo; + } + + return (void*)-1; +} + +int I_FindNext(void* const handle, findstate_t* const fileinfo) +{ + findstate_t* const state = static_cast(handle); + + if (state->current < fileinfo->count) + { + return ++state->current < fileinfo->count ? 0 : -1; + } + + return -1; +} + +int I_FindClose(void* const handle) +{ + findstate_t* const state = static_cast(handle); + + if (handle != (void*)-1 && state->count > 0) + { + for (int i = 0; i < state->count; ++i) + { + free(state->namelist[i]); + } + + free(state->namelist); + state->namelist = NULL; + state->count = 0; + } + + return 0; +} + +int I_FindAttr(findstate_t* const fileinfo) +{ + dirent* const ent = fileinfo->namelist[fileinfo->current]; + struct stat buf; + + if (stat(ent->d_name, &buf) == 0) + { + return S_ISDIR(buf.st_mode) ? FA_DIREC : 0; + } + + return 0; +} + + +static NSString* GetPasteboardStringType() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 + return NSStringPboardType; +#else // 10.6 or higher + return NSAppKitVersionNumber < AppKit10_6 + ? NSStringPboardType + : NSPasteboardTypeString; +#endif // before 10.6 +} + +void I_PutInClipboard(const char* const string) +{ + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + [pasteBoard clearContents]; + [pasteBoard setString:[NSString stringWithUTF8String:string] + forType:GetPasteboardStringType()]; +} + +FString I_GetFromClipboard(bool returnNothing) +{ + if (returnNothing) + { + return FString(); + } + + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const value = [pasteBoard stringForType:GetPasteboardStringType()]; + + return FString([value UTF8String]); +} + + +unsigned int I_MakeRNGSeed() +{ + return static_cast(arc4random()); +} + + +TArray I_GetGogPaths() +{ + // GOG's Doom games are Windows only at the moment + return TArray(); +} diff --git a/src/posix/osx/iwadpicker_cocoa.mm b/src/posix/osx/iwadpicker_cocoa.mm index d2bc1ff0c..5f2ff2ae2 100644 --- a/src/posix/osx/iwadpicker_cocoa.mm +++ b/src/posix/osx/iwadpicker_cocoa.mm @@ -462,20 +462,14 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters) [pool release]; } -void I_SetMainWindowVisible(bool visible); - // Simple wrapper so we can call this from outside. int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - I_SetMainWindowVisible(false); - IWADPicker *picker = [IWADPicker alloc]; int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad]; - I_SetMainWindowVisible(true); - NSString* parametersToAppend = [picker commandLineParameters]; osx_additional_parameters = [parametersToAppend UTF8String]; diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp index f9e6714b4..37a3b1062 100644 --- a/src/posix/sdl/i_gui.cpp +++ b/src/posix/sdl/i_gui.cpp @@ -54,8 +54,3 @@ bool I_SetCursor(FTexture *cursorpic) } return true; } - -void I_SetMainWindowVisible(bool visible) -{ - -} diff --git a/src/posix/i_system.cpp b/src/posix/sdl/i_system.cpp similarity index 100% rename from src/posix/i_system.cpp rename to src/posix/sdl/i_system.cpp From 3676a425126e326adb3b4761bcda648778c31341 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 12:54:23 +0200 Subject: [PATCH 197/335] Added missing include guard in i_common.h --- src/posix/cocoa/i_common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index dc1e12121..63377bb36 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -31,6 +31,9 @@ ** */ +#ifndef COCOA_I_COMMON_INCLUDED +#define COCOA_I_COMMON_INCLUDED + #import @@ -174,3 +177,5 @@ typedef NSInteger NSApplicationActivationPolicy; @end #endif // prior to 10.7 + +#endif // COCOA_I_COMMON_INCLUDED From 15a269db9df6c2454c4b11bb474eef750a492900 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 13:05:07 +0200 Subject: [PATCH 198/335] Extended NSWindow with ability to exit application upon closing by user --- src/posix/cocoa/i_common.h | 5 +++++ src/posix/cocoa/i_video.mm | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 63377bb36..cf2fffbdc 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -62,6 +62,11 @@ extern RenderBufferOptions rbOpts; #define AppKit10_7 1138 +@interface NSWindow(ExitAppOnClose) +- (void)exitAppOnClose; +@end + + inline bool I_IsHiDPISupported() { return NSAppKitVersionNumber >= AppKit10_7; diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index a47a1f1a8..768d147a9 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -58,6 +58,18 @@ #undef Class +@implementation NSWindow(ExitAppOnClose) + +- (void)exitAppOnClose +{ + NSButton* closeButton = [self standardWindowButton:NSWindowCloseButton]; + [closeButton setAction:@selector(terminate:)]; + [closeButton setTarget:NSApp]; +} + +@end + + EXTERN_CVAR(Bool, ticker ) EXTERN_CVAR(Bool, vid_vsync) EXTERN_CVAR(Bool, vid_hidpi) @@ -659,10 +671,7 @@ void CocoaVideo::SetWindowedMode(const int width, const int height) [m_window setContentSize:windowSize]; [m_window center]; - - NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton]; - [closeButton setAction:@selector(terminate:)]; - [closeButton setTarget:NSApp]; + [m_window exitAppOnClose]; } void CocoaVideo::SetMode(const int width, const int height, const bool fullscreen, const bool hiDPI) From 2c3d9e3ab8771b24deff0d72452f8d2f8769b764 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 16:19:08 +0200 Subject: [PATCH 199/335] Fixed mouse capturing when video isn't initialized yet --- src/posix/cocoa/i_video.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 768d147a9..9fbeb6ffa 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -567,6 +567,8 @@ void CocoaVideo::SetWindowVisible(bool visible) { [video->m_window orderOut:nil]; } + + I_SetNativeMouse(!visible); } } @@ -1248,5 +1250,4 @@ NSSize I_GetContentViewSize(const NSWindow* const window) void I_SetMainWindowVisible(bool visible) { CocoaVideo::SetWindowVisible(visible); - I_SetNativeMouse(!visible); } From 673e1b4faf6c9c3c05ae5943daee8206191c0638 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 29 Dec 2015 15:14:41 +0200 Subject: [PATCH 200/335] Fixed compilation warning when building with OS X 10.11 SDK The warning was 'null passed to a callee that requires a non-null argument' --- src/posix/cocoa/i_video.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 9fbeb6ffa..3734d938c 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -1219,7 +1219,7 @@ bool I_SetCursor(FTexture* cursorpic) // Create image from representation and set it as cursor NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType - properties:nil]; + properties:[NSDictionary dictionary]]; NSImage* cursorImage = [[NSImage alloc] initWithData:imageData]; cursor = [[NSCursor alloc] initWithImage:cursorImage From 3af95e0aeade57165c54c1a0af27894ab0023b0f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 29 Dec 2015 15:19:42 +0200 Subject: [PATCH 201/335] Added native startup window for OS X --- src/CMakeLists.txt | 10 +- src/posix/cocoa/i_main.mm | 17 +- src/posix/cocoa/i_system.mm | 3 + src/posix/cocoa/i_video.mm | 3 + src/posix/cocoa/st_console.h | 95 ++++++ src/posix/cocoa/st_console.mm | 506 +++++++++++++++++++++++++++++++ src/posix/cocoa/st_start.mm | 190 ++++++++++++ src/posix/{ => sdl}/st_start.cpp | 0 8 files changed, 808 insertions(+), 16 deletions(-) create mode 100644 src/posix/cocoa/st_console.h create mode 100644 src/posix/cocoa/st_console.mm create mode 100644 src/posix/cocoa/st_start.mm rename src/posix/{ => sdl}/st_start.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25eb25ea4..469fe5527 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -591,8 +591,7 @@ set( PLAT_WIN32_SOURCES set( PLAT_POSIX_SOURCES posix/i_cd.cpp posix/i_movie.cpp - posix/i_steam.cpp - posix/st_start.cpp ) + posix/i_steam.cpp ) set( PLAT_SDL_SOURCES posix/sdl/crashcatcher.c posix/sdl/hardware.cpp @@ -602,7 +601,8 @@ set( PLAT_SDL_SOURCES posix/sdl/i_main.cpp posix/sdl/i_system.cpp posix/sdl/i_timer.cpp - posix/sdl/sdlvideo.cpp ) + posix/sdl/sdlvideo.cpp + posix/sdl/st_start.cpp ) set( PLAT_OSX_SOURCES posix/osx/iwadpicker_cocoa.mm posix/osx/zdoom.icns ) @@ -613,7 +613,9 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_main.mm posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp - posix/cocoa/i_video.mm ) + posix/cocoa/i_video.mm + posix/cocoa/st_console.mm + posix/cocoa/st_start.mm ) if( WIN32 ) set( SYSTEM_SOURCES_DIR win32 ) diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 05a8081f6..2f65254a9 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -47,6 +47,7 @@ #include "i_system.h" #include "m_argv.h" #include "s_sound.h" +#include "st_console.h" #include "version.h" #undef Class @@ -125,18 +126,7 @@ void Mac_I_FatalError(const char* const message) { I_SetMainWindowVisible(false); - const CFStringRef errorString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, - message, kCFStringEncodingASCII, kCFAllocatorNull); - - if (NULL != errorString) - { - CFOptionFlags dummy; - - CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, - CFSTR("Fatal Error"), errorString, CFSTR("Exit"), NULL, NULL, &dummy); - - CFRelease(errorString); - } + FConsoleWindow::GetInstance().ShowFatalError(message); } @@ -315,6 +305,9 @@ ApplicationController* appCtrl; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + FConsoleWindow::CreateInstance(); + atterm(FConsoleWindow::DeleteInstance); + exit(OriginalMain(s_argc, s_argv)); } diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index c9471f8e6..f12ef18eb 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -45,6 +45,7 @@ #include "gameconfigfile.h" #include "i_sound.h" #include "i_system.h" +#include "st_console.h" #include "v_text.h" #include "x86.h" @@ -184,6 +185,8 @@ void I_SetIWADInfo() void I_PrintStr(const char* const message) { + FConsoleWindow::GetInstance().AddText(message); + // Strip out any color escape sequences before writing to output char* const copy = new char[strlen(message) + 1]; const char* srcp = message; diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3734d938c..799dd5ffd 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -47,6 +47,7 @@ #include "m_argv.h" #include "r_renderer.h" #include "r_swrenderer.h" +#include "st_console.h" #include "stats.h" #include "textures.h" #include "v_palette.h" @@ -445,6 +446,8 @@ CocoaVideo::CocoaVideo(const int multisample) [[glView openGLContext] makeCurrentContext]; [m_window setContentView:glView]; + + FConsoleWindow::GetInstance().Show(false); } void CocoaVideo::StartModeIterator(const int bits, const bool fullscreen) diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h new file mode 100644 index 000000000..49b6e0547 --- /dev/null +++ b/src/posix/cocoa/st_console.h @@ -0,0 +1,95 @@ +/* + ** st_console.h + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#ifndef COCOA_ST_CONSOLE_INCLUDED +#define COCOA_ST_CONSOLE_INCLUDED + +@class NSButton; +@class NSProgressIndicator; +@class NSScrollView; +@class NSTextField; +@class NSTextView; +@class NSView; +@class NSWindow; + +struct PalEntry; + + +class FConsoleWindow +{ +public: + static FConsoleWindow& GetInstance(); + + static void CreateInstance(); + static void DeleteInstance(); + + void Show(bool visible); + void ShowFatalError(const char* message); + + void AddText(const char* message); + + void SetTitleText(); + void SetProgressBar(bool visible); + + // FStartupScreen functionality + void Progress(int current, int maximum); + void NetInit(const char* message, int playerCount); + void NetProgress(int count); + void NetDone(); + +private: + NSWindow* m_window; + NSTextView* m_textView; + NSScrollView* m_scrollView; + NSProgressIndicator* m_progressBar; + + NSView* m_netView; + NSTextField* m_netMessageText; + NSTextField* m_netCountText; + NSProgressIndicator* m_netProgressBar; + NSButton* m_netAbortButton; + + unsigned int m_characterCount; + + int m_netCurPos; + int m_netMaxPos; + + FConsoleWindow(); + ~FConsoleWindow(); + + void ExpandTextView(float height); + + void AddText(const PalEntry& color, const char* message); +}; + +#endif // COCOA_ST_CONSOLE_INCLUDED diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm new file mode 100644 index 000000000..e0eba7527 --- /dev/null +++ b/src/posix/cocoa/st_console.mm @@ -0,0 +1,506 @@ +/* + ** st_console.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include "d_main.h" +#include "i_system.h" +#include "st_console.h" +#include "v_text.h" +#include "version.h" + + +static NSColor* RGB(const BYTE red, const BYTE green, const BYTE blue) +{ + return [NSColor colorWithCalibratedRed:red / 255.0f + green:green / 255.0f + blue:blue / 255.0f + alpha:1.0f]; +} + +static NSColor* RGB(const PalEntry& color) +{ + return RGB(color.r, color.g, color.b); +} + +static NSColor* RGB(const DWORD color) +{ + return RGB(PalEntry(color)); +} + + +static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f; +static const CGFloat NET_VIEW_HEIGHT = 88.0f; + + +FConsoleWindow::FConsoleWindow() +: m_window([NSWindow alloc]) +, m_textView([NSTextView alloc]) +, m_scrollView([NSScrollView alloc]) +, m_progressBar(nil) +, m_netView(nil) +, m_netMessageText(nil) +, m_netCountText(nil) +, m_netProgressBar(nil) +, m_netAbortButton(nil) +, m_characterCount(0) +, m_netCurPos(0) +, m_netMaxPos(0) +{ + const CGFloat initialWidth = 512.0f; + const CGFloat initialHeight = 384.0f; + const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight); + + [m_textView initWithFrame:initialRect]; + [m_textView setEditable:NO]; + [m_textView setBackgroundColor:RGB(70, 70, 70)]; + [m_textView setMinSize:NSMakeSize(0.0f, initialHeight)]; + [m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [m_textView setVerticallyResizable:YES]; + [m_textView setHorizontallyResizable:NO]; + [m_textView setAutoresizingMask:NSViewWidthSizable]; + + NSTextContainer* const textContainer = [m_textView textContainer]; + [textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)]; + [textContainer setWidthTracksTextView:YES]; + + [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)]; + [m_scrollView setBorderType:NSNoBorder]; + [m_scrollView setHasVerticalScroller:YES]; + [m_scrollView setHasHorizontalScroller:NO]; + [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [m_scrollView setDocumentView:m_textView]; + + NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()]; + + [m_window initWithContentRect:initialRect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [m_window setMinSize:[m_window frame].size]; + [m_window setTitle:title]; + [m_window center]; + [m_window exitAppOnClose]; + + [[m_window contentView] addSubview:m_scrollView]; + + [m_window makeKeyAndOrderFront:nil]; +} + +FConsoleWindow::~FConsoleWindow() +{ + [m_window close]; +} + + +static FConsoleWindow* s_instance; + + +void FConsoleWindow::CreateInstance() +{ + assert(NULL == s_instance); + s_instance = new FConsoleWindow; +} + +void FConsoleWindow::DeleteInstance() +{ + assert(NULL != s_instance); + delete s_instance; + s_instance = NULL; +} + +FConsoleWindow& FConsoleWindow::GetInstance() +{ + assert(NULL != s_instance); + return *s_instance; +} + + +void FConsoleWindow::Show(const bool visible) +{ + if (visible) + { + [m_window orderFront:nil]; + } + else + { + [m_window orderOut:nil]; + } +} + +void FConsoleWindow::ShowFatalError(const char* const message) +{ + SetProgressBar(false); + NetDone(); + + const CGFloat textViewWidth = [m_scrollView frame].size.width; + + ExpandTextView(-32.0f); + + NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)]; + [quitButton setAutoresizingMask:NSViewMinXMargin]; + [quitButton setBezelStyle:NSRoundedBezelStyle]; + [quitButton setTitle:@"Quit"]; + [quitButton setKeyEquivalent:@"\r"]; + [quitButton setTarget:NSApp]; + [quitButton setAction:@selector(terminate:)]; + + NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)]; + [quitPanel setAutoresizingMask:NSViewWidthSizable]; + [quitPanel addSubview:quitButton]; + + [[m_window contentView] addSubview:quitPanel]; + [m_window orderFront:nil]; + + AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n"); + AddText(PalEntry(255, 255, 170), message); + AddText("\n"); + + // It's impossible to restore minimized window in modal loop + [m_window setStyleMask:[m_window styleMask] & ~NSMiniaturizableWindowMask]; + + [NSApp runModalForWindow:m_window]; +} + + +void FConsoleWindow::AddText(const char* message) +{ + PalEntry color(223, 223, 223); + + char buffer[1024] = {}; + size_t pos = 0; + bool reset = false; + + while (*message != '\0') + { + if ((TEXTCOLOR_ESCAPE == *message && 0 != pos) + || (pos == sizeof buffer - 1) + || reset) + { + buffer[pos] = '\0'; + pos = 0; + reset = false; + + AddText(color, buffer); + } + +#define CHECK_BUFFER_SPACE \ + if (pos >= sizeof buffer - 3) { reset = true; continue; } + + if (TEXTCOLOR_ESCAPE == *message) + { + const BYTE* colorID = reinterpret_cast(message) + 1; + if ('\0' == colorID) + { + break; + } + + const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW); + + if (range != CR_UNDEFINED) + { + color = V_LogColorFromColorRange(range); + } + + message += 2; + } + else if (0x1d == *message) // Opening bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbc'; + ++message; + } + else if (0x1e == *message) // Middle bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY HORIZONTAL + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x94'; + buffer[pos++] = '\x81'; + ++message; + } + else if (0x1f == *message) // Closing bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbe'; + ++message; + } + else + { + buffer[pos++] = *message++; + } + +#undef CHECK_BUFFER_SPACE + } + + if (0 != pos) + { + buffer[pos] = '\0'; + + AddText(color, buffer); + } + + if ([m_window isVisible]) + { + [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + +void FConsoleWindow::AddText(const PalEntry& color, const char* const message) +{ + NSString* const text = [NSString stringWithUTF8String:message]; + + NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:14.0f], NSFontAttributeName, + RGB(color), NSForegroundColorAttributeName, + nil]; + + NSAttributedString* const formattedText = + [[NSAttributedString alloc] initWithString:text + attributes:attributes]; + [[m_textView textStorage] appendAttributedString:formattedText]; + + m_characterCount += [text length]; +} + + +void FConsoleWindow::SetTitleText() +{ + static const CGFloat TITLE_TEXT_HEIGHT = 32.0f; + + NSRect textViewFrame = [m_scrollView frame]; + textViewFrame.size.height -= TITLE_TEXT_HEIGHT; + [m_scrollView setFrame:textViewFrame]; + + const NSRect titleTextRect = NSMakeRect( + 0.0f, + textViewFrame.origin.y + textViewFrame.size.height, + textViewFrame.size.width, + TITLE_TEXT_HEIGHT); + + NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect]; + [titleText setStringValue:[NSString stringWithUTF8String:DoomStartupInfo.Name]]; + [titleText setAlignment:NSCenterTextAlignment]; + [titleText setTextColor:RGB(DoomStartupInfo.FgColor)]; + [titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)]; + [titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]]; + [titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + [titleText setSelectable:NO]; + [titleText setBordered:NO]; + + [[m_window contentView] addSubview:titleText]; +} + +void FConsoleWindow::SetProgressBar(const bool visible) +{ + if ( (!visible && nil == m_progressBar) + || (visible && nil != m_progressBar)) + { + return; + } + + if (visible) + { + ExpandTextView(-PROGRESS_BAR_HEIGHT); + + m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)]; + [m_progressBar setIndeterminate:NO]; + [m_progressBar setAutoresizingMask:NSViewWidthSizable]; + + [[m_window contentView] addSubview:m_progressBar]; + } + else + { + ExpandTextView(PROGRESS_BAR_HEIGHT); + + [m_progressBar removeFromSuperview]; + [m_progressBar release]; + m_progressBar = nil; + } +} + + +void FConsoleWindow::ExpandTextView(const float height) +{ + NSRect textFrame = [m_scrollView frame]; + textFrame.origin.y -= height; + textFrame.size.height += height; + [m_scrollView setFrame:textFrame]; +} + + +void FConsoleWindow::Progress(const int current, const int maximum) +{ + if (nil == m_progressBar) + { + return; + } + + static unsigned int previousTime = I_MSTime(); + unsigned int currentTime = I_MSTime(); + + if (currentTime - previousTime > 33) // approx. 30 FPS + { + previousTime = currentTime; + + [m_progressBar setMaxValue:maximum]; + [m_progressBar setDoubleValue:current]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + + +void FConsoleWindow::NetInit(const char* const message, const int playerCount) +{ + if (nil == m_netView) + { + SetProgressBar(false); + ExpandTextView(-NET_VIEW_HEIGHT); + + // Message like 'Waiting for players' or 'Contacting host' + m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)]; + [m_netMessageText setAutoresizingMask:NSViewWidthSizable]; + [m_netMessageText setDrawsBackground:NO]; + [m_netMessageText setSelectable:NO]; + [m_netMessageText setBordered:NO]; + + // Text with connected/total players count + m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)]; + [m_netCountText setAutoresizingMask:NSViewMinXMargin]; + [m_netCountText setAlignment:NSRightTextAlignment]; + [m_netCountText setDrawsBackground:NO]; + [m_netCountText setSelectable:NO]; + [m_netCountText setBordered:NO]; + + // Connection progress + m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)]; + [m_netProgressBar setAutoresizingMask:NSViewWidthSizable]; + [m_netProgressBar setMaxValue:playerCount]; + + if (0 == playerCount) + { + // Joining game + [m_netProgressBar setIndeterminate:YES]; + [m_netProgressBar startAnimation:nil]; + } + else + { + // Hosting game + [m_netProgressBar setIndeterminate:NO]; + } + + // Cancel network game button + m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)]; + [m_netAbortButton setAutoresizingMask:NSViewMinXMargin]; + [m_netAbortButton setBezelStyle:NSRoundedBezelStyle]; + [m_netAbortButton setTitle:@"Cancel"]; + [m_netAbortButton setKeyEquivalent:@"\r"]; + [m_netAbortButton setTarget:NSApp]; + [m_netAbortButton setAction:@selector(terminate:)]; + + // Panel for controls above + m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)]; + [m_netView setAutoresizingMask:NSViewWidthSizable]; + [m_netView addSubview:m_netMessageText]; + [m_netView addSubview:m_netCountText]; + [m_netView addSubview:m_netProgressBar]; + [m_netView addSubview:m_netAbortButton]; + + NSRect windowRect = [m_window frame]; + windowRect.origin.y -= NET_VIEW_HEIGHT; + windowRect.size.height += NET_VIEW_HEIGHT; + + [m_window setFrame:windowRect display:YES]; + [[m_window contentView] addSubview:m_netView]; + } + + [m_netMessageText setStringValue:[NSString stringWithUTF8String:message]]; + + m_netCurPos = 0; + m_netMaxPos = playerCount; + + NetProgress(1); // You always know about yourself +} + +void FConsoleWindow::NetProgress(const int count) +{ + if (0 == count) + { + ++m_netCurPos; + } + else + { + m_netCurPos = count; + } + + if (nil == m_netView) + { + return; + } + + if (m_netMaxPos > 1) + { + [m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]]; + [m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)]; + } +} + +void FConsoleWindow::NetDone() +{ + if (nil != m_netView) + { + ExpandTextView(NET_VIEW_HEIGHT); + + [m_netView removeFromSuperview]; + [m_netView release]; + m_netView = nil; + + // Released by m_netView + m_netMessageText = nil; + m_netCountText = nil; + m_netProgressBar = nil; + m_netAbortButton = nil; + } +} diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm new file mode 100644 index 000000000..a1db95a0b --- /dev/null +++ b/src/posix/cocoa/st_start.mm @@ -0,0 +1,190 @@ +/* + ** st_start.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#import + +#include "c_cvars.h" +#include "st_console.h" +#include "st_start.h" +#include "v_text.h" + + +FStartupScreen *StartScreen; + + +CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0) + { + self = 0; + } + else if (self > 2) + { + self = 2; + } +} + + +// --------------------------------------------------------------------------- + + +class FBasicStartupScreen : public FStartupScreen +{ +public: + FBasicStartupScreen(int maxProgress, bool showBar); + ~FBasicStartupScreen(); + + virtual void Progress(); + + virtual void NetInit(const char* message, int playerCount); + virtual void NetProgress(int count); + virtual void NetMessage(const char *format, ...); + virtual void NetDone(); + virtual bool NetLoop(bool (*timerCallback)(void*), void* userData); +}; + + +FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar) +: FStartupScreen(maxProgress) +{ + FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance(); + consoleWindow.SetProgressBar(true); + consoleWindow.SetTitleText(); + +#if 0 + // Testing code, please do not remove + consoleWindow.AddText("----------------------------------------------------------------\n"); + consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ " + "This is very very very long message needed to trigger word wrapping...\n\n"); + consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n"); + + consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n"); + consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n"); + consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n"); + consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n"); + consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n"); + consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n"); + consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n"); + consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n"); + consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n"); + consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n"); + consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n"); + consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n"); + consoleWindow.AddText("----------------------------------------------------------------\n"); +#endif // _DEBUG +} + +FBasicStartupScreen::~FBasicStartupScreen() +{ + FConsoleWindow::GetInstance().SetProgressBar(false); +} + + +void FBasicStartupScreen::Progress() +{ + if (CurPos < MaxPos) + { + ++CurPos; + } + + FConsoleWindow::GetInstance().Progress(CurPos, MaxPos); +} + + +void FBasicStartupScreen::NetInit(const char* const message, const int playerCount) +{ + FConsoleWindow::GetInstance().NetInit(message, playerCount); +} + +void FBasicStartupScreen::NetProgress(const int count) +{ + FConsoleWindow::GetInstance().NetProgress(count); +} + +void FBasicStartupScreen::NetMessage(const char* const format, ...) +{ + va_list args; + va_start(args, format); + + FString message; + message.VFormat(format, args); + va_end(args); + + Printf("%s\n", message.GetChars()); +} + +void FBasicStartupScreen::NetDone() +{ + FConsoleWindow::GetInstance().NetDone(); +} + +bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData) +{ + while (true) + { + if (timerCallback(userData)) + { + break; + } + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + + // Do not poll to often + usleep(50000); + } + + return true; +} + + +// --------------------------------------------------------------------------- + + +FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress) +{ + return new FBasicStartupScreen(maxProgress, true); +} + + +// --------------------------------------------------------------------------- + + +void ST_Endoom() +{ + extern void I_ShutdownJoysticks(); + I_ShutdownJoysticks(); + + exit(0); +} diff --git a/src/posix/st_start.cpp b/src/posix/sdl/st_start.cpp similarity index 100% rename from src/posix/st_start.cpp rename to src/posix/sdl/st_start.cpp From 0634205d7f4bd0e9cc507a3e0ff13670d1ac80b6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 18:01:15 +0100 Subject: [PATCH 202/335] - let WildMidi tokenizer handle quoted strings. --- src/wildmidi/wildmidi_lib.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 26e4965ba..19e290f6b 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -573,13 +573,15 @@ static inline int wm_isdigit(int c) { } #define TOKEN_CNT_INC 8 -static char** WM_LC_Tokenize_Line(char *line_data) { +static char** WM_LC_Tokenize_Line(char *line_data) +{ int line_length = strlen(line_data); int token_data_length = 0; int line_ofs = 0; int token_start = 0; char **token_data = NULL; int token_count = 0; + bool in_quotes = false; if (line_length == 0) return NULL; @@ -589,8 +591,11 @@ static char** WM_LC_Tokenize_Line(char *line_data) { if (line_data[line_ofs] == '#') { break; } - - if ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t')) { + if (line_data[line_ofs] == '"') + { + in_quotes = !in_quotes; + } + else if (!in_quotes && ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t'))) { /* whitespace means we aren't in a token */ if (token_start) { token_start = 0; From fe2dcfd588596d5311b31193f0e70630815a9932 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 20:38:08 +0100 Subject: [PATCH 203/335] - refactored the GUS/Timidity player's path building code so that it can also be used by WildMidi. - fixed crash during sound reset - in this case I_ShutdownMusic should not close the WildMidi player. --- src/CMakeLists.txt | 1 + src/pathexpander.cpp | 134 ++++++++++++++++++++++++++++++++++ src/pathexpander.h | 31 ++++++++ src/sound/i_music.cpp | 11 ++- src/sound/i_music.h | 3 +- src/timidity/common.cpp | 88 ---------------------- src/timidity/instrum.cpp | 4 +- src/timidity/instrum_font.cpp | 2 +- src/timidity/instrum_sf2.cpp | 2 +- src/timidity/timidity.cpp | 32 ++++---- src/timidity/timidity.h | 11 +-- 11 files changed, 198 insertions(+), 121 deletions(-) create mode 100644 src/pathexpander.cpp create mode 100644 src/pathexpander.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18fdb992c..f1975a8d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -915,6 +915,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE nodebuild_extract.cpp nodebuild_gl.cpp nodebuild_utility.cpp + pathexpander.cpp p_3dfloors.cpp p_3dmidtex.cpp p_acs.cpp diff --git a/src/pathexpander.cpp b/src/pathexpander.cpp new file mode 100644 index 000000000..d8b912b65 --- /dev/null +++ b/src/pathexpander.cpp @@ -0,0 +1,134 @@ +/* +** pathexpander.cpp +** Utility class for expanding a given path with a range of directories +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "pathexpander.h" +#include "cmdlib.h" +#include "w_wad.h" + +//============================================================================ +// +// +// +//============================================================================ + +static FString BuildPath(const FString &base, const char *name) +{ + FString current; + if (base.IsNotEmpty()) + { + current = base; + if (current[current.Len() - 1] != '/') current += '/'; + } + current += name; + return current; +} + +//============================================================================ +// +// This is meant to find and open files for reading. +// +//============================================================================ + +FileReader *PathExpander::openFileReader(const char *name, int *plumpnum) +{ + FileReader *fp; + FString current_filename; + + if (!name || !(*name)) + { + return 0; + } + + /* First try the given name */ + current_filename = name; + FixPathSeperator(current_filename); + + int lumpnum = Wads.CheckNumForFullName(current_filename); + + if (openmode != OM_FILE) + { + if (lumpnum >= 0) + { + fp = Wads.ReopenLumpNum(lumpnum); + if (plumpnum) *plumpnum = lumpnum; + return fp; + } + if (openmode == OM_LUMP) // search the path list when not loading the main config + { + for (unsigned int plp = PathList.Size(); plp-- != 0; ) + { /* Try along the path then */ + current_filename = BuildPath(PathList[plp], name); + lumpnum = Wads.CheckNumForFullName(current_filename); + if (lumpnum >= 0) + { + fp = Wads.ReopenLumpNum(lumpnum); + if (plumpnum) *plumpnum = lumpnum; + return fp; + } + } + return NULL; + } + } + if (plumpnum) *plumpnum = -1; + + + fp = new FileReader; + if (fp->Open(current_filename)) return fp; + + if (name[0] != '/') + { + for (unsigned int plp = PathList.Size(); plp-- != 0; ) + { /* Try along the path then */ + current_filename = BuildPath(PathList[plp], name); + if (fp->Open(current_filename)) return fp; + } + } + delete fp; + + /* Nothing could be opened. */ + return NULL; +} + +/* This adds a directory to the path list */ +void PathExpander::addToPathlist(const char *s) +{ + FString copy = s; + FixPathSeperator(copy); + PathList.Push(copy); +} + +void PathExpander::clearPathlist() +{ + PathList.Clear(); +} diff --git a/src/pathexpander.h b/src/pathexpander.h new file mode 100644 index 000000000..556598071 --- /dev/null +++ b/src/pathexpander.h @@ -0,0 +1,31 @@ +#ifndef __PATHEXPANDER_H +#define __PATHEXPANDER_H + +#include "tarray.h" +#include "zstring.h" +#include "files.h" + +class PathExpander +{ + TArray PathList; + +public: + int openmode; + + enum + { + OM_FILEORLUMP = 0, + OM_LUMP, + OM_FILE + }; + + PathExpander(int om = OM_FILEORLUMP) + { + openmode = om; + } + void addToPathlist(const char *s); + void clearPathlist(); + FileReader *openFileReader(const char *name, int *plumpnum); +}; + +#endif diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 721be5192..121c0b9fb 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -162,7 +162,7 @@ void I_InitMusic (void) if (!setatterm) { setatterm = true; - atterm (I_ShutdownMusic); + atterm (I_ShutdownMusicExit); #ifndef _WIN32 signal (SIGCHLD, ChildSigHandler); @@ -178,7 +178,7 @@ void I_InitMusic (void) // //========================================================================== -void I_ShutdownMusic(void) +void I_ShutdownMusic(bool onexit) { if (MusicDown) return; @@ -189,12 +189,17 @@ void I_ShutdownMusic(void) assert (currSong == NULL); } Timidity::FreeAll(); - WildMidi_Shutdown(); + if (onexit) WildMidi_Shutdown(); #ifdef _WIN32 I_ShutdownMusicWin32(); #endif // _WIN32 } +void I_ShutdownMusicExit() +{ + I_ShutdownMusic(true); +} + //========================================================================== // diff --git a/src/sound/i_music.h b/src/sound/i_music.h index f6a6dbadd..ee05d8caf 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -43,7 +43,8 @@ struct FOptionValues; // MUSIC I/O // void I_InitMusic (); -void I_ShutdownMusic (); +void I_ShutdownMusic (bool onexit = false); +void I_ShutdownMusicExit (); void I_BuildMIDIMenuList (FOptionValues *); void I_UpdateMusic (); diff --git a/src/timidity/common.cpp b/src/timidity/common.cpp index 92d9b009a..57fd26e0c 100644 --- a/src/timidity/common.cpp +++ b/src/timidity/common.cpp @@ -35,82 +35,6 @@ namespace Timidity { -static TArray PathList; - -FString BuildPath(FString base, const char *name) -{ - FString current; - if (base.IsNotEmpty()) - { - current = base; - if (current[current.Len() - 1] != '/') current += '/'; - } - current += name; - return current; -} - -/* This is meant to find and open files for reading. */ -FileReader *open_filereader(const char *name, int open, int *plumpnum) -{ - FileReader *fp; - FString current_filename; - - if (!name || !(*name)) - { - return 0; - } - - /* First try the given name */ - current_filename = name; - FixPathSeperator(current_filename); - - int lumpnum = Wads.CheckNumForFullName(current_filename); - - if (open != OM_FILE) - { - if (lumpnum >= 0) - { - fp = Wads.ReopenLumpNum(lumpnum); - if (plumpnum) *plumpnum = lumpnum; - return fp; - } - if (open == OM_LUMP) // search the path list when not loading the main config - { - for (unsigned int plp = PathList.Size(); plp-- != 0; ) - { /* Try along the path then */ - current_filename = BuildPath(PathList[plp], name); - lumpnum = Wads.CheckNumForFullName(current_filename); - if (lumpnum >= 0) - { - fp = Wads.ReopenLumpNum(lumpnum); - if (plumpnum) *plumpnum = lumpnum; - return fp; - } - } - return NULL; - } - } - if (plumpnum) *plumpnum = -1; - - - fp = new FileReader; - if (fp->Open(current_filename)) return fp; - - if (name[0] != '/') - { - for (unsigned int plp = PathList.Size(); plp-- != 0; ) - { /* Try along the path then */ - current_filename = BuildPath(PathList[plp], name); - if (fp->Open(current_filename)) return fp; - } - } - delete fp; - - /* Nothing could be opened. */ - current_filename = ""; - return NULL; -} - /* This'll allocate memory or die. */ @@ -132,17 +56,5 @@ void *safe_malloc(size_t count) return 0; // Unreachable. } -/* This adds a directory to the path list */ -void add_to_pathlist(const char *s) -{ - FString copy = s; - FixPathSeperator(copy); - PathList.Push(copy); -} - -void clear_pathlist() -{ - PathList.Clear(); -} } diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index 7454ca7a4..a8c7b5f7c 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -159,12 +159,12 @@ static Instrument *load_instrument(Renderer *song, const char *name, int percuss if (!name) return 0; /* Open patch file */ - if ((fp = open_filereader(name, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(name, NULL)) == NULL) { /* Try with various extensions */ FString tmp = name; tmp += ".pat"; - if ((fp = open_filereader(tmp, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) { #ifdef __unix__ // Windows isn't case-sensitive. tmp.ToUpper(); diff --git a/src/timidity/instrum_font.cpp b/src/timidity/instrum_font.cpp index 995558bd4..069eb9c84 100644 --- a/src/timidity/instrum_font.cpp +++ b/src/timidity/instrum_font.cpp @@ -54,7 +54,7 @@ void font_add(const char *filename, int load_order) } else { - FileReader *fp = open_filereader(filename, openmode, NULL); + FileReader *fp = pathExpander.openFileReader(filename, NULL); if (fp != NULL) { diff --git a/src/timidity/instrum_sf2.cpp b/src/timidity/instrum_sf2.cpp index dae330644..c4cf0bc81 100644 --- a/src/timidity/instrum_sf2.cpp +++ b/src/timidity/instrum_sf2.cpp @@ -1502,7 +1502,7 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend void SFFile::LoadSample(SFSample *sample) { - FileReader *fp = open_filereader(Filename, openmode, NULL); + FileReader *fp = pathExpander.openFileReader(Filename, NULL); DWORD i; if (fp == NULL) diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 0f0fcdeb5..1d74c5afc 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -42,10 +42,10 @@ CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) namespace Timidity { +PathExpander pathExpander; ToneBank *tonebank[MAXBANK], *drumset[MAXBANK]; static FString def_instr_name; -int openmode = OM_FILEORLUMP; static int read_config_file(const char *name, bool ismain) { @@ -62,21 +62,21 @@ static int read_config_file(const char *name, bool ismain) return (-1); } - if (ismain) openmode = OM_FILEORLUMP; + if (ismain) pathExpander.openmode = PathExpander::OM_FILEORLUMP; - if (!(fp = open_filereader(name, openmode, &lumpnum))) + if (!(fp = pathExpander.openFileReader(name, &lumpnum))) return -1; if (ismain) { if (lumpnum > 0) { - openmode = OM_LUMP; - clear_pathlist(); // when reading from a PK3 we won't want to use any external path + pathExpander.openmode = PathExpander::OM_LUMP; + pathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path } else { - openmode = OM_FILE; + pathExpander.openmode = PathExpander::OM_FILE; } } @@ -288,7 +288,7 @@ static int read_config_file(const char *name, bool ismain) return -2; } for (i = 1; i < words; i++) - add_to_pathlist(w[i]); + pathExpander.addToPathlist(w[i]); } else if (!strcmp(w[0], "source")) { @@ -532,15 +532,15 @@ int LoadConfig(const char *filename) * file itself since that file should contain any other directory * that needs to be added to the search path. */ - clear_pathlist(); + pathExpander.clearPathlist(); #ifdef _WIN32 - add_to_pathlist("C:\\TIMIDITY"); - add_to_pathlist("\\TIMIDITY"); - add_to_pathlist(progdir); + pathExpander.addToPathlist("C:\\TIMIDITY"); + pathExpander.addToPathlist("\\TIMIDITY"); + pathExpander.addToPathlist(progdir); #else - add_to_pathlist("/usr/local/lib/timidity"); - add_to_pathlist("/etc/timidity"); - add_to_pathlist("/etc"); + pathExpander.addToPathlist("/usr/local/lib/timidity"); + pathExpander.addToPathlist("/etc/timidity"); + pathExpander.addToPathlist("/etc"); #endif /* Some functions get aggravated if not even the standard banks are available. */ @@ -579,10 +579,10 @@ int LoadDMXGUS() if (ultradir.IsNotEmpty()) { ultradir += "/midi"; - add_to_pathlist(ultradir.GetChars()); + pathExpander.addToPathlist(ultradir.GetChars()); } // Load DMXGUS lump and patches from gus_patchdir - add_to_pathlist(gus_patchdir); + pathExpander.addToPathlist(gus_patchdir); char readbuffer[1024]; long size = data.GetLength(); diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 6c46317dd..0a21a41b9 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -21,6 +21,7 @@ #define TIMIDITY_H #include "doomtype.h" +#include "pathexpander.h" class FileReader; @@ -172,17 +173,8 @@ extern __inline__ double pow_x87_inline(double x,double y) common.h */ -#define OM_FILEORLUMP 0 -#define OM_LUMP 1 -#define OM_FILE 2 - -extern void add_to_pathlist(const char *s); -extern void clear_pathlist(); extern void *safe_malloc(size_t count); -FileReader *open_filereader(const char *name, int open, int *plumpnum); -extern int openmode; - /* controls.h */ @@ -627,6 +619,7 @@ int LoadConfig(const char *filename); int LoadDMXGUS(); extern int LoadConfig(); extern void FreeAll(); +extern PathExpander pathExpander; extern ToneBank *tonebank[MAXBANK]; extern ToneBank *drumset[MAXBANK]; From c3862d910142ac726358f0838aeb5d9e535cefd0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 21:18:46 +0100 Subject: [PATCH 204/335] - use PathExpander class for WildMidi's file access functions so that it can find Timdity's data on its own. --- src/wildmidi/file_io.cpp | 49 +++++++++++++++++++++++++++++++---- src/wildmidi/file_io.h | 2 +- src/wildmidi/wildmidi_lib.cpp | 2 +- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/wildmidi/file_io.cpp b/src/wildmidi/file_io.cpp index c2ef55715..50a2a6b6c 100644 --- a/src/wildmidi/file_io.cpp +++ b/src/wildmidi/file_io.cpp @@ -38,18 +38,56 @@ #include "../files.h" #include "wm_error.h" #include "file_io.h" +#include "pathexpander.h" +#include "cmdlib.h" -unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size) +static PathExpander wmPathExpander; + +unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size, bool ismain) { - FileReader file; + FileReader *fp; + int lumpnum; - if (!file.Open(filename)) + if (ismain) + { + wmPathExpander.openmode = PathExpander::OM_FILEORLUMP; + wmPathExpander.clearPathlist(); +#ifdef _WIN32 + wmPathExpander.addToPathlist("C:\\TIMIDITY"); + wmPathExpander.addToPathlist("\\TIMIDITY"); + wmPathExpander.addToPathlist(progdir); +#else + wmPathExpander.addToPathlist("/usr/local/lib/timidity"); + wmPathExpander.addToPathlist("/etc/timidity"); + wmPathExpander.addToPathlist("/etc"); +#endif + } + + if (!(fp = wmPathExpander.openFileReader(filename, &lumpnum))) + return NULL; + + if (ismain) + { + if (lumpnum > 0) + { + wmPathExpander.openmode = PathExpander::OM_LUMP; + wmPathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path + } + else + { + wmPathExpander.openmode = PathExpander::OM_FILE; + } + } + + + + if (fp == NULL) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); return NULL; } - long fsize = file.GetLength(); + long fsize = fp->GetLength(); if (fsize > WM_MAXFILESIZE) { @@ -66,7 +104,8 @@ unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size) return NULL; } - file.Read(data, fsize); + fp->Read(data, fsize); + delete fp; data[fsize] = 0; *size = fsize; return data; diff --git a/src/wildmidi/file_io.h b/src/wildmidi/file_io.h index d38caffbb..550a8a4b2 100644 --- a/src/wildmidi/file_io.h +++ b/src/wildmidi/file_io.h @@ -28,6 +28,6 @@ #define __FILE_IO_H #define WM_MAXFILESIZE 0x1fffffff -extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size); +extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size, bool mainfile = false); #endif /* __FILE_IO_H */ diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 19e290f6b..eebd42830 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -645,7 +645,7 @@ static int WM_LoadConfig(const char *config_file) { char **line_tokens = NULL; int token_count = 0; - config_buffer = (char *) _WM_BufferFile(config_file, &config_size); + config_buffer = (char *) _WM_BufferFile(config_file, &config_size, true); if (!config_buffer) { WM_FreePatches(); return -1; From e0f9a59a9ac00291abdbda2c19e602a7e29937dd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 22:14:40 +0100 Subject: [PATCH 205/335] - add WildMidi config file CVAR to menu. --- wadsrc/static/menudef.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index eef2629d3..94de2b96c 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1608,6 +1608,9 @@ OptionMenu AdvSoundOptions Option "Reverb", "timidity_reverb", "OnOff" Option "Chorus", "timidity_chorus", "OnOff" Slider "Relative volume", "timidity_mastervolume", 0, 4, 0.2, 1 + StaticText " " + StaticText "WildMidi", 1 + TextField "WildMidi config file", "wildmidi_config" } /*======================================= From 0cc4bd56d189958f1b7652312de634eea49494e2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Dec 2015 23:18:39 +0100 Subject: [PATCH 206/335] - removed the original WildMidi loader and the main playback function because none of those is actually being used anymore. --- src/wildmidi/wildmidi_lib.cpp | 1374 --------------------------------- src/wildmidi/wildmidi_lib.h | 5 - 2 files changed, 1379 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index eebd42830..4372f8436 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -151,10 +151,6 @@ struct _event_data { struct _mdi { int lock; unsigned long int samples_to_mix; - struct _event *events; - struct _event *current_event; - unsigned long int event_count; - unsigned long int events_size; /* try to stay optimally ahead to prevent reallocs */ unsigned short midi_master_vol; struct _WM_Info info; @@ -173,13 +169,6 @@ struct _mdi { struct _rvb *reverb; }; -struct _event { - void (*do_event)(struct _mdi *mdi, struct _event_data *data); - struct _event_data event_data; - unsigned long int samples_to_next; - unsigned long int samples_to_next_fixed; -}; - #define FPBITS 10 #define FPMASK ((1L<event_count >= mdi->events_size) { - mdi->events_size += MEM_CHUNK; - mdi->events = (struct _event*)realloc(mdi->events, - (mdi->events_size * sizeof(struct _event))); - } -} - static void WM_InitPatches(void) { int i; for (i = 0; i < 128; i++) { @@ -2005,257 +1986,6 @@ static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { UNUSED(data); /* NOOP, to please the compiler gods */ } -static void WM_ResetToStart(midi * handle) { - struct _mdi *mdi = (struct _mdi *) handle; - - mdi->current_event = mdi->events; - mdi->samples_to_mix = 0; - mdi->info.current_sample = 0; - - do_sysex_roland_reset(mdi, NULL); -} - -static int midi_setup_noteoff(struct _mdi *mdi, unsigned char channel, - unsigned char note, unsigned char velocity) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_note_off; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = (note << 8) - | velocity; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_note_off; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = (note << 8) | velocity; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - return 0; -} - -static int midi_setup_noteon(struct _mdi *mdi, unsigned char channel, - unsigned char note, unsigned char velocity) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_note_on; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = (note << 8) - | velocity; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_note_on; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = (note << 8) | velocity; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - - if (mdi->channel[channel].isdrum) - load_patch(mdi, ((mdi->channel[channel].bank << 8) | (note | 0x80))); - return 0; -} - -static int midi_setup_aftertouch(struct _mdi *mdi, unsigned char channel, - unsigned char note, unsigned char pressure) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_aftertouch; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = (note << 8) - | pressure; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_aftertouch; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = (note << 8) | pressure; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - return 0; -} - -static int midi_setup_control(struct _mdi *mdi, unsigned char channel, - unsigned char controller, unsigned char setting) { - void (*tmp_event)(struct _mdi *mdi, struct _event_data *data) = NULL; - - switch (controller) { - case 0: - tmp_event = *do_control_bank_select; - mdi->channel[channel].bank = setting; - break; - case 6: - tmp_event = *do_control_data_entry_course; - break; - case 7: - tmp_event = *do_control_channel_volume; - mdi->channel[channel].volume = setting; - break; - case 8: - tmp_event = *do_control_channel_balance; - break; - case 10: - tmp_event = *do_control_channel_pan; - break; - case 11: - tmp_event = *do_control_channel_expression; - break; - case 38: - tmp_event = *do_control_data_entry_fine; - break; - case 64: - tmp_event = *do_control_channel_hold; - break; - case 96: - tmp_event = *do_control_data_increment; - break; - case 97: - tmp_event = *do_control_data_decrement; - break; - case 98: - case 99: - tmp_event = *do_control_non_registered_param; - break; - case 100: - tmp_event = *do_control_registered_param_fine; - break; - case 101: - tmp_event = *do_control_registered_param_course; - break; - case 120: - tmp_event = *do_control_channel_sound_off; - break; - case 121: - tmp_event = *do_control_channel_controllers_off; - break; - case 123: - tmp_event = *do_control_channel_notes_off; - break; - default: - return 0; - } - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = tmp_event; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = setting; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = tmp_event; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = setting; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - return 0; -} - -static int midi_setup_patch(struct _mdi *mdi, unsigned char channel, - unsigned char patch) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_patch; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = patch; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_patch; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = patch; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - if (mdi->channel[channel].isdrum) { - mdi->channel[channel].bank = patch; - } else { - load_patch(mdi, ((mdi->channel[channel].bank << 8) | patch)); - mdi->channel[channel].patch = get_patch_data( - ((mdi->channel[channel].bank << 8) | patch)); - } - return 0; -} - -static int midi_setup_channel_pressure(struct _mdi *mdi, unsigned char channel, - unsigned char pressure) { - - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_channel_pressure; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = pressure; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_channel_pressure; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = pressure; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - - return 0; -} - -static int midi_setup_pitch(struct _mdi *mdi, unsigned char channel, - unsigned short pitch) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_pitch; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = pitch; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_pitch; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = pitch; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - return 0; -} - -static int midi_setup_sysex_roland_drum_track(struct _mdi *mdi, - unsigned char channel, unsigned short setting) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = - *do_sysex_roland_drum_track; - mdi->events[mdi->event_count - 1].event_data.channel = channel; - mdi->events[mdi->event_count - 1].event_data.data = setting; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_sysex_roland_drum_track; - mdi->events[mdi->event_count].event_data.channel = channel; - mdi->events[mdi->event_count].event_data.data = setting; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - - if (setting > 0) { - mdi->channel[channel].isdrum = 1; - } else { - mdi->channel[channel].isdrum = 0; - } - - return 0; -} - -static int midi_setup_sysex_roland_reset(struct _mdi *mdi) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].do_event = *do_sysex_roland_reset; - mdi->events[mdi->event_count - 1].event_data.channel = 0; - mdi->events[mdi->event_count - 1].event_data.data = 0; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = *do_sysex_roland_reset; - mdi->events[mdi->event_count].event_data.channel = 0; - mdi->events[mdi->event_count].event_data.data = 0; - mdi->events[mdi->event_count].samples_to_next = 0; - mdi->event_count++; - } - return 0; -} - static int add_handle(void * handle) { struct _hndl *tmp_handle = NULL; @@ -2299,15 +2029,6 @@ Init_MDI(void) { load_patch(mdi, 0x0000); - mdi->events_size = MEM_CHUNK; - mdi->events = (struct _event*)malloc(mdi->events_size * sizeof(struct _event)); - mdi->events[0].do_event = NULL; - mdi->events[0].event_data.channel = 0; - mdi->events[0].event_data.data = 0; - mdi->events[0].samples_to_next = 0; - mdi->event_count++; - - mdi->current_event = mdi->events; mdi->samples_to_mix = 0; mdi->info.current_sample = 0; mdi->info.total_midi_time = 0; @@ -2341,7 +2062,6 @@ static void freeMDI(struct _mdi *mdi) { free(mdi->patches); } - free(mdi->events); free(mdi->tmp_info); _WM_free_reverb(mdi->reverb); free(mdi->mix_buffer); @@ -2392,807 +2112,6 @@ static unsigned long int get_decay_samples(struct _patch *patch, unsigned char n return decay_samples; } -static struct _mdi * -WM_ParseNewMidi(unsigned char *midi_data, unsigned int midi_size) { - struct _mdi *mdi; - unsigned int tmp_val; - unsigned int midi_type; - unsigned int track_size; - unsigned char **tracks; - unsigned int end_of_tracks = 0; - unsigned int no_tracks; - unsigned int i; - unsigned int divisions = 96; - unsigned int tempo = 500000; - float samples_per_delta_f = 0.0; - float microseconds_per_pulse = 0.0; - float pulses_per_second = 0.0; - - unsigned long int sample_count = 0; - float sample_count_tmp = 0; - float sample_remainder = 0; - unsigned char *sysex_store = NULL; - unsigned long int sysex_store_len = 0; - - unsigned long int *track_delta; - unsigned char *track_end; - unsigned long int smallest_delta = 0; - unsigned long int subtract_delta = 0; - unsigned long int tmp_length = 0; - unsigned char current_event = 0; - unsigned char current_event_ch = 0; - unsigned char *running_event; - unsigned long int decay_samples = 0; - - if (memcmp(midi_data, "RIFF", 4) == 0) { - midi_data += 20; - midi_size -= 20; - } - if (memcmp(midi_data, "MThd", 4)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0); - return NULL; - } - midi_data += 4; - midi_size -= 4; - - if (midi_size < 10) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); - return NULL; - } - - /* - * Get Midi Header Size - must always be 6 - */ - tmp_val = *midi_data++ << 24; - tmp_val |= *midi_data++ << 16; - tmp_val |= *midi_data++ << 8; - tmp_val |= *midi_data++; - midi_size -= 4; - if (tmp_val != 6) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0); - return NULL; - } - - /* - * Get Midi Format - we only support 0, 1 & 2 - */ - tmp_val = *midi_data++ << 8; - tmp_val |= *midi_data++; - midi_size -= 2; - if (tmp_val > 2) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); - return NULL; - } - midi_type = tmp_val; - - /* - * Get No. of Tracks - */ - tmp_val = *midi_data++ << 8; - tmp_val |= *midi_data++; - midi_size -= 2; - if (tmp_val < 1) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(no tracks)", 0); - return NULL; - } - no_tracks = tmp_val; - - /* - * Check that type 0 midi file has only 1 track - */ - if ((midi_type == 0) && (no_tracks > 1)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(expected 1 track for type 0 midi file, found more)", 0); - return NULL; - } - - /* - * Get Divisions - */ - divisions = *midi_data++ << 8; - divisions |= *midi_data++; - midi_size -= 2; - if (divisions & 0x00008000) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); - return NULL; - } - - if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { - float bpm_f = (float) (60000000 / tempo); - tempo = 60000000 / (unsigned long int) bpm_f; - } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { - float bpm_fr = (float) (60000000 / tempo) + 0.5f; - tempo = 60000000 / (unsigned long int) bpm_fr; - } - /* Slow but needed for accuracy */ - microseconds_per_pulse = (float) tempo / (float) divisions; - pulses_per_second = 1000000.0f / microseconds_per_pulse; - samples_per_delta_f = (float) _WM_SampleRate / pulses_per_second; - - mdi = Init_MDI(); - - tracks = (unsigned char**)malloc(sizeof(unsigned char *) * no_tracks); - track_delta = (unsigned long*)malloc(sizeof(unsigned long int) * no_tracks); - track_end = (unsigned char*)malloc(sizeof(unsigned char) * no_tracks); - running_event = (unsigned char*)malloc(sizeof(unsigned char) * no_tracks); - - for (i = 0; i < no_tracks; i++) { - if (midi_size < 8) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); - goto _end; - } - if (memcmp(midi_data, "MTrk", 4) != 0) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing track header)", 0); - goto _end; - } - midi_data += 4; - midi_size -= 4; - - track_size = *midi_data++ << 24; - track_size |= *midi_data++ << 16; - track_size |= *midi_data++ << 8; - track_size |= *midi_data++; - midi_size -= 4; - if (midi_size < track_size) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); - goto _end; - } - if ((midi_data[track_size - 3] != 0xFF) - || (midi_data[track_size - 2] != 0x2F) - || (midi_data[track_size - 1] != 0x00)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing EOT)", 0); - goto _end; - } - tracks[i] = midi_data; - midi_data += track_size; - midi_size -= track_size; - track_end[i] = 0; - running_event[i] = 0; - track_delta[i] = 0; - decay_samples = 0; - while (*tracks[i] > 0x7F) { - track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - } - track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - } - - /* - * Handle type 0 & 1 the same, but type 2 differently - */ - switch (midi_type) { - case 0: - case 1: - /* Type 0 & 1 can use the same code */ - while (end_of_tracks != no_tracks) { - smallest_delta = 0; - for (i = 0; i < no_tracks; i++) { - if (track_end[i]) - continue; - - if (track_delta[i]) { - track_delta[i] -= subtract_delta; - if (track_delta[i]) { - if ((!smallest_delta) - || (smallest_delta > track_delta[i])) { - smallest_delta = track_delta[i]; - } - continue; - } - } - do { - if (*tracks[i] > 0x7F) { - current_event = *tracks[i]; - tracks[i]++; - } else { - current_event = running_event[i]; - if (running_event[i] < 0x80) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); - goto _end; - } - } - current_event_ch = current_event & 0x0F; - switch (current_event >> 4) { - case 0x8: - NOTEOFF: midi_setup_noteoff(mdi, current_event_ch, - tracks[i][0], tracks[i][1]); - /* To better calculate samples needed after the end of midi, - * we calculate samples for decay for note off */ - { - unsigned long int tmp_decay_samples = 0; - struct _patch *tmp_patch = NULL; - if (mdi->channel[current_event_ch].isdrum) { - tmp_patch = get_patch_data( - ((mdi->channel[current_event_ch].bank << 8) - | tracks[i][0] | 0x80)); - /* if (tmp_patch == NULL) - printf("Drum patch not loaded 0x%02x on channel %i\n",((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80),current_event_ch);*/ - } else { - tmp_patch = mdi->channel[current_event_ch].patch; - /* if (tmp_patch == NULL) - printf("Channel %i patch not loaded\n", current_event_ch);*/ - } - tmp_decay_samples = get_decay_samples(tmp_patch, - tracks[i][0]); - /* if the note off decay is more than the decay we currently tracking then - * we set it to new decay. */ - if (tmp_decay_samples > decay_samples) { - decay_samples = tmp_decay_samples; - } - } - - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0x9: - if (tracks[i][1] == 0) { - goto NOTEOFF; - } - midi_setup_noteon(mdi, (current_event & 0x0F), tracks[i][0], - tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xA: - midi_setup_aftertouch(mdi, (current_event & 0x0F), - tracks[i][0], tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xB: - midi_setup_control(mdi, (current_event & 0x0F), - tracks[i][0], tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xC: - midi_setup_patch(mdi, (current_event & 0x0F), *tracks[i]); - tracks[i]++; - running_event[i] = current_event; - break; - case 0xD: - midi_setup_channel_pressure(mdi, (current_event & 0x0F), - *tracks[i]); - tracks[i]++; - running_event[i] = current_event; - break; - case 0xE: - midi_setup_pitch(mdi, (current_event & 0x0F), - ((tracks[i][1] << 7) | (tracks[i][0] & 0x7F))); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xF: /* Meta Event */ - if (current_event == 0xFF) { - if (tracks[i][0] == 0x02) { /* Copyright Event */ - /* Get Length */ - tmp_length = 0; - tracks[i]++; - while (*tracks[i] > 0x7f) { - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i]++; - } - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - /* Copy copyright info in the getinfo struct */ - if (mdi->info.copyright) { - mdi->info.copyright = (char*)realloc( - mdi->info.copyright, - (strlen(mdi->info.copyright) + 1 - + tmp_length + 1)); - strncpy( - &mdi->info.copyright[strlen( - mdi->info.copyright) + 1], - (char *) tracks[i], tmp_length); - mdi->info.copyright[strlen(mdi->info.copyright) - + 1 + tmp_length] = '\0'; - mdi->info.copyright[strlen(mdi->info.copyright)] = '\n'; - - } else { - mdi->info.copyright = (char*)malloc(tmp_length + 1); - strncpy(mdi->info.copyright, (char *) tracks[i], - tmp_length); - mdi->info.copyright[tmp_length] = '\0'; - } - tracks[i] += tmp_length + 1; - } else if ((tracks[i][0] == 0x2F) - && (tracks[i][1] == 0x00)) { - /* End of Track */ - end_of_tracks++; - track_end[i] = 1; - goto NEXT_TRACK; - } else if ((tracks[i][0] == 0x51) - && (tracks[i][1] == 0x03)) { - /* Tempo */ - tempo = (tracks[i][2] << 16) + (tracks[i][3] << 8) - + tracks[i][4]; - tracks[i] += 5; - if (!tempo) - tempo = 500000; - - if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { - float bpm_f = (float) (60000000 / tempo); - tempo = 60000000 - / (unsigned long int) bpm_f; - } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { - float bpm_fr = (float) (60000000 / tempo) - + 0.5f; - tempo = 60000000 - / (unsigned long int) bpm_fr; - } - /* Slow but needed for accuracy */ - microseconds_per_pulse = (float) tempo - / (float) divisions; - pulses_per_second = 1000000.0f - / microseconds_per_pulse; - samples_per_delta_f = (float) _WM_SampleRate - / pulses_per_second; - - } else { - tmp_length = 0; - tracks[i]++; - while (*tracks[i] > 0x7f) { - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i]++; - } - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i] += tmp_length + 1; - } - } else if ((current_event == 0xF0) - || (current_event == 0xF7)) { - /* Roland Sysex Events */ - unsigned long int sysex_len = 0; - while (*tracks[i] > 0x7F) { - sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - } - sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - - running_event[i] = 0; - - sysex_store = (unsigned char*)realloc(sysex_store, - sizeof(unsigned char) - * (sysex_store_len + sysex_len)); - memcpy(&sysex_store[sysex_store_len], tracks[i], - sysex_len); - sysex_store_len += sysex_len; - - if (sysex_store[sysex_store_len - 1] == 0xF7) { - unsigned char tmpsysexdata[] = { 0x41, 0x10, 0x42, 0x12 }; - if (memcmp(tmpsysexdata, sysex_store, 4) == 0) { - /* checksum */ - unsigned char sysex_cs = 0; - unsigned int sysex_ofs = 4; - do { - sysex_cs += sysex_store[sysex_ofs]; - if (sysex_cs > 0x7F) { - sysex_cs -= 0x80; - } - sysex_ofs++; - } while (sysex_store[sysex_ofs + 1] != 0xF7); - sysex_cs = 128 - sysex_cs; - /* is roland sysex message valid */ - if (sysex_cs == sysex_store[sysex_ofs]) { - /* process roland sysex event */ - if (sysex_store[4] == 0x40) { - if (((sysex_store[5] & 0xF0) == 0x10) - && (sysex_store[6] == 0x15)) { - /* Roland Drum Track Setting */ - unsigned char sysex_ch = 0x0F - & sysex_store[5]; - if (sysex_ch == 0x00) { - sysex_ch = 0x09; - } else if (sysex_ch <= 0x09) { - sysex_ch -= 1; - } - midi_setup_sysex_roland_drum_track( - mdi, sysex_ch, - sysex_store[7]); - } else if ((sysex_store[5] == 0x00) - && (sysex_store[6] == 0x7F) - && (sysex_store[7] == 0x00)) { - /* Roland GS Reset */ - midi_setup_sysex_roland_reset(mdi); - } - } - } - } - free(sysex_store); - sysex_store = NULL; - sysex_store_len = 0; - } - tracks[i] += sysex_len; - } else { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta event)", 0); - goto _end; - } - break; - default: - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized event)", 0); - goto _end; - } - while (*tracks[i] > 0x7F) { - track_delta[i] = (track_delta[i] << 7) - + (*tracks[i] & 0x7F); - tracks[i]++; - } - track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - } while (!track_delta[i]); - if ((!smallest_delta) || (smallest_delta > track_delta[i])) { - smallest_delta = track_delta[i]; - } - NEXT_TRACK: continue; - } - - subtract_delta = smallest_delta; - sample_count_tmp = (((float) smallest_delta * samples_per_delta_f) - + sample_remainder); - sample_count = (unsigned long int) sample_count_tmp; - sample_remainder = sample_count_tmp - (float) sample_count; - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].samples_to_next += sample_count; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = NULL; - mdi->events[mdi->event_count].event_data.channel = 0; - mdi->events[mdi->event_count].event_data.data = 0; - mdi->events[mdi->event_count].samples_to_next = sample_count; - mdi->event_count++; - } - mdi->info.approx_total_samples += sample_count; - /* printf("Decay Samples = %lu\n",decay_samples);*/ - if (decay_samples > sample_count) { - decay_samples -= sample_count; - } else { - decay_samples = 0; - } - } - break; - - case 2: /* Type 2 has to be handled differently */ - for (i = 0; i < no_tracks; i++) { - sample_remainder = 0.0; - decay_samples = 0; - track_delta[i] = 0; - do { - if(track_delta[i]) { - sample_count_tmp = (((float) track_delta[i] * samples_per_delta_f) - + sample_remainder); - sample_count = (unsigned long int) sample_count_tmp; - sample_remainder = sample_count_tmp - (float) sample_count; - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].samples_to_next += sample_count; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = NULL; - mdi->events[mdi->event_count].event_data.channel = 0; - mdi->events[mdi->event_count].event_data.data = 0; - mdi->events[mdi->event_count].samples_to_next = sample_count; - mdi->event_count++; - } - mdi->info.approx_total_samples += sample_count; - /* printf("Decay Samples = %lu\n",decay_samples);*/ - if (decay_samples > sample_count) { - decay_samples -= sample_count; - } else { - decay_samples = 0; - } - } - if (*tracks[i] > 0x7F) { - current_event = *tracks[i]; - tracks[i]++; - } else { - current_event = running_event[i]; - if (running_event[i] < 0x80) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); - goto _end; - } - } - current_event_ch = current_event & 0x0F; - switch (current_event >> 4) { - case 0x8: - NOTEOFF2: midi_setup_noteoff(mdi, current_event_ch, - tracks[i][0], tracks[i][1]); - /* To better calculate samples needed after the end of midi, - * we calculate samples for decay for note off */ - { - unsigned long int tmp_decay_samples = 0; - struct _patch *tmp_patch = NULL; - - if (mdi->channel[current_event_ch].isdrum) { - tmp_patch = get_patch_data( - ((mdi->channel[current_event_ch].bank << 8) - | tracks[i][0] | 0x80)); - /* if (tmp_patch == NULL) - printf("Drum patch not loaded 0x%02x on channel %i\n",((mdi->channel[current_event_ch].bank << 8) | tracks[i][0] | 0x80),current_event_ch);*/ - } else { - tmp_patch = mdi->channel[current_event_ch].patch; - /* if (tmp_patch == NULL) - printf("Channel %i patch not loaded\n", current_event_ch);*/ - } - tmp_decay_samples = get_decay_samples(tmp_patch, - tracks[i][0]); - /* if the note off decay is more than the decay we currently tracking then - * we set it to new decay. */ - if (tmp_decay_samples > decay_samples) { - decay_samples = tmp_decay_samples; - } - } - - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0x9: - if (tracks[i][1] == 0) { - goto NOTEOFF2; - } - midi_setup_noteon(mdi, (current_event & 0x0F), tracks[i][0], - tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xA: - midi_setup_aftertouch(mdi, (current_event & 0x0F), - tracks[i][0], tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xB: - midi_setup_control(mdi, (current_event & 0x0F), - tracks[i][0], tracks[i][1]); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xC: - midi_setup_patch(mdi, (current_event & 0x0F), *tracks[i]); - tracks[i]++; - running_event[i] = current_event; - break; - case 0xD: - midi_setup_channel_pressure(mdi, (current_event & 0x0F), - *tracks[i]); - tracks[i]++; - running_event[i] = current_event; - break; - case 0xE: - midi_setup_pitch(mdi, (current_event & 0x0F), - ((tracks[i][1] << 7) | (tracks[i][0] & 0x7F))); - tracks[i] += 2; - running_event[i] = current_event; - break; - case 0xF: /* Meta Event */ - if (current_event == 0xFF) { - if (tracks[i][0] == 0x02) { /* Copyright Event */ - /* Get Length */ - tmp_length = 0; - tracks[i]++; - while (*tracks[i] > 0x7f) { - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i]++; - } - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - /* Copy copyright info in the getinfo struct */ - if (mdi->info.copyright) { - mdi->info.copyright = (char*)realloc( - mdi->info.copyright, - (strlen(mdi->info.copyright) + 1 - + tmp_length + 1)); - strncpy( - &mdi->info.copyright[strlen( - mdi->info.copyright) + 1], - (char *) tracks[i], tmp_length); - mdi->info.copyright[strlen(mdi->info.copyright) - + 1 + tmp_length] = '\0'; - mdi->info.copyright[strlen(mdi->info.copyright)] = '\n'; - - } else { - mdi->info.copyright = (char*)malloc(tmp_length + 1); - strncpy(mdi->info.copyright, (char *) tracks[i], - tmp_length); - mdi->info.copyright[tmp_length] = '\0'; - } - tracks[i] += tmp_length + 1; - } else if ((tracks[i][0] == 0x2F) - && (tracks[i][1] == 0x00)) { - /* End of Track */ - end_of_tracks++; - track_end[i] = 1; - goto NEXT_TRACK2; - } else if ((tracks[i][0] == 0x51) - && (tracks[i][1] == 0x03)) { - /* Tempo */ - tempo = (tracks[i][2] << 16) + (tracks[i][3] << 8) - + tracks[i][4]; - tracks[i] += 5; - if (!tempo) - tempo = 500000; - - if ((WM_MixerOptions & WM_MO_WHOLETEMPO)) { - float bpm_f = (float) (60000000 / tempo); - tempo = 60000000 - / (unsigned long int) bpm_f; - } else if ((WM_MixerOptions & WM_MO_ROUNDTEMPO)) { - float bpm_fr = (float) (60000000 / tempo) - + 0.5f; - tempo = 60000000 - / (unsigned long int) bpm_fr; - } - /* Slow but needed for accuracy */ - microseconds_per_pulse = (float) tempo - / (float) divisions; - pulses_per_second = 1000000.0f - / microseconds_per_pulse; - samples_per_delta_f = (float) _WM_SampleRate - / pulses_per_second; - - } else { - tmp_length = 0; - tracks[i]++; - while (*tracks[i] > 0x7f) { - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i]++; - } - tmp_length = (tmp_length << 7) - + (*tracks[i] & 0x7f); - tracks[i] += tmp_length + 1; - } - } else if ((current_event == 0xF0) - || (current_event == 0xF7)) { - /* Roland Sysex Events */ - unsigned long int sysex_len = 0; - while (*tracks[i] > 0x7F) { - sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - } - sysex_len = (sysex_len << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - - running_event[i] = 0; - - sysex_store = (unsigned char*)realloc(sysex_store, - sizeof(unsigned char) - * (sysex_store_len + sysex_len)); - memcpy(&sysex_store[sysex_store_len], tracks[i], - sysex_len); - sysex_store_len += sysex_len; - - if (sysex_store[sysex_store_len - 1] == 0xF7) { - unsigned char tmpsysexdata[] = { 0x41, 0x10, 0x42, 0x12 }; - if (memcmp(tmpsysexdata, sysex_store, 4) == 0) { - /* checksum */ - unsigned char sysex_cs = 0; - unsigned int sysex_ofs = 4; - do { - sysex_cs += sysex_store[sysex_ofs]; - if (sysex_cs > 0x7F) { - sysex_cs -= 0x80; - } - sysex_ofs++; - } while (sysex_store[sysex_ofs + 1] != 0xF7); - sysex_cs = 128 - sysex_cs; - /* is roland sysex message valid */ - if (sysex_cs == sysex_store[sysex_ofs]) { - /* process roland sysex event */ - if (sysex_store[4] == 0x40) { - if (((sysex_store[5] & 0xF0) == 0x10) - && (sysex_store[6] == 0x15)) { - /* Roland Drum Track Setting */ - unsigned char sysex_ch = 0x0F - & sysex_store[5]; - if (sysex_ch == 0x00) { - sysex_ch = 0x09; - } else if (sysex_ch <= 0x09) { - sysex_ch -= 1; - } - midi_setup_sysex_roland_drum_track( - mdi, sysex_ch, - sysex_store[7]); - } else if ((sysex_store[5] == 0x00) - && (sysex_store[6] == 0x7F) - && (sysex_store[7] == 0x00)) { - /* Roland GS Reset */ - midi_setup_sysex_roland_reset(mdi); - } - } - } - } - free(sysex_store); - sysex_store = NULL; - sysex_store_len = 0; - } - tracks[i] += sysex_len; - } else { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta event)", 0); - goto _end; - } - break; - default: - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized event)", 0); - goto _end; - } - track_delta[i] = 0; - while (*tracks[i] > 0x7F) { - track_delta[i] = (track_delta[i] << 7) - + (*tracks[i] & 0x7F); - tracks[i]++; - } - track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); - tracks[i]++; - NEXT_TRACK2: - smallest_delta = track_delta[i]; /* Added just to keep Xcode happy */ - UNUSED(smallest_delta); /* Added to just keep clang happy */ - } while (track_end[i] == 0); - /* - * Add decay at the end of each song - */ - if (decay_samples) { - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->events[mdi->event_count - 1].samples_to_next += decay_samples; - } else { - WM_CheckEventMemoryPool(mdi); - mdi->events[mdi->event_count].do_event = NULL; - mdi->events[mdi->event_count].event_data.channel = 0; - mdi->events[mdi->event_count].event_data.data = 0; - mdi->events[mdi->event_count].samples_to_next = decay_samples; - mdi->event_count++; - } - } - } - break; - - default: break; /* Don't expect to get here, added for completeness */ - } - - if ((mdi->event_count) - && (mdi->events[mdi->event_count - 1].do_event == NULL)) { - mdi->info.approx_total_samples -= - mdi->events[mdi->event_count - 1].samples_to_next; - mdi->event_count--; - } - /* Set total MIDI time to 1/1000's seconds */ - mdi->info.total_midi_time = (mdi->info.approx_total_samples * 1000) - / _WM_SampleRate; - /*mdi->info.approx_total_samples += _WM_SampleRate * 3;*/ - - /* Add additional samples needed for decay */ - mdi->info.approx_total_samples += decay_samples; - /*printf("decay_samples = %lu\n",decay_samples);*/ - - if ((mdi->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, - reverb_room_length, reverb_listen_posx, reverb_listen_posy)) - == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); - goto _end; - } - - mdi->info.current_sample = 0; - mdi->current_event = &mdi->events[0]; - mdi->samples_to_mix = 0; - mdi->note = NULL; - - WM_ResetToStart(mdi); - -_end: free(sysex_store); - free(track_end); - free(track_delta); - free(running_event); - free(tracks); - if (mdi->reverb) return mdi; - freeMDI(mdi); - return NULL; -} - static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) { struct _mdi *mdi = (struct _mdi *)handle; @@ -3635,107 +2554,6 @@ int *WM_Mix(midi *handle, int *buffer, unsigned long count) } } -static int WM_DoGetOutput(midi * handle, char * buffer, - unsigned long int size) { - unsigned long int buffer_used = 0; - unsigned long int i; - struct _mdi *mdi = (struct _mdi *) handle; - unsigned long int real_samples_to_mix = 0; - struct _event *event = mdi->current_event; - signed int *tmp_buffer; - signed int *out_buffer; - signed int left_mix, right_mix; - - _WM_Lock(&mdi->lock); - - buffer_used = 0; - memset(buffer, 0, size); - if ( (size / 2) > mdi->mix_buffer_size) { - if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { - mdi->mix_buffer_size += MEM_CHUNK; - } else { - mdi->mix_buffer_size = size / 2; - } - mdi->mix_buffer = (int*)realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(signed int)); - } - tmp_buffer = mdi->mix_buffer; - memset(tmp_buffer, 0, ((size / 2) * sizeof(signed long int))); - out_buffer = tmp_buffer; - - do { - if (!mdi->samples_to_mix) { - while ((!mdi->samples_to_mix) && (event->do_event)) { - event->do_event(mdi, &event->event_data); - event++; - mdi->samples_to_mix = event->samples_to_next; - mdi->current_event = event; - } - - if (!mdi->samples_to_mix) { - if (mdi->info.current_sample - >= mdi->info.approx_total_samples) { - break; - } else if ((mdi->info.approx_total_samples - - mdi->info.current_sample) > (size >> 2)) { - mdi->samples_to_mix = size >> 2; - } else { - mdi->samples_to_mix = mdi->info.approx_total_samples - - mdi->info.current_sample; - } - } - } - if (mdi->samples_to_mix > (size >> 2)) { - real_samples_to_mix = size >> 2; - } else { - real_samples_to_mix = mdi->samples_to_mix; - if (real_samples_to_mix == 0) { - continue; - } - } - - /* do mixing here */ - tmp_buffer = WM_Mix(handle, tmp_buffer, real_samples_to_mix); - - buffer_used += real_samples_to_mix * 4; - size -= (real_samples_to_mix << 2); - mdi->info.current_sample += real_samples_to_mix; - mdi->samples_to_mix -= real_samples_to_mix; - } while (size); - - tmp_buffer = out_buffer; - - if (mdi->info.mixer_options & WM_MO_REVERB) { - _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); - } - - for (i = 0; i < buffer_used; i += 4) { - left_mix = *tmp_buffer++; - right_mix = *tmp_buffer++; - - if (left_mix > 32767) { - left_mix = 32767; - } else if (left_mix < -32768) { - left_mix = -32768; - } - - if (right_mix > 32767) { - right_mix = 32767; - } else if (right_mix < -32768) { - right_mix = -32768; - } - - /* - * =================== - * Write to the buffer - * =================== - */ - ((short *)buffer)[0] = (short)left_mix; - ((short *)buffer)[1] = (short)right_mix; - buffer += 4; - } - _WM_Unlock(&mdi->lock); - return buffer_used; -} /* * ========================= @@ -3874,69 +2692,6 @@ WM_SYMBOL int WildMidi_Close(midi * handle) { return 0; } -WM_SYMBOL midi * -WildMidi_Open(const char *midifile) { - unsigned char *mididata = NULL; - unsigned long int midisize = 0; - midi * ret = NULL; - - if (!WM_Initialized) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); - return NULL; - } - if (midifile == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", - 0); - return NULL; - } - - if ((mididata = _WM_BufferFile(midifile, &midisize)) == NULL) { - return NULL; - } - - ret = (void *) WM_ParseNewMidi(mididata, midisize); - free(mididata); - - if (ret) { - if (add_handle(ret) != 0) { - WildMidi_Close(ret); - ret = NULL; - } - } - - return ret; -} - -WM_SYMBOL midi * -WildMidi_OpenBuffer(unsigned char *midibuffer, unsigned long int size) { - midi * ret = NULL; - - if (!WM_Initialized) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); - return NULL; - } - if (midibuffer == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(NULL midi data buffer)", 0); - return NULL; - } - if (size > WM_MAXFILESIZE) { - /* don't bother loading suspiciously long files */ - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, NULL, 0); - return NULL; - } - ret = (void *) WM_ParseNewMidi(midibuffer, size); - - if (ret) { - if (add_handle(ret) != 0) { - WildMidi_Close(ret); - ret = NULL; - } - } - - return ret; -} - midi *WildMidi_NewMidi() { midi * ret = NULL; @@ -3954,135 +2709,6 @@ midi *WildMidi_NewMidi() { return ret; } -WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { - struct _mdi *mdi; - struct _event *event; - struct _note *note_data; - unsigned long int real_samples_to_mix; - unsigned long int count; - - if (!WM_Initialized) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); - return -1; - } - if (handle == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", - 0); - return -1; - } - if (sample_pos == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(NULL seek position pointer)", 0); - return -1; - } - - mdi = (struct _mdi *) handle; - _WM_Lock(&mdi->lock); - event = mdi->current_event; - - /* make sure we havent asked for a positions beyond the end of the song. */ - if (*sample_pos > mdi->info.approx_total_samples) { - /* if so set the position to the end of the song */ - *sample_pos = mdi->info.approx_total_samples; - } - - /* was end of song requested and are we are there? */ - if (*sample_pos == mdi->info.current_sample) { - /* yes */ - _WM_Unlock(&mdi->lock); - return 0; - } - - /* did we want to fast forward? */ - if (mdi->info.current_sample < *sample_pos) { - /* yes */ - count = *sample_pos - mdi->info.current_sample; - } else { - /* no, reset values to start as the beginning */ - count = *sample_pos; - WM_ResetToStart(handle); - event = mdi->current_event; - } - - /* clear the reverb buffers since we not gonna be using them here */ - _WM_reset_reverb(mdi->reverb); - - while (count) { - if (!mdi->samples_to_mix) { - while ((!mdi->samples_to_mix) && (event->do_event)) { - event->do_event(mdi, &event->event_data); - event++; - mdi->samples_to_mix = event->samples_to_next; - mdi->current_event = event; - } - - if (!mdi->samples_to_mix) { - if (event->do_event == NULL) { - mdi->samples_to_mix = mdi->info.approx_total_samples - - *sample_pos; - } else { - mdi->samples_to_mix = count; - } - } - } - - if (mdi->samples_to_mix > count) { - real_samples_to_mix = count; - } else { - real_samples_to_mix = mdi->samples_to_mix; - } - - if (real_samples_to_mix == 0) { - break; - } - - count -= real_samples_to_mix; - mdi->info.current_sample += real_samples_to_mix; - mdi->samples_to_mix -= real_samples_to_mix; - } - - note_data = mdi->note; - if (note_data) { - do { - note_data->active = 0; - if (note_data->replay) { - note_data->replay = NULL; - } - note_data = note_data->next; - } while (note_data); - } - mdi->note = NULL; - - _WM_Unlock(&mdi->lock); - return 0; -} - -WM_SYMBOL int WildMidi_GetOutput(midi * handle, char *buffer, unsigned long int size) { - if (!WM_Initialized) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); - return -1; - } - if (handle == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", - 0); - return -1; - } - if (buffer == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(NULL buffer pointer)", 0); - return -1; - } - if (size == 0) { - return 0; - } - if (!!(size % 4)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(size not a multiple of 4)", 0); - return -1; - } - return WM_DoGetOutput(handle, buffer, size); -} - WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, unsigned short int setting) { struct _mdi *mdi; diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h index 46a517d90..ec8dea3c1 100644 --- a/src/wildmidi/wildmidi_lib.h +++ b/src/wildmidi/wildmidi_lib.h @@ -56,12 +56,7 @@ typedef void midi; WM_SYMBOL const char * WildMidi_GetString (unsigned short int info); WM_SYMBOL int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options); WM_SYMBOL int WildMidi_MasterVolume (unsigned char master_volume); -WM_SYMBOL midi * WildMidi_Open (const char *midifile); -WM_SYMBOL midi * WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size); -WM_SYMBOL int WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size); WM_SYMBOL int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting); -WM_SYMBOL struct _WM_Info * WildMidi_GetInfo (midi * handle); -WM_SYMBOL int WildMidi_FastSeek (midi * handle, unsigned long int *sample_pos); WM_SYMBOL int WildMidi_Close (midi * handle); WM_SYMBOL int WildMidi_Shutdown (void); WM_SYMBOL int WildMidi_GetSampleRate (void); From 14361d93138e2695d5fc6d7ed83d5e60aae6a09a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 16:04:26 -0600 Subject: [PATCH 207/335] Remove midi_timiditylike - Did anybody actually use this? Use WildMidi instead if you want something that sounds more like Timidity++ without actually being Timidity++, since not even the old Timidity manages that. --- src/timidity/instrum.cpp | 60 ++----------------------------- src/timidity/instrum_dls.cpp | 1 - src/timidity/instrum_sf2.cpp | 1 - src/timidity/mix.cpp | 69 ++++++------------------------------ src/timidity/playmidi.cpp | 23 +++--------- src/timidity/resample.cpp | 6 ++-- src/timidity/timidity.cpp | 14 ++------ src/timidity/timidity.h | 16 ++------- zdoom.vcproj | 8 +++++ 9 files changed, 33 insertions(+), 165 deletions(-) diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index a8c7b5f7c..fdfa4fd64 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -142,7 +142,7 @@ static void reverse_data(sample_t *sp, int ls, int le) TODO: do reverse loops right */ static Instrument *load_instrument(Renderer *song, const char *name, int percussion, - int panning, int amp, int note_to_use, + int panning, int note_to_use, int strip_loop, int strip_envelope, int strip_tail) { @@ -372,7 +372,6 @@ fail: { sp->modes &= ~(PATCH_SUSTAIN | PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD); } - sp->modes |= PATCH_T_NO_LOOP; } if (strip_envelope == 1) @@ -398,37 +397,6 @@ fail: patch_data.EnvelopeOffset[k] = patch_data.EnvelopeOffset[0]; } } - sp->modes |= PATCH_T_NO_ENVELOPE; - } - else if (strip_envelope != 0) - { - /* Have to make a guess. */ - if (!(sp->modes & (PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD))) - { - /* No loop? Then what's there to sustain? No envelope needed either... */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - No loop, removing sustain and envelope\n"); - } - else if (memcmp(patch_data.EnvelopeRate, "??????", 6) == 0 || patch_data.EnvelopeOffset[GF1_RELEASEC] >= 100) - { - /* Envelope rates all maxed out? Envelope end at a high "offset"? - That's a weird envelope. Take it out. */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - Weirdness, removing envelope\n"); - } - else if (!(sp->modes & PATCH_SUSTAIN)) - { - /* No sustain? Then no envelope. I don't know if this is - justified, but patches without sustain usually don't need the - envelope either... at least the Gravis ones. They're mostly - drums. I think. */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - No sustain, removing envelope\n"); - } - } - if (!(sp->modes & PATCH_NO_SRELEASE)) - { // TiMidity thinks that this is an envelope enable flag. - sp->modes |= PATCH_T_NO_ENVELOPE; } for (j = 0; j < 6; j++) @@ -470,29 +438,6 @@ fail: sp->modes |= PATCH_LOOPEN; /* just in case */ } - if (amp != -1) - { - sp->volume = (amp) / 100.f; - } - else - { - /* Try to determine a volume scaling factor for the sample. - This is a very crude adjustment, but things sound more - balanced with it. Still, this should be a runtime option. - (This is ignored unless midi_timiditylike is turned on.) */ - int i; - sample_t maxamp = 0, a; - sample_t *tmp; - for (i = sp->data_length, tmp = sp->data; i; --i) - { - a = fabsf(*tmp++); - if (a > maxamp) - maxamp = a; - } - sp->volume = 1 / maxamp; - cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f\n", sp->volume); - } - /* Then fractional samples */ sp->data_length <<= FRACTION_BITS; sp->loop_start <<= FRACTION_BITS; @@ -653,7 +598,6 @@ static int fill_bank(Renderer *song, int dr, int b) ip = load_instrument(song, bank->tone[i].name, (dr) ? 1 : 0, bank->tone[i].pan, - bank->tone[i].amp, (bank->tone[i].note != -1) ? bank->tone[i].note : ((dr) ? i : -1), (bank->tone[i].strip_loop != -1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1), (bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1), @@ -731,7 +675,7 @@ void free_instruments() int Renderer::set_default_instrument(const char *name) { Instrument *ip; - if ((ip = load_instrument(this, name, 0, -1, -1, -1, 0, 0, 0)) == NULL) + if ((ip = load_instrument(this, name, 0, -1, -1, 0, 0, 0)) == NULL) { return -1; } diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp index fe5e4fdcd..286fcb1a3 100644 --- a/src/timidity/instrum_dls.cpp +++ b/src/timidity/instrum_dls.cpp @@ -1141,7 +1141,6 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, sample->loop_start = rgn->wsmp_loop->ulStart / 2; sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); } - sample->volume = 1.0f; if (sample->modes & PATCH_SUSTAIN) { diff --git a/src/timidity/instrum_sf2.cpp b/src/timidity/instrum_sf2.cpp index c4cf0bc81..01576e64c 100644 --- a/src/timidity/instrum_sf2.cpp +++ b/src/timidity/instrum_sf2.cpp @@ -1441,7 +1441,6 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend sp->root_freq = note_to_freq(sp->scale_note); sp->sample_rate = sfsamp->SampleRate; sp->key_group = gen->exclusiveClass; - sp->volume = 1; // Set key scaling if (gen->keynum >= 0 && gen->keynum <= 127) diff --git a/src/timidity/mix.cpp b/src/timidity/mix.cpp index b4fc0f818..f97710326 100644 --- a/src/timidity/mix.cpp +++ b/src/timidity/mix.cpp @@ -29,8 +29,6 @@ #include "templates.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -78,16 +76,7 @@ void GF1Envelope::Init(Renderer *song, Voice *v) void GF1Envelope::Release(Voice *v) { - if (midi_timiditylike) - { - if (!(v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - stage = GF1_RELEASE; - Recompute(v); - } - // else ... loop was already turned off by the caller - } - else if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL)) + if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL)) { /* ramp out to minimum volume with rate from final release stage */ stage = GF1_RELEASEC+1; @@ -119,23 +108,11 @@ bool GF1Envelope::Recompute(Voice *v) bUpdating = false; v->status &= ~(VOICE_SUSTAINING | VOICE_LPE); v->status |= VOICE_RELEASING; - if (midi_timiditylike) - { /* kill the voice ... or not */ - if (volume <= 0) - { - v->status |= VOICE_STOPPING; - } - return 1; - } - else - { /* play sampled release */ - } + /* play sampled release */ return 0; } - if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && - ((!midi_timiditylike && (v->sample->modes & PATCH_SUSTAIN)) || - (midi_timiditylike && !(v->sample->modes & PATCH_T_NO_ENVELOPE)))) + if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN)) { v->status |= VOICE_SUSTAINING; /* Freeze envelope until note turns off. Trumpets want this. */ @@ -161,10 +138,6 @@ bool GF1Envelope::Recompute(Voice *v) bool GF1Envelope::Update(Voice *v) { - if (midi_timiditylike && (v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - return 0; - } volume += increment; if (((increment < 0) && (volume <= target)) || ((increment > 0) && (volume >= target))) { @@ -182,36 +155,14 @@ void GF1Envelope::ApplyToAmp(Voice *v) double env_vol = v->attenuation; double final_amp; - if (midi_timiditylike) - { - final_amp = v->sample->volume * FINAL_MIX_TIMIDITY_SCALE; - if (v->tremolo_phase_increment != 0) - { - env_vol *= v->tremolo_volume; - } - if (!(v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - if (stage > GF1_ATTACK) - { - env_vol *= pow(2.0, volume * (6.0 / (1 << 30)) - 6.0); - } - else - { - env_vol *= volume / float(1 << 30); - } - } - } - else - { - final_amp = FINAL_MIX_SCALE; - if (v->tremolo_phase_increment != 0) - { // [RH] FIXME: This is wrong. Tremolo should offset the - // envelope volume, not scale it. - env_vol *= v->tremolo_volume; - } - env_vol *= volume / float(1 << 30); - env_vol = calc_gf1_amp(env_vol); + final_amp = FINAL_MIX_SCALE; + if (v->tremolo_phase_increment != 0) + { // [RH] FIXME: This is wrong. Tremolo should offset the + // envelope volume, not scale it. + env_vol *= v->tremolo_volume; } + env_vol *= volume / float(1 << 30); + env_vol = calc_gf1_amp(env_vol); env_vol *= final_amp; v->left_mix = float(env_vol * v->left_offset); v->right_mix = float(env_vol * v->right_offset); diff --git a/src/timidity/playmidi.cpp b/src/timidity/playmidi.cpp index 5db4f61bc..7d8294384 100644 --- a/src/timidity/playmidi.cpp +++ b/src/timidity/playmidi.cpp @@ -29,8 +29,6 @@ #include "timidity.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -118,7 +116,7 @@ void Renderer::recompute_freq(int v) voice[v].sample_increment = (int)(a); } -static BYTE vol_table[] = { +static const BYTE vol_table[] = { 000 /* 000 */, 129 /* 001 */, 145 /* 002 */, 155 /* 003 */, 161 /* 004 */, 166 /* 005 */, 171 /* 006 */, 174 /* 007 */, 177 /* 008 */, 180 /* 009 */, 182 /* 010 */, 185 /* 011 */, @@ -161,16 +159,7 @@ void Renderer::recompute_amp(Voice *v) if (v->sample->type == INST_GUS) { - if (midi_timiditylike) - { - v->attenuation = float(timidityxx_perceived_vol(v->velocity / 127.0) * - timidityxx_perceived_vol(chanvol / 127.0) * - timidityxx_perceived_vol(chanexpr / 127.0)); - } - else - { - v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f); - } + v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f); } else { @@ -199,7 +188,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ } else { - if (type == INST_GUS && !midi_timiditylike) + if (type == INST_GUS) { /* Original amp equation looks like this: * calc_gf1_amp(atten + offset) @@ -218,9 +207,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ } else { - /* I have no idea what equation, if any, will reproduce the sc_pan_table - * that TiMidity++ uses, so midi_timiditylike gets the same Equal Power - * Panning as SF2/DLS. + /* Equal Power Panning for SF2/DLS. */ left_offset = (float)sqrt(1 - pan); right_offset = (float)sqrt(pan); @@ -561,7 +548,7 @@ void Renderer::finish_note(int i) v->status &= ~VOICE_SUSTAINING; v->status |= VOICE_RELEASING; - if (!(v->sample->modes & PATCH_NO_SRELEASE) || midi_timiditylike) + if (!(v->sample->modes & PATCH_NO_SRELEASE)) { v->status &= ~VOICE_LPE; /* sampled release */ } diff --git a/src/timidity/resample.cpp b/src/timidity/resample.cpp index 0ee6aa856..6b9bdb9f5 100644 --- a/src/timidity/resample.cpp +++ b/src/timidity/resample.cpp @@ -28,8 +28,6 @@ #include "timidity.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -522,7 +520,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) if (vp->vibrato_control_ratio) { - if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) + if (vp->status & VOICE_LPE) { if (modes & PATCH_BIDIR) return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr); @@ -536,7 +534,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) } else { - if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) + if (vp->status & VOICE_LPE) { if (modes & PATCH_BIDIR) return rs_bidir(song->resample_buffer, vp, *countptr); diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 1d74c5afc..09b5ae7b5 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -34,7 +34,6 @@ CVAR(String, midi_config, CONFIG_FILE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, midi_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Bool, midi_timiditylike, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, gus_patchdir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, midi_dmxgus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -377,7 +376,7 @@ static int read_config_file(const char *name, bool ismain) delete fp; return -2; } - bank->tone[i].note = bank->tone[i].amp = bank->tone[i].pan = + bank->tone[i].note = bank->tone[i].pan = bank->tone[i].fontbank = bank->tone[i].fontpreset = bank->tone[i].fontnote = bank->tone[i].strip_loop = bank->tone[i].strip_envelope = bank->tone[i].strip_tail = -1; @@ -415,14 +414,7 @@ static int read_config_file(const char *name, bool ismain) *cp++ = 0; if (!strcmp(w[j], "amp")) { - k = atoi(cp); - if ((k < 0 || k > MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9')) - { - Printf("%s: line %d: amplification must be between 0 and %d\n", name, line, MAX_AMPLIFICATION); - delete fp; - return -2; - } - bank->tone[i].amp = k; + /* Ignored */ } else if (!strcmp(w[j], "note")) { @@ -676,7 +668,7 @@ int LoadDMXGUS() continue; int val = k % 128; - bank->tone[val].note = bank->tone[val].amp = bank->tone[val].pan = + bank->tone[val].note = bank->tone[val].pan = bank->tone[val].fontbank = bank->tone[val].fontpreset = bank->tone[val].fontnote = bank->tone[val].strip_loop = bank->tone[val].strip_envelope = bank->tone[val].strip_tail = -1; diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 0a21a41b9..59ba5f8ad 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -55,10 +55,6 @@ config.h volume level of FMOD's built-in MIDI player. */ #define FINAL_MIX_SCALE 0.5 -/* This value is used instead when midi_timiditylike is turned on, - because TiMidity++ is louder than a GUS. */ -#define FINAL_MIX_TIMIDITY_SCALE 0.3 - /* How many bits to use for the fractional part of sample positions. This affects tonal accuracy. The entire position counter must fit in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of @@ -211,9 +207,6 @@ enum PATCH_SUSTAIN = (1<<5), PATCH_NO_SRELEASE = (1<<6), PATCH_FAST_REL = (1<<7), - - PATCH_T_NO_ENVELOPE = (1<<8), - PATCH_T_NO_LOOP = (1<<9) }; struct Sample @@ -239,8 +232,6 @@ struct Sample short release_vol; } sf2; } envelope; - float - volume; sample_t *data; SDWORD tremolo_sweep_increment, tremolo_phase_increment, @@ -316,11 +307,12 @@ struct Instrument struct ToneBankElement { ToneBankElement() : - note(0), amp(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) + note(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) {} FString name; - int note, amp, pan, fontbank, fontpreset, fontnote, strip_loop, strip_envelope, strip_tail; + int note, pan, fontbank, fontpreset, fontnote; + SBYTE strip_loop, strip_envelope, strip_tail; }; /* A hack to delay instrument loading until after reading the entire MIDI file. */ @@ -608,8 +600,6 @@ const double log_of_2 = 0.69314718055994529; #define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation #define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp -#define db_to_amp(x) (pow(10.0, (x) * (1 / -20.0))) // decibels to map -#define timidityxx_perceived_vol(x) (pow((x), 1.66096404744)) /* timidity.h diff --git a/zdoom.vcproj b/zdoom.vcproj index a5d7bfb8e..2e425f5b4 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -942,6 +942,10 @@ RelativePath=".\src\parsecontext.cpp" > + + @@ -1479,6 +1483,10 @@ RelativePath=".\src\parsecontext.h" > + + From 900937929e6e045ea568982741491812d092a1b4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 16:24:16 -0600 Subject: [PATCH 208/335] Use critical sections for WildMidi locking ...because when you're trying to be thread-safe, it's generally a good idea to use mechanisms that work across multiple processor cores. --- src/CMakeLists.txt | 1 - src/wildmidi/lock.cpp | 86 ------------------------------- src/wildmidi/lock.h | 36 ------------- src/wildmidi/wildmidi_lib.cpp | 96 ++++++++++++++++++++--------------- zdoom.vcproj | 8 --- 5 files changed, 54 insertions(+), 173 deletions(-) delete mode 100644 src/wildmidi/lock.cpp delete mode 100644 src/wildmidi/lock.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1975a8d8..8503fabcf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1138,7 +1138,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE timidity/timidity.cpp wildmidi/file_io.cpp wildmidi/gus_pat.cpp - wildmidi/lock.cpp wildmidi/reverb.cpp wildmidi/wildmidi_lib.cpp wildmidi/wm_error.cpp diff --git a/src/wildmidi/lock.cpp b/src/wildmidi/lock.cpp deleted file mode 100644 index c5d3fc7da..000000000 --- a/src/wildmidi/lock.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - lock.c - data locking code for lib - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . - */ - -//#include "config.h" - -#ifndef __DJGPP__ - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "lock.h" -#include "common.h" - -/* - _WM_Lock(wmlock) - - wmlock = a pointer to a value - - returns nothing - - Attempts to set a lock on the MDI tree so that - only 1 library command may access it at any time. - If lock fails the process retries until successful. - */ -void _WM_Lock(int * wmlock) { - LOCK_START: - /* Check if lock is clear, if so set it */ - if (*wmlock == 0) { - (*wmlock)++; - /* Now that the lock is set, make sure we - * don't have a race condition. If so, - * decrement the lock by one and retry. */ - if (*wmlock == 1) { - return; /* Lock cleanly set */ - } - (*wmlock)--; - } -#ifdef _WIN32 - Sleep(10); -#else - usleep(500); -#endif - goto LOCK_START; -} - -/* - _WM_Unlock(wmlock) - - wmlock = a pointer to a value - - returns nothing - - Removes a lock previously placed on the MDI tree. - */ -void _WM_Unlock(int *wmlock) { - /* We don't want a -1 lock, so just to make sure */ - if ((*wmlock) != 0) { - (*wmlock)--; - } -} - -#endif /* __DJGPP__ */ diff --git a/src/wildmidi/lock.h b/src/wildmidi/lock.h deleted file mode 100644 index 6504bbecf..000000000 --- a/src/wildmidi/lock.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - lock.h - data locking code for lib - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef __LOCK_H -#define __LOCK_H - -extern void _WM_Lock (int * wmlock); -extern void _WM_Unlock (int *wmlock); - -#ifdef __DJGPP__ -#define _WM_Lock(p) do {} while (0) -#define _WM_Unlock(p) do {} while (0) -#endif - -#endif /* __LOCK_H */ diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 4372f8436..fe97ad7e8 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -46,10 +46,10 @@ #include "common.h" #include "wm_error.h" #include "file_io.h" -#include "lock.h" #include "reverb.h" #include "gus_pat.h" #include "wildmidi_lib.h" +#include "critsec.h" #define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') #ifdef _WIN32 @@ -88,7 +88,7 @@ static int fix_release = 0; static int auto_amp = 0; static int auto_amp_with_amp = 0; -static int patch_lock; +static FCriticalSection patch_lock; struct _channel { unsigned char bank; @@ -149,7 +149,24 @@ struct _event_data { }; struct _mdi { - int lock; + _mdi() + { + samples_to_mix = 0; + midi_master_vol = 0; + memset(&info, 0, sizeof(info)); + tmp_info = NULL; + memset(&channel, 0, sizeof(channel)); + note = NULL; + memset(note_table, 0, sizeof(note_table)); + patches = NULL; + patch_count = 0; + amp = 0; + mix_buffer = NULL; + mix_buffer_size = NULL; + reverb = NULL; + } + + FCriticalSection lock; unsigned long int samples_to_mix; unsigned short midi_master_vol; @@ -177,7 +194,7 @@ static double newt_coeffs[58][58]; /* for start/end of samples */ #define MAX_GAUSS_ORDER 34 /* 34 is as high as we can go before errors crop up */ static double *gauss_table = NULL; /* *gauss_table[1<first_sample) { @@ -535,7 +552,7 @@ static void WM_FreePatches(void) { patch[i] = tmp_patch; } } - _WM_Unlock(&patch_lock); + patch_lock.Leave(); } /* wm_strdup -- adds extra space for appending up to 4 chars */ @@ -1273,27 +1290,27 @@ static struct _patch * get_patch_data(unsigned short patchid) { struct _patch *search_patch; - _WM_Lock(&patch_lock); + patch_lock.Enter(); search_patch = patch[patchid & 0x007F]; if (search_patch == NULL) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return NULL; } while (search_patch) { if (search_patch->patchid == patchid) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return search_patch; } search_patch = search_patch->next; } if ((patchid >> 8) != 0) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return (get_patch_data(patchid & 0x00FF)); } - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return NULL; } @@ -1312,16 +1329,16 @@ static void load_patch(struct _mdi *mdi, unsigned short patchid) { return; } - _WM_Lock(&patch_lock); + patch_lock.Enter(); if (!tmp_patch->loaded) { if (load_sample(tmp_patch) == -1) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return; } } if (tmp_patch->first_sample == NULL) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return; } @@ -1330,7 +1347,7 @@ static void load_patch(struct _mdi *mdi, unsigned short patchid) { (sizeof(struct _patch*) * mdi->patch_count)); mdi->patches[mdi->patch_count - 1] = tmp_patch; tmp_patch->inuse_count++; - _WM_Unlock(&patch_lock); + patch_lock.Leave(); } static struct _sample * @@ -1338,17 +1355,17 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { struct _sample *last_sample = NULL; struct _sample *return_sample = NULL; - _WM_Lock(&patch_lock); + patch_lock.Enter(); if (sample_patch == NULL) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return NULL; } if (sample_patch->first_sample == NULL) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return NULL; } if (freq == 0) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return sample_patch->first_sample; } @@ -1357,7 +1374,7 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { while (last_sample) { if (freq > last_sample->freq_low) { if (freq < last_sample->freq_high) { - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return last_sample; } else { return_sample = last_sample; @@ -1365,7 +1382,7 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { } last_sample = last_sample->next; } - _WM_Unlock(&patch_lock); + patch_lock.Leave(); return return_sample; } @@ -2021,8 +2038,7 @@ static struct _mdi * Init_MDI(void) { struct _mdi *mdi; - mdi = (struct _mdi*)malloc(sizeof(struct _mdi)); - memset(mdi, 0, (sizeof(struct _mdi))); + mdi = new _mdi; mdi->info.copyright = NULL; mdi->info.mixer_options = WM_MixerOptions; @@ -2044,7 +2060,7 @@ static void freeMDI(struct _mdi *mdi) { unsigned long int i; if (mdi->patch_count != 0) { - _WM_Lock(&patch_lock); + patch_lock.Enter(); for (i = 0; i < mdi->patch_count; i++) { mdi->patches[i]->inuse_count--; if (mdi->patches[i]->inuse_count == 0) { @@ -2058,7 +2074,7 @@ static void freeMDI(struct _mdi *mdi) { mdi->patches[i]->loaded = 0; } } - _WM_Unlock(&patch_lock); + patch_lock.Leave(); free(mdi->patches); } @@ -2554,7 +2570,6 @@ int *WM_Mix(midi *handle, int *buffer, unsigned long count) } } - /* * ========================= * External Functions @@ -2602,9 +2617,6 @@ WM_SYMBOL int WildMidi_Init(const char * config_file, unsigned short int rate, return -1; } _WM_SampleRate = rate; - - gauss_lock = 0; - patch_lock = 0; WM_Initialized = 1; return 0; @@ -2663,7 +2675,7 @@ WM_SYMBOL int WildMidi_Close(midi * handle) { 0); return -1; } - _WM_Lock(&mdi->lock); + mdi->lock.Enter(); if (first_handle->handle == handle) { tmp_handle = first_handle->next; free(first_handle); @@ -2725,17 +2737,17 @@ WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, } mdi = (struct _mdi *) handle; - _WM_Lock(&mdi->lock); + mdi->lock.Enter(); if ((!(options & 0x0007)) || (options & 0xFFF8)) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0); - _WM_Unlock(&mdi->lock); + mdi->lock.Leave(); return -1; } if (setting & 0xFFF8) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0); - _WM_Unlock(&mdi->lock); + mdi->lock.Leave(); return -1; } @@ -2763,7 +2775,7 @@ WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, _WM_reset_reverb(mdi->reverb); } - _WM_Unlock(&mdi->lock); + mdi->lock.Leave(); return 0; } @@ -2779,12 +2791,12 @@ WildMidi_GetInfo(midi * handle) { 0); return NULL; } - _WM_Lock(&mdi->lock); + mdi->lock.Enter(); if (mdi->tmp_info == NULL) { mdi->tmp_info = (struct _WM_Info*)malloc(sizeof(struct _WM_Info)); if (mdi->tmp_info == NULL) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0); - _WM_Unlock(&mdi->lock); + mdi->lock.Leave(); return NULL; } mdi->tmp_info->copyright = NULL; @@ -2799,7 +2811,7 @@ WildMidi_GetInfo(midi * handle) { } else { mdi->tmp_info->copyright = NULL; } - _WM_Unlock(&mdi->lock); + mdi->lock.Leave(); return mdi->tmp_info; } diff --git a/zdoom.vcproj b/zdoom.vcproj index 2e425f5b4..a2587840f 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2819,10 +2819,6 @@ RelativePath=".\src\wildmidi\gus_pat.h" > - - @@ -2847,10 +2843,6 @@ RelativePath=".\src\wildmidi\gus_pat.cpp" > - - From 545e2f7c69a3648680811e27228a845ecac5398f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 16:30:01 -0600 Subject: [PATCH 209/335] Slap WildMidi onto snd_listmididevices's output for Windows --- src/sound/music_midi_base.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 048e52e3f..260f635b2 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -168,6 +168,7 @@ CCMD (snd_listmididevices) MIDIOUTCAPS caps; MMRESULT res; + PrintMidiDevice (-6, "WildMidi", MOD_SWSYNTH, 0); #ifdef HAVE_FLUIDSYNTH PrintMidiDevice (-5, "FluidSynth", MOD_SWSYNTH, 0); #endif From 6d2e93254fcea18ea37c6eb21f9ba116084172d1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 17:14:13 -0600 Subject: [PATCH 210/335] Fix CreateSMF's SysEx writing - It was wrong before. It might still be wrong, but at least it doesn't look obviously wrong anymore. --- src/sound/music_midistream.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 37616b9a6..064606d0f 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -1196,9 +1196,15 @@ void MIDIStreamer::CreateSMF(TArray &file, int looplimit) len--; file.Push(MIDI_SYSEX); WriteVarLen(file, len); - memcpy(&file[file.Reserve(len - 1)], bytes, len); - running_status = 255; + memcpy(&file[file.Reserve(len)], bytes + 1, len); } + else + { + file.Push(MIDI_SYSEXEND); + WriteVarLen(file, len); + memcpy(&file[file.Reserve(len)], bytes, len); + } + running_status = 255; } else if (MEVT_EVENTTYPE(event[2]) == 0) { From 92e0bbeee9e2440999990f6e21fa0a1312d21d0f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 17:49:43 -0600 Subject: [PATCH 211/335] Handle WildMidi's supported SysEx messages --- src/wildmidi/wildmidi_lib.cpp | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index fe97ad7e8..68ab89933 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2918,6 +2918,45 @@ void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2) void WildMidi_Renderer::LongEvent(const char *data, int len) { + // Check for Roland SysEx + if (len >= 11 && // Must be at least 11 bytes + data[len-1] == 0xF7 && // SysEx end + data[0] == 0xF0 && // SysEx + data[1] == 0x41 && // Roland + data[2] == 0x10 && // Device ID, defaults to 0x10 + data[3] == 0x42 && // Model ID, 0x42 indicates a GS synth + data[4] == 0x12 && // The other end is sending data to us + data[5] == 0x40) // We only care about addresses with this first byte + { + // Calculate checksum + int cksum = 0; + for (int i = 5; i < len - 2; ++i) + { + cksum += data[i]; + } + cksum = 128 - (cksum & 0x7F); + if (data[len-2] == cksum) + { // Check destination address + if (((data[6] & 0xF0) == 0x10) && data[7] == 0x15) + { // Roland drum track setting + int sysex_ch = data[6] & 0x0F; + if (sysex_ch == 0) + { + sysex_ch = 9; + } + else if (sysex_ch <= 9) + { + sysex_ch -= 1; + } + _event_data ev = { sysex_ch, data[8] }; + do_sysex_roland_drum_track((_mdi *)handle, &ev); + } + else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00) + { // Roland GS reset + do_sysex_roland_reset((_mdi *)handle, NULL); + } + } + } } void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len) From 3ec6ad5018941bde5dd0802afc28f70ffc8674ee Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Dec 2015 22:39:38 -0600 Subject: [PATCH 212/335] Add SysEx retrieval to the MIDI file reader --- src/sound/i_musicinterns.h | 2 +- src/sound/music_smf_midiout.cpp | 53 ++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 03282ef37..dd5fd1606 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -566,7 +566,7 @@ protected: struct TrackInfo; void ProcessInitialMetaEvents (); - DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay); + DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom); TrackInfo *FindNextDue (); BYTE *MusHeader; diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index d5d307ec7..49fd12502 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -322,7 +322,12 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) // Play all events for this tick. do { - DWORD *new_events = SendCommand(events, TrackDue, time); + bool sysex_noroom = false; + DWORD *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom); + if (sysex_noroom) + { + return events; + } TrackDue = FindNextDue(); if (new_events != events) { @@ -366,12 +371,15 @@ void MIDISong2::AdvanceTracks(DWORD time) // //========================================================================== -DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) +DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom) { DWORD len; BYTE event, data1 = 0, data2 = 0; int i; + sysex_noroom = false; + size_t start_p = track->TrackP; + CHECK_FINISHED event = track->TrackBegin[track->TrackP++]; CHECK_FINISHED @@ -588,13 +596,44 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) } else { - // Skip SysEx events just because I don't want to bother with them. - // The old MIDI player ignored them too, so this won't break - // anything that played before. + // SysEx events could potentially not have enough room in the buffer... if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { - len = track->ReadVarLen (); - track->TrackP += len; + len = track->ReadVarLen(); + if (len >= (MAX_EVENTS-1)*3*4) + { // This message will never fit. Throw it away. + track->TrackP += len; + } + else if (len + 12 >= (size_t)room * 4) + { // Not enough room left in this buffer. Backup and wait for the next one. + track->TrackP = start_p; + sysex_noroom = true; + return events; + } + else + { + events[0] = delay; + events[1] = 0; + BYTE *msg = (BYTE *)&events[3]; + if (event == MIDI_SYSEX) + { // Need to add the SysEx marker to the message. + events[2] = (MEVT_LONGMSG << 24) | (len + 1); + *msg++ = MIDI_SYSEX; + } + else + { + events[2] = (MEVT_LONGMSG << 24) | len; + } + memcpy(msg, &track->TrackBegin[track->TrackP], len); + msg += len; + // Must pad with 0 + while ((size_t)msg & 3) + { + *msg++ = 0; + } + events = (DWORD *)msg; + track->TrackP += len; + } } else if (event == MIDI_META) { From 6c13ba40ac57136d63ba617f6e5f48a191a36696 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 30 Dec 2015 01:09:11 -0600 Subject: [PATCH 213/335] Fix for __unix__ compilation -- section not changed with the rest of fe2dcfd588596d53 --- src/timidity/instrum.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index fdfa4fd64..fa9360267 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -168,7 +168,7 @@ static Instrument *load_instrument(Renderer *song, const char *name, int percuss { #ifdef __unix__ // Windows isn't case-sensitive. tmp.ToUpper(); - if ((fp = open_filereader(tmp, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) #endif { noluck = true; From 1def61e3e37e9bd0baf23102e9cc19f915e72859 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Dec 2015 10:14:18 +0100 Subject: [PATCH 214/335] - allow changing the reverb and resampling mode setting for WildMidi. - fixed: WildMidi did not initialize the reverb data structures. - removed the menu option for midi_timiditylike. --- src/sound/i_music.cpp | 4 ++++ src/sound/i_music.h | 1 + src/sound/i_musicinterns.h | 3 +++ src/sound/music_midistream.cpp | 25 ++++++++++++++++++++++ src/sound/music_wildmidi_mididevice.cpp | 28 ++++++++++++++++++++++++- src/wildmidi/wildmidi_lib.cpp | 15 +++++++++++++ src/wildmidi/wildmidi_lib.h | 1 + wadsrc/static/menudef.txt | 2 +- 8 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 121c0b9fb..a46401f3e 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -286,6 +286,10 @@ void MusInfo::FluidSettingStr(const char *, const char *) { } +void MusInfo::WildMidiSetOption(int opt, int set) +{ +} + FString MusInfo::GetStats() { return "No stats available for this song"; diff --git a/src/sound/i_music.h b/src/sound/i_music.h index ee05d8caf..03e0a3212 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -82,6 +82,7 @@ public: virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings virtual void FluidSettingNum(const char *setting, double value); // " virtual void FluidSettingStr(const char *setting, const char *value); // " + virtual void WildMidiSetOption(int opt, int set); void Start(bool loop, float rel_vol = -1.f, int subsong = 0); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index dd5fd1606..275253d84 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -102,6 +102,7 @@ public: virtual void FluidSettingInt(const char *setting, int value); virtual void FluidSettingNum(const char *setting, double value); virtual void FluidSettingStr(const char *setting, const char *value); + virtual void WildMidiSetOption(int opt, int set); virtual bool Preprocess(MIDIStreamer *song, bool looping); virtual FString GetStats(); }; @@ -349,6 +350,7 @@ protected: void HandleEvent(int status, int parm1, int parm2); void HandleLongEvent(const BYTE *data, int len); void ComputeOutput(float *buffer, int len); + void WildMidiSetOption(int opt, int set); }; // FluidSynth implementation of a MIDI device ------------------------------- @@ -447,6 +449,7 @@ public: void FluidSettingInt(const char *setting, int value); void FluidSettingNum(const char *setting, double value); void FluidSettingStr(const char *setting, const char *value); + void WildMidiSetOption(int opt, int set); void CreateSMF(TArray &file, int looplimit=0); protected: diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 064606d0f..a6fb5f4d8 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -626,6 +626,21 @@ void MIDIStreamer::FluidSettingStr(const char *setting, const char *value) } +//========================================================================== +// +// MIDIDeviceStreamer :: WildMidiSetOption +// +//========================================================================== + +void MIDIStreamer::WildMidiSetOption(int opt, int set) +{ + if (MIDI != NULL) + { + MIDI->WildMidiSetOption(opt, set); + } +} + + //========================================================================== // // MIDIStreamer :: OutputVolume @@ -1522,6 +1537,16 @@ void MIDIDevice::FluidSettingStr(const char *setting, const char *value) { } +//========================================================================== +// +// MIDIDevice :: WildMidiSetOption +// +//========================================================================== + +void MIDIDevice::WildMidiSetOption(int opt, int set) +{ +} + //========================================================================== // // MIDIDevice :: GetStats diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp index 44c060f26..80bf46e2b 100644 --- a/src/sound/music_wildmidi_mididevice.cpp +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -61,6 +61,17 @@ static FString CurrentConfig; CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (currSong != NULL) + currSong->WildMidiSetOption(WM_MO_REVERB, *self? WM_MO_REVERB:0); +} + +CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (currSong != NULL) + currSong->WildMidiSetOption(WM_MO_ENHANCED_RESAMPLING, *self? WM_MO_ENHANCED_RESAMPLING:0); +} // CODE -------------------------------------------------------------------- @@ -90,7 +101,7 @@ WildMIDIDevice::WildMIDIDevice() WildMidi_Shutdown(); CurrentConfig = ""; } - if (!WildMidi_Init(wildmidi_config, SampleRate, WM_MO_ENHANCED_RESAMPLING)) + if (!WildMidi_Init(wildmidi_config, SampleRate, 0)) { CurrentConfig = wildmidi_config; } @@ -98,6 +109,10 @@ WildMIDIDevice::WildMIDIDevice() if (CurrentConfig.IsNotEmpty()) { Renderer = new WildMidi_Renderer(); + int flags = 0; + if (wildmidi_enhanced_resampling) flags |= WM_MO_ENHANCED_RESAMPLING; + if (wildmidi_reverb) flags |= WM_MO_REVERB; + Renderer->SetOption(WM_MO_ENHANCED_RESAMPLING | WM_MO_REVERB, flags); } } @@ -204,3 +219,14 @@ FString WildMIDIDevice::GetStats() out.Format("%3d voices", Renderer->GetVoiceCount()); return out; } + +//========================================================================== +// +// WildMIDIDevice :: GetStats +// +//========================================================================== + +void WildMIDIDevice::WildMidiSetOption(int opt, int set) +{ + Renderer->SetOption(opt, set); +} diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 68ab89933..40e462b62 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2718,6 +2718,16 @@ midi *WildMidi_NewMidi() { ret = NULL; } } + + if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, + reverb_room_length, reverb_listen_posx, reverb_listen_posy)) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); + WildMidi_Close(ret); + ret = NULL; + } + + return ret; } @@ -2988,3 +2998,8 @@ int WildMidi_Renderer::GetVoiceCount() } return count; } + +void WildMidi_Renderer::SetOption(int opt, int set) +{ + WildMidi_SetOption((_mdi*)handle, (unsigned short)opt, (unsigned short)set); +} diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h index ec8dea3c1..8f021d426 100644 --- a/src/wildmidi/wildmidi_lib.h +++ b/src/wildmidi/wildmidi_lib.h @@ -78,6 +78,7 @@ public: void ComputeOutput(float *buffer, int len); void LoadInstrument(int bank, int percussion, int instr); int GetVoiceCount(); + void SetOption(int opt, int set); private: void *handle; }; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 94de2b96c..244b14691 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1592,7 +1592,6 @@ OptionMenu AdvSoundOptions StaticText "GUS Emulation", 1 TextField "GUS config file", "midi_config" Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 - Option "Emulate TiMidity", "midi_timiditylike", "OnOff" Option "Read DMXGUS lumps", "midi_dmxgus", "OnOff" Option "GUS memory size", "gus_memsize", "GusMemory" StaticText " " @@ -1611,6 +1610,7 @@ OptionMenu AdvSoundOptions StaticText " " StaticText "WildMidi", 1 TextField "WildMidi config file", "wildmidi_config" + Option "Reverb", "wildmidi_reverb", "OnOff" } /*======================================= From aff42a6186073abf7ebf6abbe73c5ecc18cced07 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Dec 2015 10:21:17 +0100 Subject: [PATCH 215/335] - don't look up a lump name in PathExpander if we are only looking for real files. --- src/pathexpander.cpp | 2 +- src/sound/music_wildmidi_mididevice.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pathexpander.cpp b/src/pathexpander.cpp index d8b912b65..bb89a0555 100644 --- a/src/pathexpander.cpp +++ b/src/pathexpander.cpp @@ -74,10 +74,10 @@ FileReader *PathExpander::openFileReader(const char *name, int *plumpnum) current_filename = name; FixPathSeperator(current_filename); - int lumpnum = Wads.CheckNumForFullName(current_filename); if (openmode != OM_FILE) { + int lumpnum = Wads.CheckNumForFullName(current_filename); if (lumpnum >= 0) { fp = Wads.ReopenLumpNum(lumpnum); diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp index 80bf46e2b..332a97abe 100644 --- a/src/sound/music_wildmidi_mididevice.cpp +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -226,7 +226,7 @@ FString WildMIDIDevice::GetStats() // //========================================================================== -void WildMIDIDevice::WildMidiSetOption(int opt, int set) -{ - Renderer->SetOption(opt, set); -} +void WildMIDIDevice::WildMidiSetOption(int opt, int set) +{ + Renderer->SetOption(opt, set); +} From a2b377c58039bdf896dea0f79da1d6844b2e135b Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 30 Dec 2015 10:58:52 +0100 Subject: [PATCH 216/335] - Fixed Clang errors/warnings on wildMIDI code. --- src/sound/music_wildmidi_mididevice.cpp | 2 +- src/wildmidi/wildmidi_lib.cpp | 8 ++++---- src/wildmidi/wildmidi_lib.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp index 332a97abe..c3fd674c9 100644 --- a/src/sound/music_wildmidi_mididevice.cpp +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -193,7 +193,7 @@ void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2) void WildMIDIDevice::HandleLongEvent(const BYTE *data, int len) { - Renderer->LongEvent((const char *)data, len); + Renderer->LongEvent(data, len); } //========================================================================== diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 40e462b62..94a446e17 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -162,7 +162,7 @@ struct _mdi { patch_count = 0; amp = 0; mix_buffer = NULL; - mix_buffer_size = NULL; + mix_buffer_size = 0; reverb = NULL; } @@ -2926,7 +2926,7 @@ void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2) } } -void WildMidi_Renderer::LongEvent(const char *data, int len) +void WildMidi_Renderer::LongEvent(const unsigned char *data, int len) { // Check for Roland SysEx if (len >= 11 && // Must be at least 11 bytes @@ -2949,7 +2949,7 @@ void WildMidi_Renderer::LongEvent(const char *data, int len) { // Check destination address if (((data[6] & 0xF0) == 0x10) && data[7] == 0x15) { // Roland drum track setting - int sysex_ch = data[6] & 0x0F; + unsigned char sysex_ch = data[6] & 0x0F; if (sysex_ch == 0) { sysex_ch = 9; @@ -2958,7 +2958,7 @@ void WildMidi_Renderer::LongEvent(const char *data, int len) { sysex_ch -= 1; } - _event_data ev = { sysex_ch, data[8] }; + _event_data ev = { sysex_ch, static_cast(data[8]) }; do_sysex_roland_drum_track((_mdi *)handle, &ev); } else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00) diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h index 8f021d426..b5aa79849 100644 --- a/src/wildmidi/wildmidi_lib.h +++ b/src/wildmidi/wildmidi_lib.h @@ -74,7 +74,7 @@ public: ~WildMidi_Renderer(); void ShortEvent(int status, int parm1, int parm2); - void LongEvent(const char *data, int len); + void LongEvent(const unsigned char *data, int len); void ComputeOutput(float *buffer, int len); void LoadInstrument(int bank, int percussion, int instr); int GetVoiceCount(); From db207feed1a167866ae134c2ed72db12ce1db1c0 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 12:17:38 +0200 Subject: [PATCH 217/335] Added missing header #include for old OS X SDKs --- src/posix/cocoa/st_start.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm index a1db95a0b..36582c64b 100644 --- a/src/posix/cocoa/st_start.mm +++ b/src/posix/cocoa/st_start.mm @@ -31,6 +31,8 @@ ** */ +#include + #import #include "c_cvars.h" From 3466a8c7a90b30156b653704fe81df6d4e496032 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 12:19:50 +0200 Subject: [PATCH 218/335] Disabled miniaturization for OS X startup window Old versions of OS X don't support changing of window style mask --- src/posix/cocoa/st_console.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index e0eba7527..d9c6ba810 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -104,7 +104,7 @@ FConsoleWindow::FConsoleWindow() NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()]; [m_window initWithContentRect:initialRect - styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO]; [m_window setMinSize:[m_window frame].size]; @@ -186,9 +186,6 @@ void FConsoleWindow::ShowFatalError(const char* const message) AddText(PalEntry(255, 255, 170), message); AddText("\n"); - // It's impossible to restore minimized window in modal loop - [m_window setStyleMask:[m_window styleMask] & ~NSMiniaturizableWindowMask]; - [NSApp runModalForWindow:m_window]; } From 63993dee968f214ed2d1f7f6f5d5c2cda3b629b2 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 16:05:16 +0200 Subject: [PATCH 219/335] Hid resize indicator on OS X startup window The resize indicator overlapped with progress bar and Quit/Cancel button on 10.6 and older versions OS X 10.7 and newer don't have this indicator at all --- src/posix/cocoa/st_console.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index d9c6ba810..342e251a3 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -108,6 +108,7 @@ FConsoleWindow::FConsoleWindow() backing:NSBackingStoreBuffered defer:NO]; [m_window setMinSize:[m_window frame].size]; + [m_window setShowsResizeIndicator:NO]; [m_window setTitle:title]; [m_window center]; [m_window exitAppOnClose]; From be6daf5d787de17ce5fabf36ac2e9c5488d79f1b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Dec 2015 19:13:28 +0100 Subject: [PATCH 220/335] - changed instrument lookup in MUS files. Based on evidence from several songs in Eternal Doom the description in all known documents is wrong. The instruments are not stored in a 16-bit word but in an 8-bit byte, followed by some variable size data. Known variations are: * second byte is 0 - no additional data follows * second byte is 1 - a third byte for the 'bank' value follows. --- src/sound/music_mus_midiout.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 5f7d2d503..5f5d39d18 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -43,6 +43,7 @@ #include "doomdef.h" #include "m_swap.h" #include "files.h" +#include "s_sound.h" // MACROS ------------------------------------------------------------------ @@ -211,20 +212,34 @@ bool MUSSong2::CheckDone() void MUSSong2::Precache() { WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD)); - const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD); - int i, j; + const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE); + int i, j, k; - for (i = j = 0; i < MusHeader->NumInstruments; ++i) + for (i = j = k = 0; i < MusHeader->NumInstruments; ++i) { - WORD instr = LittleShort(used[i]); + BYTE instr = used[k++]; + WORD val; if (instr < 128) { - work[j++] = instr; + val = instr; } - else if (used[i] >= 135 && used[i] <= 181) + else if (instr >= 135 && instr <= 181) { // Percussions are 100-based, not 128-based, eh? - work[j++] = instr - 100 + (1 << 14); + val = instr - 100 + (1 << 14); } + + BYTE moreparam = used[k++]; + if (moreparam == 1) + { + BYTE bank = used[k++]; + val |= (bank << 7); + } + else if (moreparam > 0) + { + // No information if this is even valid. Print a message so it can be investigated later + Printf("Unknown instrument data found in music\n"); + } + work[j++] = val; } MIDI->PrecacheInstruments(&work[0], j); } From 3c40d71c20805d96d36089559b1112c9ca682a9e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Dec 2015 20:32:19 +0100 Subject: [PATCH 221/335] - hopefully fixed the MUS precaching for good. According to blzut3, it looks like it is a byte followed by a variable length field. It can be any value 0-15 and will be followed by that many bytes one for each bank used. If the bank count is 0 then it is shorthand for using one bank (bank 0). --- src/sound/music_mus_midiout.cpp | 16 ++++++++-------- src/wildmidi/wildmidi_lib.cpp | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 5f5d39d18..e81adc07f 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -228,18 +228,18 @@ void MUSSong2::Precache() val = instr - 100 + (1 << 14); } - BYTE moreparam = used[k++]; - if (moreparam == 1) + int numbanks = used[k++]; + if (numbanks > 0) { - BYTE bank = used[k++]; - val |= (bank << 7); + for (int b = 0; b < numbanks; b++) + { + work[j++] = val | used[k++]; + } } - else if (moreparam > 0) + else { - // No information if this is even valid. Print a message so it can be investigated later - Printf("Unknown instrument data found in music\n"); + work[j++] = val; } - work[j++] = val; } MIDI->PrecacheInstruments(&work[0], j); } diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 94a446e17..0a527ec2a 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2719,14 +2719,14 @@ midi *WildMidi_NewMidi() { } } - if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, - reverb_room_length, reverb_listen_posx, reverb_listen_posy)) - == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); + if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, + reverb_room_length, reverb_listen_posx, reverb_listen_posy)) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); WildMidi_Close(ret); ret = NULL; - } - + } + return ret; } From c88ed426a805e191742067ad2654871a40bd15e0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Dec 2015 20:39:38 +0100 Subject: [PATCH 222/335] - oops, this somehow lost the shift operator... --- src/sound/music_mus_midiout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index e81adc07f..1ebaa2eb4 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -233,7 +233,7 @@ void MUSSong2::Precache() { for (int b = 0; b < numbanks; b++) { - work[j++] = val | used[k++]; + work[j++] = val | (used[k++] << 7); } } else From 94fec26cb67c61fedefcaaf21c7556e3a782046c Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 31 Dec 2015 11:00:05 +0200 Subject: [PATCH 223/335] Fixed runtime warning on OS X 10.4 Tiger The 'invalid pixel format attribute' warning was introduced with automated graphics switching control --- src/posix/cocoa/i_video.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 799dd5ffd..07c2464f4 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -420,7 +420,7 @@ CocoaVideo::CocoaVideo(const int multisample) attributes[i++] = NSOpenGLPFAStencilSize; attributes[i++] = NSOpenGLPixelFormatAttribute(8); - if (!vid_autoswitch) + if (NSAppKitVersionNumber >= AppKit10_5 && !vid_autoswitch) { attributes[i++] = NSOpenGLPFAAllowOfflineRenderers; } From 1316120fe4ebf2ce47e6ebe595d20cd10901602d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 31 Dec 2015 14:35:34 +0100 Subject: [PATCH 224/335] - fixed: The MUS precacher did not handle invalid patches well. - increased the valid range of patch values for MUS. According to the original MIDI2MUS code it can handle numbers up to 188, not 181, and at least one track from Eternal Doom uses #183. --- src/sound/music_mus_midiout.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 1ebaa2eb4..eaf7e4afb 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -223,10 +223,17 @@ void MUSSong2::Precache() { val = instr; } - else if (instr >= 135 && instr <= 181) + else if (instr >= 135 && instr <= 188) { // Percussions are 100-based, not 128-based, eh? val = instr - 100 + (1 << 14); } + else + { + // skip it. + val = used[k++]; + k += val; + continue; + } int numbanks = used[k++]; if (numbanks > 0) From 262580c92f880b3554540cbd413cc4eae44c0b33 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 31 Dec 2015 17:23:54 +0200 Subject: [PATCH 225/335] Updated LZMA SDK to version 15.14 Enabled support for PPMD compression method --- lzma/C/7z.h | 219 ++-- lzma/C/7zArcIn.c | 1770 +++++++++++++++++++++++++++++++++ lzma/C/7zBuf.c | 6 +- lzma/C/7zBuf.h | 12 +- lzma/C/7zCrc.c | 73 +- lzma/C/7zCrc.h | 4 +- lzma/C/7zCrcOpt.c | 89 +- lzma/C/7zDec.c | 355 ++++--- lzma/C/7zIn.c | 1402 -------------------------- lzma/C/7zStream.c | 6 +- lzma/C/{Types.h => 7zTypes.h} | 10 +- lzma/C/7zVersion.h | 27 +- lzma/C/Bcj2.c | 334 +++++-- lzma/C/Bcj2.h | 160 ++- lzma/C/Bra.c | 2 + lzma/C/Bra.h | 12 +- lzma/C/Bra86.c | 99 +- lzma/C/BraIA64.c | 69 ++ lzma/C/Compiler.h | 32 + lzma/C/CpuArch.c | 53 +- lzma/C/CpuArch.h | 149 ++- lzma/C/Delta.c | 64 ++ lzma/C/Delta.h | 19 + lzma/C/LzFind.c | 499 ++++++++-- lzma/C/LzFind.h | 38 +- lzma/C/LzFindMt.c | 190 ++-- lzma/C/LzFindMt.h | 12 +- lzma/C/LzHash.h | 43 +- lzma/C/Lzma2Dec.c | 50 +- lzma/C/Lzma2Dec.h | 12 +- lzma/C/LzmaDec.c | 229 +++-- lzma/C/LzmaDec.h | 12 +- lzma/C/LzmaEnc.c | 344 ++++--- lzma/C/LzmaEnc.h | 6 +- lzma/C/Ppmd.h | 85 ++ lzma/C/Ppmd7.c | 710 +++++++++++++ lzma/C/Ppmd7.h | 140 +++ lzma/C/Ppmd7Dec.c | 189 ++++ lzma/C/Precomp.h | 10 + lzma/C/Threads.c | 29 +- lzma/C/Threads.h | 26 +- lzma/CMakeLists.txt | 10 +- lzma/history.txt | 56 ++ lzma/lzma.txt | 451 ++------- src/resourcefiles/file_7z.cpp | 15 +- 45 files changed, 5329 insertions(+), 2793 deletions(-) create mode 100644 lzma/C/7zArcIn.c delete mode 100644 lzma/C/7zIn.c rename lzma/C/{Types.h => 7zTypes.h} (93%) create mode 100644 lzma/C/BraIA64.c create mode 100644 lzma/C/Compiler.h create mode 100644 lzma/C/Delta.c create mode 100644 lzma/C/Delta.h create mode 100644 lzma/C/Ppmd.h create mode 100644 lzma/C/Ppmd7.c create mode 100644 lzma/C/Ppmd7.h create mode 100644 lzma/C/Ppmd7Dec.c create mode 100644 lzma/C/Precomp.h diff --git a/lzma/C/7z.h b/lzma/C/7z.h index b7edd3ba5..216f381ca 100644 --- a/lzma/C/7z.h +++ b/lzma/C/7z.h @@ -1,89 +1,57 @@ /* 7z.h -- 7z interface -2010-03-11 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ #ifndef __7Z_H #define __7Z_H -#include "7zBuf.h" +#include "7zTypes.h" EXTERN_C_BEGIN #define k7zStartHeaderSize 0x20 #define k7zSignatureSize 6 -extern Byte k7zSignature[k7zSignatureSize]; -#define k7zMajorVersion 0 -enum EIdEnum -{ - k7zIdEnd, - k7zIdHeader, - k7zIdArchiveProperties, - k7zIdAdditionalStreamsInfo, - k7zIdMainStreamsInfo, - k7zIdFilesInfo, - k7zIdPackInfo, - k7zIdUnpackInfo, - k7zIdSubStreamsInfo, - k7zIdSize, - k7zIdCRC, - k7zIdFolder, - k7zIdCodersUnpackSize, - k7zIdNumUnpackStream, - k7zIdEmptyStream, - k7zIdEmptyFile, - k7zIdAnti, - k7zIdName, - k7zIdCTime, - k7zIdATime, - k7zIdMTime, - k7zIdWinAttributes, - k7zIdComment, - k7zIdEncodedHeader, - k7zIdStartPos, - k7zIdDummy -}; +extern const Byte k7zSignature[k7zSignatureSize]; typedef struct { - UInt32 NumInStreams; - UInt32 NumOutStreams; - UInt64 MethodID; - CBuf Props; -} CSzCoderInfo; + const Byte *Data; + size_t Size; +} CSzData; -void SzCoderInfo_Init(CSzCoderInfo *p); -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); +/* CSzCoderInfo & CSzFolder support only default methods */ + +typedef struct +{ + size_t PropsOffset; + UInt32 MethodID; + Byte NumStreams; + Byte PropsSize; +} CSzCoderInfo; typedef struct { UInt32 InIndex; UInt32 OutIndex; -} CSzBindPair; +} CSzBond; + +#define SZ_NUM_CODERS_IN_FOLDER_MAX 4 +#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 +#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 typedef struct { - CSzCoderInfo *Coders; - CSzBindPair *BindPairs; - UInt32 *PackStreams; - UInt64 *UnpackSizes; UInt32 NumCoders; - UInt32 NumBindPairs; + UInt32 NumBonds; UInt32 NumPackStreams; - int UnpackCRCDefined; - UInt32 UnpackCRC; - - UInt32 NumUnpackStreams; + UInt32 UnpackStream; + UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; + CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; } CSzFolder; -void SzFolder_Init(CSzFolder *p); -UInt64 SzFolder_GetUnpackSize(CSzFolder *p); -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); -UInt64 SzFolder_GetUnpackSize(CSzFolder *p); -SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, - ILookInStream *stream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); typedef struct { @@ -93,38 +61,97 @@ typedef struct typedef struct { - CNtfsFileTime MTime; - UInt64 Size; - UInt32 Crc; - UInt32 Attrib; - Byte HasStream; - Byte IsDir; - Byte IsAnti; - Byte CrcDefined; - Byte MTimeDefined; - Byte AttribDefined; -} CSzFileItem; - -void SzFile_Init(CSzFileItem *p); + Byte *Defs; /* MSB 0 bit numbering */ + UInt32 *Vals; +} CSzBitUi32s; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + // UInt64 *Vals; + CNtfsFileTime *Vals; +} CSzBitUi64s; + +#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) typedef struct { - UInt64 *PackSizes; - Byte *PackCRCsDefined; - UInt32 *PackCRCs; - CSzFolder *Folders; - CSzFileItem *Files; UInt32 NumPackStreams; UInt32 NumFolders; - UInt32 NumFiles; + + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders + + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders + + Byte *CodersData; } CSzAr; -void SzAr_Init(CSzAr *p); -void SzAr_Free(CSzAr *p, ISzAlloc *alloc); +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAlloc *allocMain); + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 NumFiles; + + UInt64 *UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte *IsDirs; + CSzBitUi32s CRCs; + + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; + + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles + + size_t *FileNameOffsets; /* in 2-byte steps */ + Byte *FileNames; /* UTF-16-LE */ +} CSzArEx; + +#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) + +#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + /* - SzExtract extracts file from archive + SzArEx_Extract extracts file from archive *outBuffer must be 0 before first call for each new archive. @@ -143,35 +170,6 @@ void SzAr_Free(CSzAr *p, ISzAlloc *alloc); Free *outBuffer and set *outBuffer to 0, if you want to flush cache. */ -typedef struct -{ - CSzAr db; - - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 *FolderStartPackStreamIndex; - UInt64 *PackStreamStartPositions; - UInt32 *FolderStartFileIndex; - UInt32 *FileIndexToFolderIndexMap; - - size_t *FileNameOffsets; /* in 2-byte steps */ - CBuf FileNames; /* UTF-16-LE */ -} CSzArEx; - -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); - -/* -if dest == NULL, the return value specifies the required size of the buffer, - in 16-bit characters, including the null-terminating character. -if dest != NULL, the return value specifies the number of 16-bit characters that - are written to the dest, including the null-terminating character. */ - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); - SRes SzArEx_Extract( const CSzArEx *db, ILookInStream *inStream, @@ -196,7 +194,8 @@ SZ_ERROR_INPUT_EOF SZ_ERROR_FAIL */ -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAlloc *allocMain, ISzAlloc *allocTemp); EXTERN_C_END diff --git a/lzma/C/7zArcIn.c b/lzma/C/7zArcIn.c new file mode 100644 index 000000000..080d8df2a --- /dev/null +++ b/lzma/C/7zArcIn.c @@ -0,0 +1,1770 @@ +/* 7zArcIn.c -- 7z Input functions +2015-11-18 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7z.h" +#include "7zBuf.h" +#include "7zCrc.h" +#include "CpuArch.h" + +#define MY_ALLOC(T, p, size, alloc) { \ + if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } + +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal +}; + +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc) +{ + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } + return SZ_OK; +} + +void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + +#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + + +static void SzAr_Init(CSzAr *p) +{ + p->NumPackStreams = 0; + p->NumFolders = 0; + + p->PackPositions = NULL; + SzBitUi32s_Init(&p->FolderCRCs); + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; +} + +static void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); + + IAlloc_Free(alloc, p->FoCodersOffsets); + IAlloc_Free(alloc, p->FoStartPackStreamIndex); + IAlloc_Free(alloc, p->FoToCoderUnpackSizes); + IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + IAlloc_Free(alloc, p->CoderUnpackSizes); + + IAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_Init(&p->CRCs); + SzBitUi32s_Init(&p->Attribs); + // SzBitUi32s_Init(&p->Parents); + SzBitUi64s_Init(&p->MTime); + SzBitUi64s_Init(&p->CTime); +} + +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->UnpackPositions); + IAlloc_Free(alloc, p->IsDirs); + + IAlloc_Free(alloc, p->FolderToFile); + IAlloc_Free(alloc, p->FileToFolder); + + IAlloc_Free(alloc, p->FileNameOffsets); + IAlloc_Free(alloc, p->FileNames); + + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + + +static int TestSignatureCandidate(const Byte *testBytes) +{ + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; +#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) +#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; + +#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } +#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } + +#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ + dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); + +static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte, mask; + unsigned i; + UInt32 v; + + SZ_READ_BYTE(firstByte); + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v); + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask); + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + + +static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)); + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +#define ReadID(sd, value) ReadNumber(sd, value) + +static SRes SkipData(CSzData *sd) +{ + UInt64 size; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size); + return SZ_OK; +} + +static SRes WaitId(CSzData *sd, UInt32 id) +{ + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)); + } +} + +static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +{ + UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes); + return SZ_OK; +} + +static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +{ + Byte b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += ((b >> m) & 1); + } + return sum; +} + +static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc) +{ + Byte allAreDefined; + Byte *v2; + UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); + SKIP_DATA(sd, numBytes); + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc); + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; +} + +static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +{ + UInt32 i; + CSzData sd; + UInt32 *vals; + const Byte *defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]); + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; +} + +static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +{ + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + return ReadUi32s(sd, numItems, crcs, alloc); +} + +static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +{ + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined); + if (!allAreDefined) + { + size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes); + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4); + return SZ_OK; +} + +static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc) +{ + RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + + RINOK(WaitId(sd, k7zIdSize)); + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + { + UInt64 sum = 0; + UInt32 i; + UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)); + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + continue; + } + RINOK(SkipData(sd)); + } +} + +/* +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} +*/ + +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +{ + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte *dataStart = sd->Data; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; + + SZ_READ_BYTE(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; + + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; + + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)); + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = sd->Data - dataStart; + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; +} + + +static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +{ + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte); + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i); + } + *sd2 = sd; + return SZ_OK; +} + + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + + +static SRes ReadUnpackInfo(CSzAr *p, + CSzData *sd2, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAlloc *alloc) +{ + CSzData sd; + + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte *startBufPtr; + Byte external; + + RINOK(WaitId(sd2, k7zIdFolder)); + + RINOK(SzReadNumber32(sd2, &numFolders)); + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + + RINOK(SzReadNumber32(&sd, &numCoders)); + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize); + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)); + RINOK(SzReadNumber32(&sd, &coderOutStreams)); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)); + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize); + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + + packStreamIndex += numPackStreams; + if (packStreamIndex < numPackStreams) + return SZ_ERROR_UNSUPPORTED; + + if (packStreamIndex > p->NumPackStreams) + return SZ_ERROR_ARCHIVE; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + size_t dataSize = sd.Data - startBufPtr; + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)); + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + continue; + } + RINOK(SkipData(&sd)); + } +} + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + + +typedef struct +{ + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; +} CSubStreamInfo; + + +static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +{ + UInt64 type = 0; + UInt32 numSubDigests = 0; + UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; + + for (;;) + { + RINOK(ReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } + + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; + + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)); + ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; + RINOK(ReadID(sd, &type)); + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)); + ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + } + else + { + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } +} + +static SRes SzReadStreamsInfo(CSzAr *p, + CSzData *sd, + UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt64 *dataOffset, + CSubStreamInfo *ssi, + ISzAlloc *alloc) +{ + UInt64 type; + + SzData_Clear(&ssi->sdSizes); + SzData_Clear(&ssi->sdCRCs); + SzData_Clear(&ssi->sdNumSubStreams); + + *dataOffset = 0; + RINOK(ReadID(sd, &type)); + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)); + RINOK(ReadPackInfo(p, sd, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)); + RINOK(ReadID(sd, &type)); + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } + + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr *p, + ISzAlloc *allocTemp) +{ + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; + + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf *tempBuf = tempBufs + fo; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf *tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + } + + return SZ_OK; +} + +static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +{ + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte *p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; + #ifdef _WIN32 + *(const UInt16 *)p != 0 + #else + p[0] != 0 || p[1] != 0 + #endif + ; p += 2); + pos = p - data + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, + CSzData *sd2, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAlloc *alloc) +{ + CSzData sd; + UInt32 i; + CNtfsFileTime *vals; + Byte *defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8); + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; +} + + +#define NUM_ADDITIONAL_STREAMS_MAX 8 + + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + ILookInStream *inStream, + CBuf *tempBufs, UInt32 *numTempBufs, + ISzAlloc *allocMain, + ISzAlloc *allocTemp + ) +{ + UInt64 type; + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + CSubStreamInfo ssi; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; + + SzData_Clear(&ssi.sdSizes); + SzData_Clear(&ssi.sdCRCs); + SzData_Clear(&ssi.sdNumSubStreams); + + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; + + RINOK(ReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)); + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdEnd) + { + return SZ_OK; + } + + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->NumFiles = numFiles; + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size); + } + else switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte *namesData; + Byte external; + + SZ_READ_BYTE(external); + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } + + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize); + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData *sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + + SZ_READ_BYTE(external); + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + default: + { + SKIP_DATA(sd, size); + } + } + } + + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; + UInt32 digestsValsIndex = 0; + UInt32 digestIndex; + Byte allDigestsDefined = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; + + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + + if (ssi.sdCRCs.Size != 0) + { + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } + + digestIndex = 0; + + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)); + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + } + } + + if (mask != 0x80) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } + + return SZ_OK; +} + + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); + + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); + + RINOK(res); + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; + + startArcPos = 0; + RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; +} + + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAlloc *allocMain, ISzAlloc *allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **tempBuf, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; + + *offset = 0; + *outSizeProcessed = 0; + + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } + + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + size_t unpackSize = (size_t)unpackSizeSpec; + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; +} + + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t offs = p->FileNameOffsets[fileIndex]; + size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) +{ + size_t len; + if (!p->FileNameOffsets) + return 1; + len = 0; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return len; + fileIndex = parent; + } +} + +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + Bool needSlash; + if (!p->FileNameOffsets) + { + *(--dest) = 0; + return dest; + } + needSlash = False; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); + if (needSlash) + *(dest - 1) = '/'; + needSlash = True; + dest -= curLen; + + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return dest; + fileIndex = parent; + } +} +*/ diff --git a/lzma/C/7zBuf.c b/lzma/C/7zBuf.c index a35fa2f98..b0ac1104b 100644 --- a/lzma/C/7zBuf.c +++ b/lzma/C/7zBuf.c @@ -1,7 +1,7 @@ /* 7zBuf.c -- Byte Buffer -2008-03-28 -Igor Pavlov -Public domain */ +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "7zBuf.h" diff --git a/lzma/C/7zBuf.h b/lzma/C/7zBuf.h index 88ff0c2f2..e5f9218be 100644 --- a/lzma/C/7zBuf.h +++ b/lzma/C/7zBuf.h @@ -1,14 +1,12 @@ /* 7zBuf.h -- Byte Buffer -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_BUF_H #define __7Z_BUF_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN typedef struct { @@ -32,8 +30,6 @@ void DynBuf_SeekToBeg(CDynBuf *p); int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/7zCrc.c b/lzma/C/7zCrc.c index 6993a6988..607db3404 100644 --- a/lzma/C/7zCrc.c +++ b/lzma/C/7zCrc.c @@ -1,29 +1,35 @@ /* 7zCrc.c -- CRC32 init -2010-12-01 : Igor Pavlov : Public domain */ +2015-03-10 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #define kCrcPoly 0xEDB88320 -#ifdef MY_CPU_X86_OR_AMD64 +#ifdef MY_CPU_LE #define CRC_NUM_TABLES 8 - UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); -#elif defined(MY_CPU_LE) - #define CRC_NUM_TABLES 4 #else - #define CRC_NUM_TABLES 5 + #define CRC_NUM_TABLES 9 + #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); -static CRC_FUNC g_CrcUpdate; +CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT8; +CRC_FUNC g_CrcUpdate; + UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) @@ -36,6 +42,17 @@ UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + void MY_FAST_CALL CrcGenerateTable() { UInt32 i; @@ -52,22 +69,43 @@ void MY_FAST_CALL CrcGenerateTable() UInt32 r = g_CrcTable[i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } + + #if CRC_NUM_TABLES < 4 + g_CrcUpdate = CrcUpdateT1; + + #else + #ifdef MY_CPU_LE - g_CrcUpdate = CrcUpdateT4; + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; - #if CRC_NUM_TABLES == 8 - if (!CPU_Is_InOrder()) - g_CrcUpdate = CrcUpdateT8; - #endif + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; + #endif + #endif #else { #ifndef MY_CPU_BE - UInt32 k = 1; - if (*(const Byte *)&k == 1) + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + { + g_CrcUpdateT4 = CrcUpdateT4; g_CrcUpdate = CrcUpdateT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + // g_CrcUpdate = CrcUpdateT8; + #endif + } + else if (p[0] != 1 || p[1] != 2) + g_CrcUpdate = CrcUpdateT1; else #endif { @@ -76,8 +114,15 @@ void MY_FAST_CALL CrcGenerateTable() UInt32 x = g_CrcTable[i - 256]; g_CrcTable[i] = CRC_UINT32_SWAP(x); } + g_CrcUpdateT4 = CrcUpdateT1_BeT4; g_CrcUpdate = CrcUpdateT1_BeT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + // g_CrcUpdate = CrcUpdateT1_BeT8; + #endif } } #endif + + #endif } diff --git a/lzma/C/7zCrc.h b/lzma/C/7zCrc.h index 4a1ec38c9..3b0459402 100644 --- a/lzma/C/7zCrc.h +++ b/lzma/C/7zCrc.h @@ -1,10 +1,10 @@ /* 7zCrc.h -- CRC32 calculation -2009-11-21 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_CRC_H #define __7Z_CRC_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN diff --git a/lzma/C/7zCrcOpt.c b/lzma/C/7zCrcOpt.c index 85405ccfc..58628efe5 100644 --- a/lzma/C/7zCrcOpt.c +++ b/lzma/C/7zCrcOpt.c @@ -1,12 +1,14 @@ /* 7zCrcOpt.c -- CRC32 calculation -2010-12-01 : Igor Pavlov : Public domain */ +2015-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "CpuArch.h" -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - #ifndef MY_CPU_BE +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; @@ -16,10 +18,10 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U { v ^= *(const UInt32 *)p; v = - table[0x300 + (v & 0xFF)] ^ - table[0x200 + ((v >> 8) & 0xFF)] ^ - table[0x100 + ((v >> 16) & 0xFF)] ^ - table[0x000 + ((v >> 24))]; + table[0x300 + ((v ) & 0xFF)] + ^ table[0x200 + ((v >> 8) & 0xFF)] + ^ table[0x100 + ((v >> 16) & 0xFF)] + ^ table[0x000 + ((v >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); @@ -28,7 +30,28 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { - return CrcUpdateT4(v, data, size, table); + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x700 + ((v ) & 0xFF)] + ^ table[0x600 + ((v >> 8) & 0xFF)] + ^ table[0x500 + ((v >> 16) & 0xFF)] + ^ table[0x400 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x300 + ((d ) & 0xFF)] + ^ table[0x200 + ((d >> 8) & 0xFF)] + ^ table[0x100 + ((d >> 16) & 0xFF)] + ^ table[0x000 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } #endif @@ -38,27 +61,55 @@ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const U #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - v = CRC_UINT32_SWAP(v); table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = - table[0x000 + (v & 0xFF)] ^ - table[0x100 + ((v >> 8) & 0xFF)] ^ - table[0x200 + ((v >> 16) & 0xFF)] ^ - table[0x300 + ((v >> 24))]; + table[0x000 + ((v ) & 0xFF)] + ^ table[0x100 + ((v >> 8) & 0xFF)] + ^ table[0x200 + ((v >> 16) & 0xFF)] + ^ table[0x300 + ((v >> 24))]; } - table -= 0x100; - v = CRC_UINT32_SWAP(v); for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x400 + ((v ) & 0xFF)] + ^ table[0x500 + ((v >> 8) & 0xFF)] + ^ table[0x600 + ((v >> 16) & 0xFF)] + ^ table[0x700 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x000 + ((d ) & 0xFF)] + ^ table[0x100 + ((d >> 8) & 0xFF)] + ^ table[0x200 + ((d >> 16) & 0xFF)] + ^ table[0x300 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); } #endif diff --git a/lzma/C/7zDec.c b/lzma/C/7zDec.c index 338680747..e39b4ff12 100644 --- a/lzma/C/7zDec.c +++ b/lzma/C/7zDec.c @@ -1,15 +1,19 @@ /* 7zDec.c -- Decoding from 7z folder -2010-11-02 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include /* #define _7ZIP_PPMD_SUPPPORT */ #include "7z.h" +#include "7zCrc.h" #include "Bcj2.h" #include "Bra.h" #include "CpuArch.h" +#include "Delta.h" #include "LzmaDec.h" #include "Lzma2Dec.h" #ifdef _7ZIP_PPMD_SUPPPORT @@ -17,14 +21,17 @@ #endif #define k_Copy 0 +#define k_Delta 3 #define k_LZMA2 0x21 #define k_LZMA 0x30101 -#define k_BCJ 0x03030103 -#define k_PPC 0x03030205 -#define k_ARM 0x03030501 -#define k_ARMT 0x03030701 -#define k_SPARC 0x03030805 -#define k_BCJ2 0x0303011B +#define k_BCJ 0x3030103 +#define k_BCJ2 0x303011B +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_ARMT 0x3030701 +#define k_SPARC 0x3030805 + #ifdef _7ZIP_PPMD_SUPPPORT @@ -63,7 +70,7 @@ static Byte ReadByte(void *pp) return 0; } -static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CPpmd7 ppmd; @@ -77,12 +84,12 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt s.res = SZ_OK; s.processed = 0; - if (coder->Props.size != 5) + if (propsSize != 5) return SZ_ERROR_UNSUPPORTED; { - unsigned order = coder->Props.data[0]; - UInt32 memSize = GetUi32(coder->Props.data + 1); + unsigned order = props[0]; + UInt32 memSize = GetUi32(props + 1); if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER || memSize < PPMD7_MIN_MEM_SIZE || @@ -124,25 +131,25 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt #endif -static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CLzmaDec state; SRes res = SZ_OK; LzmaDec_Construct(&state); - RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); state.dic = outBuffer; state.dicBufSize = outSize; LzmaDec_Init(&state); for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break; @@ -154,14 +161,23 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt inSize -= inProcessed; if (res != SZ_OK) break; - if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + if (outSize != state.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break; @@ -172,27 +188,30 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt return res; } -static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + +#ifndef _7Z_NO_METHOD_LZMA2 + +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CLzma2Dec state; SRes res = SZ_OK; Lzma2Dec_Construct(&state); - if (coder->Props.size != 1) + if (propsSize != 1) return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); state.decoder.dic = outBuffer; state.decoder.dicBufSize = outSize; Lzma2Dec_Init(&state); for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break; @@ -204,13 +223,20 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS inSize -= inProcessed; if (res != SZ_OK) break; - if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.decoder.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK)) + if (outSize != state.decoder.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break; @@ -221,15 +247,18 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS return res; } +#endif + + static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) { while (inSize > 0) { - void *inBuf; + const void *inBuf; size_t curSize = (1 << 18); if (curSize > inSize) curSize = (size_t)inSize; - RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); + RINOK(inStream->Look(inStream, &inBuf, &curSize)); if (curSize == 0) return SZ_ERROR_INPUT_EOF; memcpy(outBuffer, inBuf, curSize); @@ -242,11 +271,13 @@ static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer static Bool IS_MAIN_METHOD(UInt32 m) { - switch(m) + switch (m) { case k_Copy: case k_LZMA: + #ifndef _7Z_NO_METHOD_LZMA2 case k_LZMA2: + #endif #ifdef _7ZIP_PPMD_SUPPPORT case k_PPMD: #endif @@ -258,13 +289,12 @@ static Bool IS_MAIN_METHOD(UInt32 m) static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) { return - c->NumInStreams == 1 && - c->NumOutStreams == 1 && - c->MethodID <= (UInt32)0xFFFFFFFF && - IS_MAIN_METHOD((UInt32)c->MethodID); + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); } -#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) static SRes CheckSupportedFolder(const CSzFolder *f) { @@ -274,65 +304,73 @@ static SRes CheckSupportedFolder(const CSzFolder *f) return SZ_ERROR_UNSUPPORTED; if (f->NumCoders == 1) { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + + + #ifndef _7Z_NO_METHODS_FILTERS + if (f->NumCoders == 2) { - CSzCoderInfo *c = &f->Coders[1]; - if (c->MethodID > (UInt32)0xFFFFFFFF || - c->NumInStreams != 1 || - c->NumOutStreams != 1 || - f->NumPackStreams != 1 || - f->PackStreams[0] != 0 || - f->NumBindPairs != 1 || - f->BindPairs[0].InIndex != 1 || - f->BindPairs[0].OutIndex != 0) + const CSzCoderInfo *c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) return SZ_ERROR_UNSUPPORTED; switch ((UInt32)c->MethodID) { + case k_Delta: case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: case k_ARM: + case k_ARMT: break; default: return SZ_ERROR_UNSUPPORTED; } return SZ_OK; } + + #endif + + if (f->NumCoders == 4) { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) || - !IS_SUPPORTED_CODER(&f->Coders[2]) || - !IS_BCJ2(&f->Coders[3])) + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 || - f->PackStreams[0] != 2 || - f->PackStreams[1] != 6 || - f->PackStreams[2] != 1 || - f->PackStreams[3] != 0 || - f->NumBindPairs != 3 || - f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || - f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || - f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + return SZ_ERROR_UNSUPPORTED; } -static UInt64 GetSum(const UInt64 *values, UInt32 index) -{ - UInt64 sum = 0; - UInt32 i; - for (i = 0; i < index; i++) - sum += values[i]; - return sum; -} - #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; -static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, +static SRes SzFolder_Decode2(const CSzFolder *folder, + const Byte *propsData, + const UInt64 *unpackSizes, + const UInt64 *packPositions, ILookInStream *inStream, UInt64 startPos, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, Byte *tempBuf[]) @@ -346,7 +384,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, for (ci = 0; ci < folder->NumCoders; ci++) { - CSzCoderInfo *coder = &folder->Coders[ci]; + const CSzCoderInfo *coder = &folder->Coders[ci]; if (IS_MAIN_METHOD((UInt32)coder->MethodID)) { @@ -358,7 +396,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, if (folder->NumCoders == 4) { UInt32 indices[] = { 3, 2, 0 }; - UInt64 unpackSize = folder->UnpackSizes[ci]; + UInt64 unpackSize = unpackSizes[ci]; si = indices[ci]; if (ci < 2) { @@ -367,7 +405,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, if (outSizeCur != unpackSize) return SZ_ERROR_MEM; temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); - if (temp == 0 && outSizeCur != 0) + if (!temp && outSizeCur != 0) return SZ_ERROR_MEM; outBufCur = tempBuf[1 - ci] = temp; tempSizes[1 - ci] = outSizeCur; @@ -382,8 +420,8 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, else return SZ_ERROR_UNSUPPORTED; } - offset = GetSum(packSizes, si); - inSize = packSizes[si]; + offset = packPositions[si]; + inSize = packPositions[si + 1] - offset; RINOK(LookInStream_SeekTo(inStream, startPos + offset)); if (coder->MethodID == k_Copy) @@ -394,77 +432,160 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, } else if (coder->MethodID == k_LZMA) { - RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } + #ifndef _7Z_NO_METHOD_LZMA2 else if (coder->MethodID == k_LZMA2) { - RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } - else + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + else if (coder->MethodID == k_PPMD) { - #ifdef _7ZIP_PPMD_SUPPPORT - RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); - #else - return SZ_ERROR_UNSUPPORTED; - #endif + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } + #endif + else + return SZ_ERROR_UNSUPPORTED; } else if (coder->MethodID == k_BCJ2) { - UInt64 offset = GetSum(packSizes, 1); - UInt64 s3Size = packSizes[1]; - SRes res; + UInt64 offset = packPositions[1]; + UInt64 s3Size = packPositions[2] - offset; + if (ci != 3) return SZ_ERROR_UNSUPPORTED; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + tempSizes[2] = (SizeT)s3Size; if (tempSizes[2] != s3Size) return SZ_ERROR_MEM; tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); - if (tempBuf[2] == 0 && tempSizes[2] != 0) + if (!tempBuf[2] && tempSizes[2] != 0) return SZ_ERROR_MEM; - res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); - RINOK(res) + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; - res = Bcj2_Decode( - tempBuf3, tempSize3, - tempBuf[0], tempSizes[0], - tempBuf[1], tempSizes[1], - tempBuf[2], tempSizes[2], - outBuffer, outSize); - RINOK(res) - } - else - { - if (ci != 1) - return SZ_ERROR_UNSUPPORTED; - switch(coder->MethodID) { - case k_BCJ: + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); - break; + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; + + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; } - CASE_BRA_CONV(ARM) - default: - return SZ_ERROR_UNSUPPORTED; } } + #ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) + { + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + } + else + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } + #endif + else + return SZ_ERROR_UNSUPPORTED; } + return SZ_OK; } -SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) + Byte *outBuffer, size_t outSize, + ISzAlloc *allocMain) { - Byte *tempBuf[3] = { 0, 0, 0}; - int i; - SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, - outBuffer, (SizeT)outSize, allocMain, tempBuf); - for (i = 0; i < 3; i++) - IAlloc_Free(allocMain, tempBuf[i]); - return res; + SRes res; + CSzFolder folder; + CSzData sd; + + const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; + + res = SzGetNextFolderItem(&folder, &sd); + + if (res != SZ_OK) + return res; + + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte *tempBuf[3] = { 0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + IAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } } diff --git a/lzma/C/7zIn.c b/lzma/C/7zIn.c deleted file mode 100644 index f1a44928e..000000000 --- a/lzma/C/7zIn.c +++ /dev/null @@ -1,1402 +0,0 @@ -/* 7zIn.c -- 7z Input functions -2010-10-29 : Igor Pavlov : Public domain */ - -#include - -#include "7z.h" -#include "7zCrc.h" -#include "CpuArch.h" - -Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } - -#define NUM_FOLDER_CODERS_MAX 32 -#define NUM_CODER_STREAMS_MAX 32 - -void SzCoderInfo_Init(CSzCoderInfo *p) -{ - Buf_Init(&p->Props); -} - -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) -{ - Buf_Free(&p->Props, alloc); - SzCoderInfo_Init(p); -} - -void SzFolder_Init(CSzFolder *p) -{ - p->Coders = 0; - p->BindPairs = 0; - p->PackStreams = 0; - p->UnpackSizes = 0; - p->NumCoders = 0; - p->NumBindPairs = 0; - p->NumPackStreams = 0; - p->UnpackCRCDefined = 0; - p->UnpackCRC = 0; - p->NumUnpackStreams = 0; -} - -void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Coders) - for (i = 0; i < p->NumCoders; i++) - SzCoderInfo_Free(&p->Coders[i], alloc); - IAlloc_Free(alloc, p->Coders); - IAlloc_Free(alloc, p->BindPairs); - IAlloc_Free(alloc, p->PackStreams); - IAlloc_Free(alloc, p->UnpackSizes); - SzFolder_Init(p); -} - -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) -{ - UInt32 result = 0; - UInt32 i; - for (i = 0; i < p->NumCoders; i++) - result += p->Coders[i].NumOutStreams; - return result; -} - -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].InIndex == inStreamIndex) - return i; - return -1; -} - - -int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].OutIndex == outStreamIndex) - return i; - return -1; -} - -UInt64 SzFolder_GetUnpackSize(CSzFolder *p) -{ - int i = (int)SzFolder_GetNumOutStreams(p); - if (i == 0) - return 0; - for (i--; i >= 0; i--) - if (SzFolder_FindBindPairForOutStream(p, i) < 0) - return p->UnpackSizes[i]; - /* throw 1; */ - return 0; -} - -void SzFile_Init(CSzFileItem *p) -{ - p->HasStream = 1; - p->IsDir = 0; - p->IsAnti = 0; - p->CrcDefined = 0; - p->MTimeDefined = 0; -} - -void SzAr_Init(CSzAr *p) -{ - p->PackSizes = 0; - p->PackCRCsDefined = 0; - p->PackCRCs = 0; - p->Folders = 0; - p->Files = 0; - p->NumPackStreams = 0; - p->NumFolders = 0; - p->NumFiles = 0; -} - -void SzAr_Free(CSzAr *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Folders) - for (i = 0; i < p->NumFolders; i++) - SzFolder_Free(&p->Folders[i], alloc); - - IAlloc_Free(alloc, p->PackSizes); - IAlloc_Free(alloc, p->PackCRCsDefined); - IAlloc_Free(alloc, p->PackCRCs); - IAlloc_Free(alloc, p->Folders); - IAlloc_Free(alloc, p->Files); - SzAr_Init(p); -} - - -void SzArEx_Init(CSzArEx *p) -{ - SzAr_Init(&p->db); - p->FolderStartPackStreamIndex = 0; - p->PackStreamStartPositions = 0; - p->FolderStartFileIndex = 0; - p->FileIndexToFolderIndexMap = 0; - p->FileNameOffsets = 0; - Buf_Init(&p->FileNames); -} - -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) -{ - IAlloc_Free(alloc, p->FolderStartPackStreamIndex); - IAlloc_Free(alloc, p->PackStreamStartPositions); - IAlloc_Free(alloc, p->FolderStartFileIndex); - IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); - - IAlloc_Free(alloc, p->FileNameOffsets); - Buf_Free(&p->FileNames, alloc); - - SzAr_Free(&p->db, alloc); - SzArEx_Init(p); -} - -/* -UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const -{ - return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; -} - -UInt64 GetFilePackSize(int fileIndex) const -{ - int folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex >= 0) - { - const CSzFolder &folderInfo = Folders[folderIndex]; - if (FolderStartFileIndex[folderIndex] == fileIndex) - return GetFolderFullPackSize(folderIndex); - } - return 0; -} -*/ - -#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ - if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } - -static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) -{ - UInt32 startPos = 0; - UInt64 startPosSize = 0; - UInt32 i; - UInt32 folderIndex = 0; - UInt32 indexInFolder = 0; - MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); - for (i = 0; i < p->db.NumFolders; i++) - { - p->FolderStartPackStreamIndex[i] = startPos; - startPos += p->db.Folders[i].NumPackStreams; - } - - MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); - - for (i = 0; i < p->db.NumPackStreams; i++) - { - p->PackStreamStartPositions[i] = startPosSize; - startPosSize += p->db.PackSizes[i]; - } - - MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); - MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); - - for (i = 0; i < p->db.NumFiles; i++) - { - CSzFileItem *file = p->db.Files + i; - int emptyStream = !file->HasStream; - if (emptyStream && indexInFolder == 0) - { - p->FileIndexToFolderIndexMap[i] = (UInt32)-1; - continue; - } - if (indexInFolder == 0) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: Loop for skipping empty folders - */ - for (;;) - { - if (folderIndex >= p->db.NumFolders) - return SZ_ERROR_ARCHIVE; - p->FolderStartFileIndex[folderIndex] = i; - if (p->db.Folders[folderIndex].NumUnpackStreams != 0) - break; - folderIndex++; - } - } - p->FileIndexToFolderIndexMap[i] = folderIndex; - if (emptyStream) - continue; - indexInFolder++; - if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) - { - folderIndex++; - indexInFolder = 0; - } - } - return SZ_OK; -} - - -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) -{ - return p->dataPos + - p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; -} - -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) -{ - UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 size = 0; - UInt32 i; - for (i = 0; i < folder->NumPackStreams; i++) - { - UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; - if (t < size) /* check it */ - return SZ_ERROR_FAIL; - size = t; - } - *resSize = size; - return SZ_OK; -} - - -/* -SRes SzReadTime(const CObjectVector &dataVector, - CObjectVector &files, UInt64 type) -{ - CBoolVector boolVector; - RINOK(ReadBoolVector2(files.Size(), boolVector)) - - CStreamSwitch streamSwitch; - RINOK(streamSwitch.Set(this, &dataVector)); - - for (int i = 0; i < files.Size(); i++) - { - CSzFileItem &file = files[i]; - CArchiveFileTime fileTime; - bool defined = boolVector[i]; - if (defined) - { - UInt32 low, high; - RINOK(SzReadUInt32(low)); - RINOK(SzReadUInt32(high)); - fileTime.dwLowDateTime = low; - fileTime.dwHighDateTime = high; - } - switch(type) - { - case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; - case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; - case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; - } - } - return SZ_OK; -} -*/ - -static int TestSignatureCandidate(Byte *testBytes) -{ - size_t i; - for (i = 0; i < k7zSignatureSize; i++) - if (testBytes[i] != k7zSignature[i]) - return 0; - return 1; -} - -typedef struct _CSzState -{ - Byte *Data; - size_t Size; -}CSzData; - -static SRes SzReadByte(CSzData *sd, Byte *b) -{ - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - sd->Size--; - *b = *sd->Data++; - return SZ_OK; -} - -static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) -{ - size_t i; - for (i = 0; i < size; i++) - { - RINOK(SzReadByte(sd, data + i)); - } - return SZ_OK; -} - -static SRes SzReadUInt32(CSzData *sd, UInt32 *value) -{ - int i; - *value = 0; - for (i = 0; i < 4; i++) - { - Byte b; - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt32)(b) << (8 * i)); - } - return SZ_OK; -} - -static SRes SzReadNumber(CSzData *sd, UInt64 *value) -{ - Byte firstByte; - Byte mask = 0x80; - int i; - RINOK(SzReadByte(sd, &firstByte)); - *value = 0; - for (i = 0; i < 8; i++) - { - Byte b; - if ((firstByte & mask) == 0) - { - UInt64 highPart = firstByte & (mask - 1); - *value += (highPart << (8 * i)); - return SZ_OK; - } - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt64)b << (8 * i)); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadNumber32(CSzData *sd, UInt32 *value) -{ - UInt64 value64; - RINOK(SzReadNumber(sd, &value64)); - if (value64 >= 0x80000000) - return SZ_ERROR_UNSUPPORTED; - if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) - return SZ_ERROR_UNSUPPORTED; - *value = (UInt32)value64; - return SZ_OK; -} - -static SRes SzReadID(CSzData *sd, UInt64 *value) -{ - return SzReadNumber(sd, value); -} - -static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) -{ - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - sd->Size -= (size_t)size; - sd->Data += (size_t)size; - return SZ_OK; -} - -static SRes SzSkeepData(CSzData *sd) -{ - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - return SzSkeepDataSize(sd, size); -} - -static SRes SzReadArchiveProperties(CSzData *sd) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - SzSkeepData(sd); - } - return SZ_OK; -} - -static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == attribute) - return SZ_OK; - if (type == k7zIdEnd) - return SZ_ERROR_ARCHIVE; - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte b = 0; - Byte mask = 0; - size_t i; - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - { - if (mask == 0) - { - RINOK(SzReadByte(sd, &b)); - mask = 0x80; - } - (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte allAreDefined; - size_t i; - RINOK(SzReadByte(sd, &allAreDefined)); - if (allAreDefined == 0) - return SzReadBoolVector(sd, numItems, v, alloc); - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - (*v)[i] = 1; - return SZ_OK; -} - -static SRes SzReadHashDigests( - CSzData *sd, - size_t numItems, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *alloc) -{ - size_t i; - RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); - MY_ALLOC(UInt32, *digests, numItems, alloc); - for (i = 0; i < numItems; i++) - if ((*digestsDefined)[i]) - { - RINOK(SzReadUInt32(sd, (*digests) + i)); - } - return SZ_OK; -} - -static SRes SzReadPackInfo( - CSzData *sd, - UInt64 *dataOffset, - UInt32 *numPackStreams, - UInt64 **packSizes, - Byte **packCRCsDefined, - UInt32 **packCRCs, - ISzAlloc *alloc) -{ - UInt32 i; - RINOK(SzReadNumber(sd, dataOffset)); - RINOK(SzReadNumber32(sd, numPackStreams)); - - RINOK(SzWaitAttribute(sd, k7zIdSize)); - - MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); - - for (i = 0; i < *numPackStreams; i++) - { - RINOK(SzReadNumber(sd, (*packSizes) + i)); - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - if (type == k7zIdCRC) - { - RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); - continue; - } - RINOK(SzSkeepData(sd)); - } - if (*packCRCsDefined == 0) - { - MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); - MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); - for (i = 0; i < *numPackStreams; i++) - { - (*packCRCsDefined)[i] = 0; - (*packCRCs)[i] = 0; - } - } - return SZ_OK; -} - -static SRes SzReadSwitch(CSzData *sd) -{ - Byte external; - RINOK(SzReadByte(sd, &external)); - return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; -} - -static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) -{ - UInt32 numCoders, numBindPairs, numPackStreams, i; - UInt32 numInStreams = 0, numOutStreams = 0; - - RINOK(SzReadNumber32(sd, &numCoders)); - if (numCoders > NUM_FOLDER_CODERS_MAX) - return SZ_ERROR_UNSUPPORTED; - folder->NumCoders = numCoders; - - MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); - - for (i = 0; i < numCoders; i++) - SzCoderInfo_Init(folder->Coders + i); - - for (i = 0; i < numCoders; i++) - { - Byte mainByte; - CSzCoderInfo *coder = folder->Coders + i; - { - unsigned idSize, j; - Byte longID[15]; - RINOK(SzReadByte(sd, &mainByte)); - idSize = (unsigned)(mainByte & 0xF); - RINOK(SzReadBytes(sd, longID, idSize)); - if (idSize > sizeof(coder->MethodID)) - return SZ_ERROR_UNSUPPORTED; - coder->MethodID = 0; - for (j = 0; j < idSize; j++) - coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); - - if ((mainByte & 0x10) != 0) - { - RINOK(SzReadNumber32(sd, &coder->NumInStreams)); - RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); - if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || - coder->NumOutStreams > NUM_CODER_STREAMS_MAX) - return SZ_ERROR_UNSUPPORTED; - } - else - { - coder->NumInStreams = 1; - coder->NumOutStreams = 1; - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) - return SZ_ERROR_MEM; - RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); - } - } - while ((mainByte & 0x80) != 0) - { - RINOK(SzReadByte(sd, &mainByte)); - RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); - if ((mainByte & 0x10) != 0) - { - UInt32 n; - RINOK(SzReadNumber32(sd, &n)); - RINOK(SzReadNumber32(sd, &n)); - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - RINOK(SzSkeepDataSize(sd, propertiesSize)); - } - } - numInStreams += coder->NumInStreams; - numOutStreams += coder->NumOutStreams; - } - - if (numOutStreams == 0) - return SZ_ERROR_UNSUPPORTED; - - folder->NumBindPairs = numBindPairs = numOutStreams - 1; - MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); - - for (i = 0; i < numBindPairs; i++) - { - CSzBindPair *bp = folder->BindPairs + i; - RINOK(SzReadNumber32(sd, &bp->InIndex)); - RINOK(SzReadNumber32(sd, &bp->OutIndex)); - } - - if (numInStreams < numBindPairs) - return SZ_ERROR_UNSUPPORTED; - - folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; - MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams ; i++) - if (SzFolder_FindBindPairForInStream(folder, i) < 0) - break; - if (i == numInStreams) - return SZ_ERROR_UNSUPPORTED; - folder->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - RINOK(SzReadNumber32(sd, folder->PackStreams + i)); - } - return SZ_OK; -} - -static SRes SzReadUnpackInfo( - CSzData *sd, - UInt32 *numFolders, - CSzFolder **folders, /* for alloc */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - UInt32 i; - RINOK(SzWaitAttribute(sd, k7zIdFolder)); - RINOK(SzReadNumber32(sd, numFolders)); - { - RINOK(SzReadSwitch(sd)); - - MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); - - for (i = 0; i < *numFolders; i++) - SzFolder_Init((*folders) + i); - - for (i = 0; i < *numFolders; i++) - { - RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); - } - } - - RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); - - for (i = 0; i < *numFolders; i++) - { - UInt32 j; - CSzFolder *folder = (*folders) + i; - UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); - - MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); - - for (j = 0; j < numOutStreams; j++) - { - RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); - } - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - SRes res; - Byte *crcsDefined = 0; - UInt32 *crcs = 0; - res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < *numFolders; i++) - { - CSzFolder *folder = (*folders) + i; - folder->UnpackCRCDefined = crcsDefined[i]; - folder->UnpackCRC = crcs[i]; - } - } - IAlloc_Free(allocTemp, crcs); - IAlloc_Free(allocTemp, crcsDefined); - RINOK(res); - continue; - } - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadSubStreamsInfo( - CSzData *sd, - UInt32 numFolders, - CSzFolder *folders, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - UInt64 type = 0; - UInt32 i; - UInt32 si = 0; - UInt32 numDigests = 0; - - for (i = 0; i < numFolders; i++) - folders[i].NumUnpackStreams = 1; - *numUnpackStreams = numFolders; - - for (;;) - { - RINOK(SzReadID(sd, &type)); - if (type == k7zIdNumUnpackStream) - { - *numUnpackStreams = 0; - for (i = 0; i < numFolders; i++) - { - UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); - folders[i].NumUnpackStreams = numStreams; - *numUnpackStreams += numStreams; - } - continue; - } - if (type == k7zIdCRC || type == k7zIdSize) - break; - if (type == k7zIdEnd) - break; - RINOK(SzSkeepData(sd)); - } - - if (*numUnpackStreams == 0) - { - *unpackSizes = 0; - *digestsDefined = 0; - *digests = 0; - } - else - { - *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); - RINOM(*unpackSizes); - *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); - RINOM(*digestsDefined); - *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); - RINOM(*digests); - } - - for (i = 0; i < numFolders; i++) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: we check that folder is empty - */ - UInt64 sum = 0; - UInt32 j; - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams == 0) - continue; - if (type == k7zIdSize) - for (j = 1; j < numSubstreams; j++) - { - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - (*unpackSizes)[si++] = size; - sum += size; - } - (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; - } - if (type == k7zIdSize) - { - RINOK(SzReadID(sd, &type)); - } - - for (i = 0; i < *numUnpackStreams; i++) - { - (*digestsDefined)[i] = 0; - (*digests)[i] = 0; - } - - - for (i = 0; i < numFolders; i++) - { - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) - numDigests += numSubstreams; - } - - - si = 0; - for (;;) - { - if (type == k7zIdCRC) - { - int digestIndex = 0; - Byte *digestsDefined2 = 0; - UInt32 *digests2 = 0; - SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < numFolders; i++) - { - CSzFolder *folder = folders + i; - UInt32 numSubstreams = folder->NumUnpackStreams; - if (numSubstreams == 1 && folder->UnpackCRCDefined) - { - (*digestsDefined)[si] = 1; - (*digests)[si] = folder->UnpackCRC; - si++; - } - else - { - UInt32 j; - for (j = 0; j < numSubstreams; j++, digestIndex++) - { - (*digestsDefined)[si] = digestsDefined2[digestIndex]; - (*digests)[si] = digests2[digestIndex]; - si++; - } - } - } - } - IAlloc_Free(allocTemp, digestsDefined2); - IAlloc_Free(allocTemp, digests2); - RINOK(res); - } - else if (type == k7zIdEnd) - return SZ_OK; - else - { - RINOK(SzSkeepData(sd)); - } - RINOK(SzReadID(sd, &type)); - } -} - - -static SRes SzReadStreamsInfo( - CSzData *sd, - UInt64 *dataOffset, - CSzAr *p, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if ((UInt64)(int)type != type) - return SZ_ERROR_UNSUPPORTED; - switch((int)type) - { - case k7zIdEnd: - return SZ_OK; - case k7zIdPackInfo: - { - RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, - &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); - break; - } - case k7zIdUnpackInfo: - { - RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); - break; - } - case k7zIdSubStreamsInfo: - { - RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, - numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); - break; - } - default: - return SZ_ERROR_UNSUPPORTED; - } - } -} - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) -{ - size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; - if (dest != 0) - { - size_t i; - const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); - for (i = 0; i < len; i++) - dest[i] = GetUi16(src + i * 2); - } - return len; -} - -static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) -{ - UInt32 i; - size_t pos = 0; - for (i = 0; i < numFiles; i++) - { - sizes[i] = pos; - for (;;) - { - if (pos >= size) - return SZ_ERROR_ARCHIVE; - if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) - break; - pos++; - } - pos++; - } - sizes[i] = pos; - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; -} - -static SRes SzReadHeader2( - CSzArEx *p, /* allocMain */ - CSzData *sd, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - Byte **emptyStreamVector, /* allocTemp */ - Byte **emptyFileVector, /* allocTemp */ - Byte **lwtVector, /* allocTemp */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 type; - UInt32 numUnpackStreams = 0; - UInt32 numFiles = 0; - CSzFileItem *files = 0; - UInt32 numEmptyStreams = 0; - UInt32 i; - - RINOK(SzReadID(sd, &type)); - - if (type == k7zIdArchiveProperties) - { - RINOK(SzReadArchiveProperties(sd)); - RINOK(SzReadID(sd, &type)); - } - - - if (type == k7zIdMainStreamsInfo) - { - RINOK(SzReadStreamsInfo(sd, - &p->dataPos, - &p->db, - &numUnpackStreams, - unpackSizes, - digestsDefined, - digests, allocMain, allocTemp)); - p->dataPos += p->startPosAfterHeader; - RINOK(SzReadID(sd, &type)); - } - - if (type == k7zIdEnd) - return SZ_OK; - if (type != k7zIdFilesInfo) - return SZ_ERROR_ARCHIVE; - - RINOK(SzReadNumber32(sd, &numFiles)); - p->db.NumFiles = numFiles; - - MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); - - p->db.Files = files; - for (i = 0; i < numFiles; i++) - SzFile_Init(files + i); - - for (;;) - { - UInt64 type; - UInt64 size; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - RINOK(SzReadNumber(sd, &size)); - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - if ((UInt64)(int)type != type) - { - RINOK(SzSkeepDataSize(sd, size)); - } - else - switch((int)type) - { - case k7zIdName: - { - size_t namesSize; - RINOK(SzReadSwitch(sd)); - namesSize = (size_t)size - 1; - if ((namesSize & 1) != 0) - return SZ_ERROR_ARCHIVE; - if (!Buf_Create(&p->FileNames, namesSize, allocMain)) - return SZ_ERROR_MEM; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - memcpy(p->FileNames.data, sd->Data, namesSize); - RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) - RINOK(SzSkeepDataSize(sd, namesSize)); - break; - } - case k7zIdEmptyStream: - { - RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); - numEmptyStreams = 0; - for (i = 0; i < numFiles; i++) - if ((*emptyStreamVector)[i]) - numEmptyStreams++; - break; - } - case k7zIdEmptyFile: - { - RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); - break; - } - case k7zIdWinAttributes: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->AttribDefined = defined; - f->Attrib = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->Attrib)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - case k7zIdMTime: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->MTimeDefined = defined; - f->MTime.Low = f->MTime.High = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->MTime.Low)); - RINOK(SzReadUInt32(sd, &f->MTime.High)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - default: - { - RINOK(SzSkeepDataSize(sd, size)); - } - } - } - - { - UInt32 emptyFileIndex = 0; - UInt32 sizeIndex = 0; - for (i = 0; i < numFiles; i++) - { - CSzFileItem *file = files + i; - file->IsAnti = 0; - if (*emptyStreamVector == 0) - file->HasStream = 1; - else - file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); - if (file->HasStream) - { - file->IsDir = 0; - file->Size = (*unpackSizes)[sizeIndex]; - file->Crc = (*digests)[sizeIndex]; - file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; - sizeIndex++; - } - else - { - if (*emptyFileVector == 0) - file->IsDir = 1; - else - file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); - emptyFileIndex++; - file->Size = 0; - file->Crc = 0; - file->CrcDefined = 0; - } - } - } - return SzArEx_Fill(p, allocMain); -} - -static SRes SzReadHeader( - CSzArEx *p, - CSzData *sd, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - Byte *emptyStreamVector = 0; - Byte *emptyFileVector = 0; - Byte *lwtVector = 0; - SRes res = SzReadHeader2(p, sd, - &unpackSizes, &digestsDefined, &digests, - &emptyStreamVector, &emptyFileVector, &lwtVector, - allocMain, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - IAlloc_Free(allocTemp, emptyStreamVector); - IAlloc_Free(allocTemp, emptyFileVector); - IAlloc_Free(allocTemp, lwtVector); - return res; -} - -static SRes SzReadAndDecodePackedStreams2( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - CSzAr *p, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - - UInt32 numUnpackStreams = 0; - UInt64 dataStartPos; - CSzFolder *folder; - UInt64 unpackSize; - SRes res; - - RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, - &numUnpackStreams, unpackSizes, digestsDefined, digests, - allocTemp, allocTemp)); - - dataStartPos += baseOffset; - if (p->NumFolders != 1) - return SZ_ERROR_ARCHIVE; - - folder = p->Folders; - unpackSize = SzFolder_GetUnpackSize(folder); - - RINOK(LookInStream_SeekTo(inStream, dataStartPos)); - - if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) - return SZ_ERROR_MEM; - - res = SzFolder_Decode(folder, p->PackSizes, - inStream, dataStartPos, - outBuffer->data, (size_t)unpackSize, allocTemp); - RINOK(res); - if (folder->UnpackCRCDefined) - if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) - return SZ_ERROR_CRC; - return SZ_OK; -} - -static SRes SzReadAndDecodePackedStreams( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - ISzAlloc *allocTemp) -{ - CSzAr p; - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - SRes res; - SzAr_Init(&p); - res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, - &p, &unpackSizes, &digestsDefined, &digests, - allocTemp); - SzAr_Free(&p, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - return res; -} - -static SRes SzArEx_Open2( - CSzArEx *p, - ILookInStream *inStream, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - Byte header[k7zStartHeaderSize]; - Int64 startArcPos; - UInt64 nextHeaderOffset, nextHeaderSize; - size_t nextHeaderSizeT; - UInt32 nextHeaderCRC; - CBuf buffer; - SRes res; - - startArcPos = 0; - RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); - - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); - - if (!TestSignatureCandidate(header)) - return SZ_ERROR_NO_ARCHIVE; - if (header[6] != k7zMajorVersion) - return SZ_ERROR_UNSUPPORTED; - - nextHeaderOffset = GetUi64(header + 12); - nextHeaderSize = GetUi64(header + 20); - nextHeaderCRC = GetUi32(header + 28); - - p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; - - if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) - return SZ_ERROR_CRC; - - nextHeaderSizeT = (size_t)nextHeaderSize; - if (nextHeaderSizeT != nextHeaderSize) - return SZ_ERROR_MEM; - if (nextHeaderSizeT == 0) - return SZ_OK; - if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || - nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) - return SZ_ERROR_NO_ARCHIVE; - - { - Int64 pos = 0; - RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); - if ((UInt64)pos < startArcPos + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) - return SZ_ERROR_INPUT_EOF; - } - - RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); - - if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) - return SZ_ERROR_MEM; - - res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); - if (res == SZ_OK) - { - res = SZ_ERROR_ARCHIVE; - if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) - { - CSzData sd; - UInt64 type; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - if (res == SZ_OK) - { - if (type == k7zIdEncodedHeader) - { - CBuf outBuffer; - Buf_Init(&outBuffer); - res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); - if (res != SZ_OK) - Buf_Free(&outBuffer, allocTemp); - else - { - Buf_Free(&buffer, allocTemp); - buffer.data = outBuffer.data; - buffer.size = outBuffer.size; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - } - } - } - if (res == SZ_OK) - { - if (type == k7zIdHeader) - res = SzReadHeader(p, &sd, allocMain, allocTemp); - else - res = SZ_ERROR_UNSUPPORTED; - } - } - } - Buf_Free(&buffer, allocTemp); - return res; -} - -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) -{ - SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); - if (res != SZ_OK) - SzArEx_Free(p, allocMain); - return res; -} - -SRes SzArEx_Extract( - const CSzArEx *p, - ILookInStream *inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **outBuffer, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; - SRes res = SZ_OK; - *offset = 0; - *outSizeProcessed = 0; - if (folderIndex == (UInt32)-1) - { - IAlloc_Free(allocMain, *outBuffer); - *blockIndex = folderIndex; - *outBuffer = 0; - *outBufferSize = 0; - return SZ_OK; - } - - if (*outBuffer == 0 || *blockIndex != folderIndex) - { - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); - size_t unpackSize = (size_t)unpackSizeSpec; - UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); - - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - IAlloc_Free(allocMain, *outBuffer); - *outBuffer = 0; - - RINOK(LookInStream_SeekTo(inStream, startOffset)); - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*outBuffer == 0) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) - { - res = SzFolder_Decode(folder, - p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], - inStream, startOffset, - *outBuffer, unpackSize, allocTemp); - if (res == SZ_OK) - { - if (folder->UnpackCRCDefined) - { - if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) - res = SZ_ERROR_CRC; - } - } - } - } - } - if (res == SZ_OK) - { - UInt32 i; - CSzFileItem *fileItem = p->db.Files + fileIndex; - *offset = 0; - for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) - *offset += (UInt32)p->db.Files[i].Size; - *outSizeProcessed = (size_t)fileItem->Size; - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) - res = SZ_ERROR_CRC; - } - return res; -} diff --git a/lzma/C/7zStream.c b/lzma/C/7zStream.c index f0959fb07..5a92d532c 100644 --- a/lzma/C/7zStream.c +++ b/lzma/C/7zStream.c @@ -1,9 +1,11 @@ /* 7zStream.c -- 7z Stream functions -2010-03-11 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include -#include "Types.h" +#include "7zTypes.h" SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) { diff --git a/lzma/C/Types.h b/lzma/C/7zTypes.h similarity index 93% rename from lzma/C/Types.h rename to lzma/C/7zTypes.h index f193ce2f5..f39d10326 100644 --- a/lzma/C/Types.h +++ b/lzma/C/7zTypes.h @@ -1,15 +1,15 @@ -/* Types.h -- Basic types -2010-10-09 : Igor Pavlov : Public domain */ +/* 7zTypes.h -- Basic types +2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H -#include - #ifdef _WIN32 #include #endif +#include + #ifndef EXTERN_C_BEGIN #ifdef __cplusplus #define EXTERN_C_BEGIN extern "C" { @@ -44,6 +44,7 @@ typedef int SRes; #ifdef _WIN32 typedef DWORD WRes; +/* typedef unsigned WRes; */ #else typedef int WRes; #endif @@ -116,6 +117,7 @@ typedef int Bool; #else +#define MY_NO_INLINE #define MY_CDECL #define MY_FAST_CALL diff --git a/lzma/C/7zVersion.h b/lzma/C/7zVersion.h index 43f0fef6f..52ad3c1b1 100644 --- a/lzma/C/7zVersion.h +++ b/lzma/C/7zVersion.h @@ -1,8 +1,19 @@ -#define MY_VER_MAJOR 9 -#define MY_VER_MINOR 22 -#define MY_VER_BUILD 00 -#define MY_VERSION "9.22 beta" -#define MY_7ZIP_VERSION "9.22 beta" -#define MY_DATE "2011-04-18" -#define MY_COPYRIGHT ": Igor Pavlov : Public domain" -#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE +#define MY_VER_MAJOR 15 +#define MY_VER_MINOR 14 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "15.14" +#define MY_VERSION "15.14" +#define MY_DATE "2015-12-31" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2015 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE diff --git a/lzma/C/Bcj2.c b/lzma/C/Bcj2.c index 474bdd45d..707362a61 100644 --- a/lzma/C/Bcj2.c +++ b/lzma/C/Bcj2.c @@ -1,132 +1,256 @@ -/* Bcj2.c -- Converter for x86 code (BCJ2) -2008-10-04 : Igor Pavlov : Public domain */ +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2015-08-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "Bcj2.h" +#include "CpuArch.h" -#ifdef _LZMA_PROB32 -#define CProb UInt32 -#else #define CProb UInt16 -#endif -#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) -#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) #define kNumMoveBits 5 -#define RC_READ_BYTE (*buffer++) -#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } -#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ - { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} +#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) +#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); -#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } - -#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; - -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize) +void Bcj2Dec_Init(CBcj2Dec *p) { - CProb p[256 + 2]; - SizeT inPos = 0, outPos = 0; + unsigned i; - const Byte *buffer, *bufferLim; - UInt32 range, code; - Byte prevByte = 0; + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} - unsigned int i; - for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) - p[i] = kBitModelTotal >> 1; +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + if (p->range <= 5) + { + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; + + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } - buffer = buf3; - bufferLim = buffer + size3; - RC_INIT2 + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) + { + Byte *dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0]; + p->dest = dest + 1; + } + } - if (outSize == 0) - return SZ_OK; + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + + { + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; + } + } + */ for (;;) { - Byte b; - CProb *prob; - UInt32 bound; - UInt32 ttt; - - SizeT limit = size0 - inPos; - if (outSize - outPos < limit) - limit = outSize - outPos; - while (limit != 0) - { - Byte b = buf0[inPos]; - outBuf[outPos++] = b; - if (IsJ(prevByte, b)) - break; - inPos++; - prevByte = b; - limit--; - } - - if (limit == 0 || outPos == outSize) - break; - - b = buf0[inPos++]; - - if (b == 0xE8) - prob = p + prevByte; - else if (b == 0xE9) - prob = p + 256; - else - prob = p + 257; - - IF_BIT_0(prob) - { - UPDATE_0(prob) - prevByte = b; - } + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; else { - UInt32 dest; - const Byte *v; - UPDATE_1(prob) - if (b == 0xE8) + if (p->range < kTopValue) { - v = buf1; - if (size1 < 4) - return SZ_ERROR_DATA; - buf1 += 4; - size1 -= 4; + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; } - else + { - v = buf2; - if (size2 < 4) - return SZ_ERROR_DATA; - buf2 += 4; - size2 -= 4; + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; + + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } + + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb *prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + + } } - dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | - ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); - outBuf[outPos++] = (Byte)dest; - if (outPos == outSize) + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; break; - outBuf[outPos++] = (Byte)(dest >> 8); - if (outPos == outSize) + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; break; - outBuf[outPos++] = (Byte)(dest >> 16); - if (outPos == outSize) - break; - outBuf[outPos++] = prevByte = (Byte)(dest >> 24); + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; } } - return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; } diff --git a/lzma/C/Bcj2.h b/lzma/C/Bcj2.h index d9d857bc3..68893d2d1 100644 --- a/lzma/C/Bcj2.h +++ b/lzma/C/Bcj2.h @@ -1,38 +1,146 @@ -/* Bcj2.h -- Converter for x86 code (BCJ2) -2009-02-07 : Igor Pavlov : Public domain */ +/* Bcj2.h -- BCJ2 Converter for x86 code +2014-11-10 : Igor Pavlov : Public domain */ #ifndef __BCJ2_H #define __BCJ2_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN + +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; + +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK +}; + +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK +}; + + +#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) /* -Conditions: - outSize <= FullOutputSize, - where FullOutputSize is full size of output stream of x86_2 filter. - -If buf0 overlaps outBuf, there are two required conditions: - 1) (buf0 >= outBuf) - 2) (buf0 + size0 >= outBuf + FullOutputSize). - -Returns: - SZ_OK - SZ_ERROR_DATA - Data error +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 */ -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize); +/* +CBcj2Dec: +dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + tempReserv = 0 : for first call of Bcj2Dec_Decode + tempReserv = 4 : for any other calls of Bcj2Dec_Decode + overlap with offset = 1 is not allowed +*/ -#ifdef __cplusplus -} -#endif +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; +} CBcj2Dec; + +void Bcj2Dec_Init(CBcj2Dec *p); + +/* Returns: SZ_OK or SZ_ERROR_DATA */ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) + + + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte prevByte; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + UInt32 ip; + + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; + + unsigned flushPos; + + UInt16 probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); +void Bcj2Enc_Encode(CBcj2Enc *p); + +#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) +#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) + + +#define BCJ2_RELAT_LIMIT_NUM_BITS 26 +#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) + +/* limit for CBcj2Enc::fileSize variable */ +#define BCJ2_FileSize_MAX ((UInt32)1 << 31) + +EXTERN_C_END #endif diff --git a/lzma/C/Bra.c b/lzma/C/Bra.c index 2a0f147b2..976810c96 100644 --- a/lzma/C/Bra.c +++ b/lzma/C/Bra.c @@ -1,6 +1,8 @@ /* Bra.c -- Converters for RISC code 2010-04-16 : Igor Pavlov : Public domain */ +#include "Precomp.h" + #include "Bra.h" SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) diff --git a/lzma/C/Bra.h b/lzma/C/Bra.h index 9c91e332d..aba8dce14 100644 --- a/lzma/C/Bra.h +++ b/lzma/C/Bra.h @@ -1,14 +1,12 @@ /* Bra.h -- Branch converters for executables -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __BRA_H #define __BRA_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* These functions convert relative addresses to absolute addresses @@ -61,8 +59,6 @@ SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/Bra86.c b/lzma/C/Bra86.c index 93566cb21..8dd3ed48d 100644 --- a/lzma/C/Bra86.c +++ b/lzma/C/Bra86.c @@ -1,85 +1,82 @@ /* Bra86.c -- Converter for x86 code (BCJ) -2008-10-04 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "Bra.h" -#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) - -const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; -const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; +#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) { - SizeT bufferPos = 0, prevPosT; - UInt32 prevMask = *state & 0x7; + SizeT pos = 0; + UInt32 mask = *state & 7; if (size < 5) return 0; + size -= 4; ip += 5; - prevPosT = (SizeT)0 - 1; for (;;) { - Byte *p = data + bufferPos; - Byte *limit = data + size - 4; + Byte *p = data + pos; + const Byte *limit = data + size; for (; p < limit; p++) if ((*p & 0xFE) == 0xE8) break; - bufferPos = (SizeT)(p - data); - if (p >= limit) - break; - prevPosT = bufferPos - prevPosT; - if (prevPosT > 3) - prevMask = 0; - else + { - prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; - if (prevMask != 0) + SizeT d = (SizeT)(p - data - pos); + pos = (SizeT)(p - data); + if (p >= limit) { - Byte b = p[4 - kMaskToBitNumber[prevMask]]; - if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) + *state = (d > 2 ? 0 : mask >> (unsigned)d); + return pos; + } + if (d > 2) + mask = 0; + else + { + mask >>= (unsigned)d; + if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) { - prevPosT = bufferPos; - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; + mask = (mask >> 1) | 4; + pos++; continue; } } } - prevPosT = bufferPos; if (Test86MSByte(p[4])) { - UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); - UInt32 dest; - for (;;) + UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 cur = ip + (UInt32)pos; + pos += 5; + if (encoding) + v += cur; + else + v -= cur; + if (mask != 0) { - Byte b; - int index; - if (encoding) - dest = (ip + (UInt32)bufferPos) + src; - else - dest = src - (ip + (UInt32)bufferPos); - if (prevMask == 0) - break; - index = kMaskToBitNumber[prevMask] * 8; - b = (Byte)(dest >> (24 - index)); - if (!Test86MSByte(b)) - break; - src = dest ^ ((1 << (32 - index)) - 1); + unsigned sh = (mask & 6) << 2; + if (Test86MSByte((Byte)(v >> sh))) + { + v ^= (((UInt32)0x100 << sh) - 1); + if (encoding) + v += cur; + else + v -= cur; + } + mask = 0; } - p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); - p[3] = (Byte)(dest >> 16); - p[2] = (Byte)(dest >> 8); - p[1] = (Byte)dest; - bufferPos += 5; + p[1] = (Byte)v; + p[2] = (Byte)(v >> 8); + p[3] = (Byte)(v >> 16); + p[4] = (Byte)(0 - ((v >> 24) & 1)); } else { - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; + mask = (mask >> 1) | 4; + pos++; } } - prevPosT = bufferPos - prevPosT; - *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); - return bufferPos; } diff --git a/lzma/C/BraIA64.c b/lzma/C/BraIA64.c new file mode 100644 index 000000000..813830c79 --- /dev/null +++ b/lzma/C/BraIA64.c @@ -0,0 +1,69 @@ +/* BraIA64.c -- Converter for IA-64 code +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" + +static const Byte kBranchTable[32] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 +}; + +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 16) + return 0; + size -= 16; + for (i = 0; i <= size; i += 16) + { + UInt32 instrTemplate = data[i] & 0x1F; + UInt32 mask = kBranchTable[instrTemplate]; + UInt32 bitPos = 5; + int slot; + for (slot = 0; slot < 3; slot++, bitPos += 41) + { + UInt32 bytePos, bitRes; + UInt64 instruction, instNorm; + int j; + if (((mask >> slot) & 1) == 0) + continue; + bytePos = (bitPos >> 3); + bitRes = bitPos & 0x7; + instruction = 0; + for (j = 0; j < 6; j++) + instruction += (UInt64)data[i + j + bytePos] << (8 * j); + + instNorm = instruction >> bitRes; + if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) + { + UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); + UInt32 dest; + src |= ((UInt32)(instNorm >> 36) & 1) << 20; + + src <<= 4; + + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + + dest >>= 4; + + instNorm &= ~((UInt64)(0x8FFFFF) << 13); + instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); + instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); + + instruction &= (1 << bitRes) - 1; + instruction |= (instNorm << bitRes); + for (j = 0; j < 6; j++) + data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); + } + } + } + return i; +} diff --git a/lzma/C/Compiler.h b/lzma/C/Compiler.h new file mode 100644 index 000000000..de8fab374 --- /dev/null +++ b/lzma/C/Compiler.h @@ -0,0 +1,32 @@ +/* Compiler.h +2015-08-02 : Igor Pavlov : Public domain */ + +#ifndef __7Z_COMPILER_H +#define __7Z_COMPILER_H + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + + #if _MSC_VER >= 1300 + #pragma warning(disable : 4996) // This function or variable may be unsafe + #else + #pragma warning(disable : 4511) // copy constructor could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4710) // not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/lzma/C/CpuArch.c b/lzma/C/CpuArch.c index d6ab3f7f8..bcb84cb2b 100644 --- a/lzma/C/CpuArch.c +++ b/lzma/C/CpuArch.c @@ -1,5 +1,7 @@ /* CpuArch.c -- CPU specific code -2010-10-26: Igor Pavlov : Public domain */ +2015-03-25: Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "CpuArch.h" @@ -9,6 +11,10 @@ #define USE_ASM #endif +#if !defined(USE_ASM) && _MSC_VER >= 1500 +#include +#endif + #if defined(USE_ASM) && !defined(MY_CPU_AMD64) static UInt32 CheckFlag(UInt32 flag) { @@ -48,7 +54,7 @@ static UInt32 CheckFlag(UInt32 flag) #define CHECK_CPUID_IS_SUPPORTED #endif -static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) { #ifdef USE_ASM @@ -70,28 +76,20 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) *c = c2; *d = d2; - #elif defined __PIC__ && defined __i386__ - - /* GCC or Clang WITH position-independent code generation, i386 only */ - - __asm__ __volatile__ ( - "xchgl %%ebx, %1\n" - "cpuid\n" - "xchgl %%ebx, %1\n" - : "=a" (*a) , - "=r" (*b) , - "=c" (*c) , - "=d" (*d) - : "0" (function)) ; - #else - /* GCC or Clang WITHOUT position-independent code generation, or x86_64 */ - __asm__ __volatile__ ( + #if defined(MY_CPU_X86) && defined(__PIC__) + "mov %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=a" (*a) , + "=D" (*b) , + #else "cpuid" : "=a" (*a) , "=b" (*b) , + #endif "=c" (*c) , "=d" (*d) : "0" (function)) ; @@ -118,7 +116,7 @@ Bool x86cpuid_CheckAndRead(Cx86cpuid *p) return True; } -static UInt32 kVendors[][3] = +static const UInt32 kVendors[][3] = { { 0x756E6547, 0x49656E69, 0x6C65746E}, { 0x68747541, 0x69746E65, 0x444D4163}, @@ -146,12 +144,22 @@ Bool CPU_Is_InOrder() UInt32 family, model; if (!x86cpuid_CheckAndRead(&p)) return True; - family = x86cpuid_GetFamily(&p); - model = x86cpuid_GetModel(&p); + + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); + firm = x86cpuid_GetFirm(&p); + switch (firm) { - case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + ))); case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); } @@ -159,6 +167,7 @@ Bool CPU_Is_InOrder() } #if !defined(MY_CPU_AMD64) && defined(_WIN32) +#include static Bool CPU_Sys_Is_SSE_Supported() { OSVERSIONINFO vi; diff --git a/lzma/C/CpuArch.h b/lzma/C/CpuArch.h index 1cd7c29c5..b31c2546c 100644 --- a/lzma/C/CpuArch.h +++ b/lzma/C/CpuArch.h @@ -1,27 +1,34 @@ /* CpuArch.h -- CPU specific code -2010-12-01: Igor Pavlov : Public domain */ +2015-12-01: Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN /* MY_CPU_LE means that CPU is LITTLE ENDIAN. -If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. -If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. */ -#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) -#define MY_CPU_AMD64 +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 #endif -#if defined(MY_CPU_AMD64) || defined(_M_IA64) -#define MY_CPU_64BIT +#if defined(MY_CPU_AMD64) \ + || defined(_M_IA64) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) + #define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__) @@ -32,8 +39,13 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla #define MY_CPU_X86_OR_AMD64 #endif -#if defined(MY_CPU_X86) || defined(_M_ARM) -#define MY_CPU_32BIT +#if defined(MY_CPU_X86) \ + || defined(_M_ARM) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) + #define MY_CPU_32BIT #endif #if defined(_WIN32) && defined(_M_ARM) @@ -44,34 +56,63 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla #define MY_CPU_IA64_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) -#define MY_CPU_LE_UNALIGN +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) -#define MY_CPU_LE -#endif - -#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) -#define MY_CPU_BE +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE #endif #if defined(MY_CPU_LE) && defined(MY_CPU_BE) Stop_Compiling_Bad_Endian #endif + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + /* || defined(__AARCH64EL__) */ + #define MY_CPU_LE_UNALIGN + #endif +#endif + + #ifdef MY_CPU_LE_UNALIGN -#define GetUi16(p) (*(const UInt16 *)(p)) -#define GetUi32(p) (*(const UInt32 *)(p)) -#define GetUi64(p) (*(const UInt64 *)(p)) -#define SetUi16(p, d) *(UInt16 *)(p) = (d); -#define SetUi32(p, d) *(UInt32 *)(p) = (d); -#define SetUi64(p, d) *(UInt64 *)(p) = (d); +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) + +#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } +#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } #else -#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) #define GetUi32(p) ( \ ((const Byte *)(p))[0] | \ @@ -81,29 +122,43 @@ Stop_Compiling_Bad_Endian #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) -#define SetUi16(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } -#define SetUi32(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ - ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ - ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } -#define SetUi64(p, d) { UInt64 _x64_ = (d); \ - SetUi32(p, (UInt32)_x64_); \ - SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_); \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } #endif -#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) + +/* Note: we use bswap instruction, that is unsupported in 386 cpu */ + +#include #pragma intrinsic(_byteswap_ulong) #pragma intrinsic(_byteswap_uint64) #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) + +#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + +#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) + #else #define GetBe32(p) ( \ @@ -114,9 +169,19 @@ Stop_Compiling_Bad_Endian #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + #endif -#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) + +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) + #ifdef MY_CPU_X86_OR_AMD64 @@ -138,12 +203,14 @@ enum CPU_FIRM_VIA }; +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); + Bool x86cpuid_CheckAndRead(Cx86cpuid *p); int x86cpuid_GetFirm(const Cx86cpuid *p); -#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) -#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) -#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) +#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) +#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) +#define x86cpuid_GetStepping(ver) (ver & 0xF) Bool CPU_Is_InOrder(); Bool CPU_Is_Aes_Supported(); diff --git a/lzma/C/Delta.c b/lzma/C/Delta.c new file mode 100644 index 000000000..6cbbe4601 --- /dev/null +++ b/lzma/C/Delta.c @@ -0,0 +1,64 @@ +/* Delta.c -- Delta converter +2009-05-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + +static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +{ + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; +} + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} diff --git a/lzma/C/Delta.h b/lzma/C/Delta.h new file mode 100644 index 000000000..e59d5a252 --- /dev/null +++ b/lzma/C/Delta.h @@ -0,0 +1,19 @@ +/* Delta.h -- Delta converter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __DELTA_H +#define __DELTA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +EXTERN_C_END + +#endif diff --git a/lzma/C/LzFind.c b/lzma/C/LzFind.c index f6c9e66d5..c335d363c 100644 --- a/lzma/C/LzFind.c +++ b/lzma/C/LzFind.c @@ -1,5 +1,7 @@ /* LzFind.c -- Match finder for LZ algorithms -2009-04-22 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include @@ -9,8 +11,8 @@ #define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ -#define kNormalizeMask (~(kNormalizeStepMin - 1)) -#define kMaxHistorySize ((UInt32)3 << 30) +#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)7 << 29) #define kStartMaxLen 3 @@ -19,7 +21,7 @@ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) if (!p->directInput) { alloc->Free(alloc, p->bufferBase); - p->bufferBase = 0; + p->bufferBase = NULL; } } @@ -33,17 +35,16 @@ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *a p->blockSize = blockSize; return 1; } - if (p->bufferBase == 0 || p->blockSize != blockSize) + if (!p->bufferBase || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } - return (p->bufferBase != 0); + return (p->bufferBase != NULL); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } -Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } @@ -58,9 +59,12 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; + + /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + if (p->directInput) { - UInt32 curSize = 0xFFFFFFFF - p->streamPos; + UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize; @@ -69,12 +73,14 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) p->streamEndWasReached = 1; return; } + for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; + p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return; @@ -92,8 +98,8 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, - p->buffer - p->keepSizeBefore, - (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); p->buffer = p->bufferBase + p->keepSizeBefore; } @@ -133,15 +139,15 @@ static void MatchFinder_SetDefaultSettings(CMatchFinder *p) void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; - p->bufferBase = 0; + p->bufferBase = NULL; p->directInput = 0; - p->hash = 0; + p->hash = NULL; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; - int j; + unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r; @@ -151,7 +157,7 @@ void MatchFinder_Construct(CMatchFinder *p) static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); - p->hash = 0; + p->hash = NULL; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) @@ -160,11 +166,11 @@ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) LzInWindow_Free(p, alloc); } -static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +static CLzRef* AllocRefs(size_t num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) - return 0; + return NULL; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); } @@ -173,19 +179,24 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ISzAlloc *alloc) { UInt32 sizeReserv; + if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } + sizeReserv = historySize >> 1; - if (historySize > ((UInt32)2 << 30)) - sizeReserv = historySize >> 2; + if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; + else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1; @@ -210,6 +221,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, hs = (1 << 24) - 1; else hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ } } p->hashMask = hs; @@ -221,24 +233,32 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, } { - UInt32 prevSize = p->hashSizeSum + p->numSons; - UInt32 newSize; + size_t newSize; + size_t numSons; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; - p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); - newSize = p->hashSizeSum + p->numSons; - if (p->hash != 0 && prevSize == newSize) + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hs + numSons; + + if (p->hash && p->numRefs == newSize) return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; p->hash = AllocRefs(newSize, alloc); - if (p->hash != 0) + + if (p->hash) { p->son = p->hash + p->hashSizeSum; return 1; } } } + MatchFinder_Free(p, alloc); return 0; } @@ -247,9 +267,11 @@ static void MatchFinder_SetLimits(CMatchFinder *p) { UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) { if (limit2 > 0) @@ -257,8 +279,10 @@ static void MatchFinder_SetLimits(CMatchFinder *p) } else limit2 -= p->keepSizeAfter; + if (limit2 < limit) limit = limit2; + { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen) @@ -268,28 +292,39 @@ static void MatchFinder_SetLimits(CMatchFinder *p) p->posLimit = p->pos + limit; } -void MatchFinder_Init(CMatchFinder *p) +void MatchFinder_Init_2(CMatchFinder *p, int readData) { UInt32 i; - for (i = 0; i < p->hashSizeSum; i++) - p->hash[i] = kEmptyHashValue; + UInt32 *hash = p->hash; + UInt32 num = p->hashSizeSum; + for (i = 0; i < num; i++) + hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; - MatchFinder_ReadBlock(p); + + if (readData) + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); } +void MatchFinder_Init(CMatchFinder *p) +{ + MatchFinder_Init_2(p, True); +} + static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) { - UInt32 i; + size_t i; for (i = 0; i < numItems; i++) { UInt32 value = items[i]; @@ -304,7 +339,7 @@ void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); - MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_Normalize3(subValue, p->hash, p->numRefs); MatchFinder_ReduceOffsets(p, subValue); } @@ -465,7 +500,7 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ - UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + UInt32 lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; @@ -481,13 +516,20 @@ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +#define UPDATE_maxLen { \ + ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (UInt32)(c - cur); } + static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) } @@ -497,35 +539,38 @@ UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, delta2, maxLen, offset; + UInt32 h2, d2, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(3) HASH3_CALC; - delta2 = p->pos - p->hash[hash2Value]; - curMatch = p->hash[kFix3HashSize + hashValue]; - - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; + hash = p->hash; + pos = p->pos; + d2 = pos - hash[h2]; + + curMatch = hash[kFix3HashSize + hv]; + + hash[h2] = pos; + hash[kFix3HashSize + hv] = pos; maxLen = 2; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[0] = maxLen; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; if (maxLen == lenLimit) { @@ -533,44 +578,51 @@ static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; - - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + pos = p->pos; - maxLen = 1; + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; + + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) { @@ -578,46 +630,131 @@ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) } +/* +static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + GET_MATCHES_FOOTER(offset, maxLen) +} +*/ + static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; - maxLen = 1; + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) { @@ -625,22 +762,103 @@ static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances + offset, maxLen) - (distances)); + distances + offset, maxLen) - (distances)); MOVE_POS_RET } +/* +static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} +*/ + UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances, 2) - (distances)); + distances, 2) - (distances)); MOVE_POS_RET } @@ -650,8 +868,8 @@ static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { SKIP_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -663,8 +881,8 @@ void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -674,12 +892,14 @@ static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value; + UInt32 h2; + UInt32 *hash; SKIP_HEADER(3) HASH3_CALC; - curMatch = p->hash[kFix3HashSize + hashValue]; - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix3HashSize + hv]; + hash[h2] = + hash[kFix3HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -689,43 +909,90 @@ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = p->pos; - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0); } +/* +static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} +*/ + static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } +/* +static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = p->hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} +*/ + void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } @@ -735,13 +1002,22 @@ void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { - vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; - vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + /* if (p->numHashBytes <= 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; + } + */ } else if (p->numHashBytes == 2) { @@ -753,9 +1029,16 @@ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } - else + else /* if (p->numHashBytes == 4) */ { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; + } + */ } diff --git a/lzma/C/LzFind.h b/lzma/C/LzFind.h index 7ebdfa446..2ff667377 100644 --- a/lzma/C/LzFind.h +++ b/lzma/C/LzFind.h @@ -1,14 +1,12 @@ /* LzFind.h -- Match finder for LZ algorithms -2009-04-22 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN typedef UInt32 CLzRef; @@ -23,6 +21,11 @@ typedef struct _CMatchFinder UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; + UInt32 matchMaxLen; CLzRef *hash; CLzRef *son; @@ -31,30 +34,30 @@ typedef struct _CMatchFinder Byte *bufferBase; ISeqInStream *stream; - int streamEndWasReached; - + UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; - int directInput; size_t directInputRem; - int btMode; - int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; - UInt32 numSons; SRes result; UInt32 crc[256]; + size_t numRefs; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) -#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) + int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p); @@ -70,7 +73,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, @@ -84,7 +87,6 @@ Conditions: */ typedef void (*Mf_Init_Func)(void *object); -typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); @@ -93,7 +95,6 @@ typedef void (*Mf_Skip_Func)(void *object, UInt32); typedef struct _IMatchFinder { Mf_Init_Func Init; - Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; @@ -102,14 +103,15 @@ typedef struct _IMatchFinder void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); +void MatchFinder_Init_2(CMatchFinder *p, int readData); void MatchFinder_Init(CMatchFinder *p); + UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzFindMt.c b/lzma/C/LzFindMt.c index db95590c3..cb61e0953 100644 --- a/lzma/C/LzFindMt.c +++ b/lzma/C/LzFindMt.c @@ -1,11 +1,13 @@ /* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2009-09-20 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "LzHash.h" #include "LzFindMt.h" -void MtSync_Construct(CMtSync *p) +static void MtSync_Construct(CMtSync *p) { p->wasCreated = False; p->csWasInitialized = False; @@ -18,7 +20,7 @@ void MtSync_Construct(CMtSync *p) Semaphore_Construct(&p->filledSemaphore); } -void MtSync_GetNextBlock(CMtSync *p) +static void MtSync_GetNextBlock(CMtSync *p) { if (p->needStart) { @@ -46,7 +48,7 @@ void MtSync_GetNextBlock(CMtSync *p) /* MtSync_StopWriting must be called if Writing was started */ -void MtSync_StopWriting(CMtSync *p) +static void MtSync_StopWriting(CMtSync *p) { UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart) @@ -69,7 +71,7 @@ void MtSync_StopWriting(CMtSync *p) p->needStart = True; } -void MtSync_Destruct(CMtSync *p) +static void MtSync_Destruct(CMtSync *p) { if (Thread_WasCreated(&p->thread)) { @@ -97,7 +99,7 @@ void MtSync_Destruct(CMtSync *p) #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } -static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { if (p->wasCreated) return SZ_OK; @@ -119,7 +121,7 @@ static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void return SZ_OK; } -static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); if (res != SZ_OK) @@ -132,20 +134,20 @@ void MtSync_Init(CMtSync *p) { p->needStart = True; } #define kMtMaxValForNormalize 0xFFFFFFFF #define DEF_GetHeads2(name, v, action) \ -static void GetHeads ## name(const Byte *p, UInt32 pos, \ -UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ -{ action; for (; numHeads != 0; numHeads--) { \ -const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ + { action; for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) -DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ -void HashThreadFunc(CMatchFinderMt *mt) +static void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; for (;;) @@ -171,12 +173,12 @@ void HashThreadFunc(CMatchFinderMt *mt) CriticalSection_Enter(&mt->btSync.cs); CriticalSection_Enter(&mt->hashSync.cs); { - const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); - const Byte *afterPtr; + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; MatchFinder_MoveBlock(mf); - afterPtr = MatchFinder_GetPointerToCurrentPos(mf); - mt->pointerToCurPos -= beforePtr - afterPtr; - mt->buffer -= beforePtr - afterPtr; + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; } CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs); @@ -190,7 +192,7 @@ void HashThreadFunc(CMatchFinderMt *mt) { UInt32 subValue = (mf->pos - mf->historySize - 1); MatchFinder_ReduceOffsets(mf, subValue); - MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); } { UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; @@ -215,7 +217,7 @@ void HashThreadFunc(CMatchFinderMt *mt) } } -void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) { MtSync_GetNextBlock(&p->hashSync); p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; @@ -231,7 +233,7 @@ void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) #define NO_INLINE MY_FAST_CALL -Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, +static Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) { @@ -308,12 +310,14 @@ Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CL #endif -void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 numProcessed = 0; UInt32 curPos = 2; UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + distances[1] = p->hashNumAvail; + while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit) @@ -322,9 +326,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) distances[1] = numProcessed + p->hashNumAvail; if (p->hashNumAvail >= p->numHashBytes) continue; + distances[0] = curPos + p->hashNumAvail; + distances += curPos; for (; p->hashNumAvail != 0; p->hashNumAvail--) - distances[curPos++] = 0; - break; + *distances++ = 0; + return; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos; @@ -341,13 +347,14 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) if (size2 < size) size = size2; } + #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { UInt32 *startDistances = distances + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], - pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - startDistances + 1, p->numHashBytes - 1) - startDistances); + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); *startDistances = num - 1; curPos += num; cyclicBufferPos++; @@ -358,7 +365,7 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 posRes; curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos), size, &posRes); p->hashBufPos += posRes - pos; cyclicBufferPos += posRes - pos; p->buffer += posRes - pos; @@ -374,10 +381,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) p->cyclicBufferPos = cyclicBufferPos; } } + distances[0] = curPos; } -void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; if (!sync->needStart) @@ -391,7 +399,7 @@ void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) { UInt32 subValue = p->pos - p->cyclicBufferSize; - MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); p->pos -= subValue; } @@ -430,15 +438,15 @@ void BtThreadFunc(CMatchFinderMt *mt) void MatchFinderMt_Construct(CMatchFinderMt *p) { - p->hashBuf = 0; + p->hashBuf = NULL; MtSync_Construct(&p->hashSync); MtSync_Construct(&p->btSync); } -void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hashBuf); - p->hashBuf = 0; + p->hashBuf = NULL; } void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) @@ -451,14 +459,15 @@ void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) -static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } -static unsigned MY_STD_CALL BtThreadFunc2(void *p) +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; - int i = 0; + unsigned i = 0; for (i = 0; i < 16; i++) - allocaDummy[i] = (Byte)i; - BtThreadFunc((CMatchFinderMt *)p); + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); return 0; } @@ -469,10 +478,10 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; - if (p->hashBuf == 0) + if (!p->hashBuf) { p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); - if (p->hashBuf == 0) + if (!p->hashBuf) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; } @@ -492,8 +501,11 @@ void MatchFinderMt_Init(CMatchFinderMt *p) CMatchFinder *mf = p->MatchFinder; p->btBufPos = p->btBufPosLimit = 0; p->hashBufPos = p->hashBufPosLimit = 0; - MatchFinder_Init(mf); - p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_2(mf, False); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; p->lzPos = p->historySize + 1; @@ -518,13 +530,13 @@ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) /* p->MatchFinder->ReleaseStream(); */ } -void MatchFinderMt_Normalize(CMatchFinderMt *p) +static void MatchFinderMt_Normalize(CMatchFinderMt *p) { MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); p->lzPos = p->historySize + 1; } -void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { UInt32 blockIndex; MtSync_GetNextBlock(&p->btSync); @@ -536,34 +548,29 @@ void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) MatchFinderMt_Normalize(p); } -const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); -UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { GET_NEXT_BLOCK_IF_REQUIRED; return p->btNumAvailBytes; } -Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - return p->pointerToCurPos[index]; -} - -UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) -{ - UInt32 hash2Value, curMatch2; + UInt32 h2, curMatch2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH2_CALC - curMatch2 = hash[hash2Value]; - hash[hash2Value] = lzPos; + curMatch2 = hash[h2]; + hash[h2] = lzPos; if (curMatch2 >= matchMinPos) if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) @@ -571,23 +578,23 @@ UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) *distances++ = 2; *distances++ = lzPos - curMatch2 - 1; } + return distances; } -UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, curMatch2, curMatch3; + UInt32 h2, h3, curMatch2, curMatch3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH3_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { @@ -600,43 +607,45 @@ UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { *distances++ = 3; *distances++ = lzPos - curMatch3 - 1; } + return distances; } /* -UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; + UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH4_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; - curMatch4 = hash[kFix4HashSize + hash4Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; + curMatch4 = hash[kFix4HashSize + h4]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - hash[kFix4HashSize + hash4Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; + hash[kFix4HashSize + h4] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { - distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; return distances + 2; } distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch3 - 1; @@ -658,13 +667,14 @@ UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) *distances++ = 4; *distances++ = lzPos - curMatch4 - 1; } + return distances; } */ #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; -UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; @@ -682,7 +692,7 @@ UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) return len; } -UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; @@ -690,6 +700,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) if (len == 0) { + /* change for bt5 ! */ if (p->btNumAvailBytes-- >= 4) len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); } @@ -705,7 +716,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) *distances2++ = *btBuf++; } while ((len -= 2) != 0); - len = (UInt32)(distances2 - (distances)); + len = (UInt32)(distances2 - (distances)); } INCREASE_LZ_POS return len; @@ -715,41 +726,41 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); -void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER2_MT { p->btNumAvailBytes--; SKIP_FOOTER_MT } -void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(2) - UInt32 hash2Value; + UInt32 h2; MT_HASH2_CALC - hash[hash2Value] = p->lzPos; + hash[h2] = p->lzPos; SKIP_FOOTER_MT } -void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(3) - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; MT_HASH3_CALC - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT } /* -void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) - UInt32 hash2Value, hash3Value, hash4Value; + UInt32 h2, h3, h4; MT_HASH4_CALC - hash[kFix4HashSize + hash4Value] = - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix4HashSize + h4] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT } @@ -758,11 +769,11 @@ void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; - switch(p->MatchFinder->numHashBytes) + + switch (p->MatchFinder->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2; @@ -778,7 +789,6 @@ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) default: /* case 4: */ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; - /* p->GetHeadsFunc = GetHeads4; */ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break; diff --git a/lzma/C/LzFindMt.h b/lzma/C/LzFindMt.h index 17ed237d6..46b6924ad 100644 --- a/lzma/C/LzFindMt.h +++ b/lzma/C/LzFindMt.h @@ -1,5 +1,5 @@ /* LzFindMt.h -- multithreaded Match finder for LZ algorithms -2009-02-07 : Igor Pavlov : Public domain */ +2015-05-03 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_MT_H #define __LZ_FIND_MT_H @@ -7,9 +7,7 @@ #include "LzFind.h" #include "Threads.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN #define kMtHashBlockSize (1 << 13) #define kMtHashNumBlocks (1 << 3) @@ -77,7 +75,7 @@ typedef struct _CMatchFinderMt UInt32 matchMaxLen; UInt32 numHashBytes; UInt32 pos; - Byte *buffer; + const Byte *buffer; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be historySize + 1 */ UInt32 cutValue; @@ -98,8 +96,6 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzHash.h b/lzma/C/LzHash.h index b2f0e3c24..219144407 100644 --- a/lzma/C/LzHash.h +++ b/lzma/C/LzHash.h @@ -1,5 +1,5 @@ /* LzHash.h -- HASH functions for LZ algorithms -2009-02-07 : Igor Pavlov : Public domain */ +2015-04-12 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H @@ -12,43 +12,46 @@ #define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) -#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); +#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ - hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ - hash4Value &= (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << 5); \ + h4 = temp & (kHash4Size - 1); \ + hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } -/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ -#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; +/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ - hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif diff --git a/lzma/C/Lzma2Dec.c b/lzma/C/Lzma2Dec.c index 7c4eb4449..b6884571c 100644 --- a/lzma/C/Lzma2Dec.c +++ b/lzma/C/Lzma2Dec.c @@ -1,8 +1,10 @@ /* Lzma2Dec.c -- LZMA2 Decoder -2010-12-15 : Igor Pavlov : Public domain */ +2015-11-09 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */ +#include "Precomp.h" + #ifdef SHOW_DEBUG_INFO #include #endif @@ -97,12 +99,12 @@ void Lzma2Dec_Init(CLzma2Dec *p) static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { - switch(p->state) + switch (p->state) { case LZMA2_STATE_CONTROL: p->control = b; - PRF(printf("\n %4X ", p->decoder.dicPos)); - PRF(printf(" %2X", b)); + PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos)); + PRF(printf(" %2X", (unsigned)b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) @@ -122,7 +124,7 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; - PRF(printf(" %8d", p->unpackSize)); + PRF(printf(" %8u", (unsigned)p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: @@ -132,13 +134,13 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; - PRF(printf(" %8d", p->packSize)); + PRF(printf(" %8u", (unsigned)p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { - int lc, lp; + unsigned lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; @@ -177,13 +179,16 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; + if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) @@ -193,8 +198,15 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); + + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } continue; } + { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen; @@ -220,7 +232,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); } @@ -229,7 +244,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, srcSizeCur = destSizeCur; if (srcSizeCur == 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); @@ -245,17 +263,21 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (p->state == LZMA2_STATE_DATA) { - int mode = LZMA2_GET_LZMA_MODE(p); + unsigned mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); - Bool initState = (mode > 0); + Bool initState = (mode != 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } + if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize; @@ -274,16 +296,22 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (srcSizeCur == 0 && outSizeProcessed == 0) { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || - p->unpackSize != 0 || p->packSize != 0) + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->state = LZMA2_STATE_CONTROL; } + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } + *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; } diff --git a/lzma/C/Lzma2Dec.h b/lzma/C/Lzma2Dec.h index 827698dee..026cdefe9 100644 --- a/lzma/C/Lzma2Dec.h +++ b/lzma/C/Lzma2Dec.h @@ -1,14 +1,12 @@ /* Lzma2Dec.h -- LZMA2 Decoder -2009-05-03 : Igor Pavlov : Public domain */ +2015-05-13 : Igor Pavlov : Public domain */ #ifndef __LZMA2_DEC_H #define __LZMA2_DEC_H #include "LzmaDec.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* ---------- State Interface ---------- */ @@ -17,7 +15,7 @@ typedef struct CLzmaDec decoder; UInt32 packSize; UInt32 unpackSize; - int state; + unsigned state; Byte control; Bool needInitDic; Bool needInitState; @@ -77,8 +75,6 @@ Returns: SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzmaDec.c b/lzma/C/LzmaDec.c index 72451d1ff..651d1f284 100644 --- a/lzma/C/LzmaDec.c +++ b/lzma/C/LzmaDec.c @@ -1,5 +1,7 @@ /* LzmaDec.c -- LZMA Decoder -2010-12-15 : Igor Pavlov : Public domain */ +2015-06-23 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "LzmaDec.h" @@ -44,6 +46,13 @@ i -= 0x40; } #endif +#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) +#define MATCHED_LITER_DEC \ + matchByte <<= 1; \ + bit = (matchByte & offs); \ + probLit = prob + offs + bit + symbol; \ + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) @@ -105,14 +114,14 @@ #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) +#define LZMA_LIT_SIZE 0x300 #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif +#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. @@ -124,8 +133,8 @@ Out: p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : Flush marker - = kMatchSpecLenStart + 2 : State Init Marker + = kMatchSpecLenStart + 1 : Flush marker (unused now) + = kMatchSpecLenStart + 2 : State Init Marker (unused now) */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) @@ -163,38 +172,62 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte unsigned symbol; UPDATE_0(prob); prob = probs + Literal; - if (checkDicSize != 0 || processedPos != 0) - prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + if (processedPos != 0 || checkDicSize != 0) + prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + processedPos++; if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; - do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + #ifdef _LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif } else { - unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; + #ifdef _LZMA_SIZE_OPT do { unsigned bit; CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + MATCHED_LITER_DEC } while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif } + dic[dicPos++] = (Byte)symbol; - processedPos++; continue; } - else + { UPDATE_1(prob); prob = probs + IsRep + state; @@ -217,7 +250,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte IF_BIT_0(prob) { UPDATE_0(prob); - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; @@ -258,6 +291,8 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } + + #ifdef _LZMA_SIZE_OPT { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; @@ -290,6 +325,42 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte TREE_DECODE(probLen, limit, len); len += offset; } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols + kLenNumMidSymbols; + } + } + } + #endif if (state >= kNumStates) { @@ -300,7 +371,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; - int numDirectBits = (int)(((distance >> 1) - 1)); + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { @@ -359,6 +430,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte } } } + rep3 = rep2; rep2 = rep1; rep1 = rep0; @@ -366,26 +438,39 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte if (checkDicSize == 0) { if (distance >= processedPos) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } } else if (distance >= checkDicSize) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; - if (limit == dicPos) - return SZ_ERROR_DATA; { - SizeT rem = limit - dicPos; - unsigned curLen = ((rem < len) ? (unsigned)rem : len); - SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); processedPos += curLen; len -= curLen; - if (pos + curLen <= dicBufSize) + if (curLen <= dicBufSize - pos) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; @@ -409,7 +494,9 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte } } while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; p->range = range; p->code = code; @@ -433,9 +520,10 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; - UInt32 rep0 = p->reps[0]; - if (limit - dicPos < len) - len = (unsigned)(limit - dicPos); + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; @@ -445,7 +533,7 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) while (len != 0) { len--; - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; @@ -463,17 +551,19 @@ static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - if (p->processedPos >= p->prop.dicSize) + + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) - { p->remainLen = kMatchSpecLenStart; - } + return 0; } @@ -490,12 +580,12 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; - CLzmaProb *probs = p->probs; + const CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { - CLzmaProb *prob; + const CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); @@ -509,9 +599,9 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) - prob += (LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { @@ -521,13 +611,13 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; - CLzmaProb *probLit; + const CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; @@ -597,7 +687,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS } { unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; + const CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; @@ -637,7 +727,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { - int numDirectBits = ((posSlot >> 1) - 1); + unsigned numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ @@ -676,13 +766,6 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS } -static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -{ - p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; -} - void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; @@ -707,8 +790,8 @@ void LzmaDec_Init(CLzmaDec *p) static void LzmaDec_InitStateReal(CLzmaDec *p) { - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); - UInt32 i; + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; @@ -730,7 +813,7 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr { int checkEndMarkNow; - if (p->needFlush != 0) + if (p->needFlush) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; @@ -741,8 +824,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; - - LzmaDec_InitRc(p, p->tempBuf); + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; p->tempBufSize = 0; } @@ -826,7 +914,16 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; - lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; @@ -881,13 +978,13 @@ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *sr void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); - p->probs = 0; + p->probs = NULL; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); - p->dic = 0; + p->dic = NULL; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) @@ -925,12 +1022,12 @@ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (p->probs == 0 || numProbs != p->numProbs) + if (!p->probs || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; - if (p->probs == 0) + if (!p->probs) return SZ_ERROR_MEM; } return SZ_OK; @@ -951,12 +1048,22 @@ SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAll SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (p->dic == 0) + if (!p->dic) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; diff --git a/lzma/C/LzmaDec.h b/lzma/C/LzmaDec.h index 6741a644b..2633abeac 100644 --- a/lzma/C/LzmaDec.h +++ b/lzma/C/LzmaDec.h @@ -1,14 +1,12 @@ /* LzmaDec.h -- LZMA Decoder -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, @@ -224,8 +222,6 @@ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzmaEnc.c b/lzma/C/LzmaEnc.c index 870399d35..11de42c09 100644 --- a/lzma/C/LzmaEnc.c +++ b/lzma/C/LzmaEnc.c @@ -1,5 +1,7 @@ /* LzmaEnc.c -- LZMA Encoder -2011-01-27 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include @@ -18,9 +20,12 @@ #endif #ifdef SHOW_STAT -static int ttt = 0; +static unsigned g_STAT_OFFSET = 0; #endif +#define kMaxHistorySize ((UInt32)3 << 29) +/* #define kMaxHistorySize ((UInt32)7 << 29) */ + #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) #define kBlockSize (9 << 10) @@ -46,7 +51,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) { p->level = 5; p->dictSize = p->mc = 0; - p->reduceSize = (UInt32)(Int32)-1; + p->reduceSize = (UInt64)(Int64)-1; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; p->writeEndMark = 0; } @@ -56,24 +61,28 @@ void LzmaEncProps_Normalize(CLzmaEncProps *p) int level = p->level; if (level < 0) level = 5; p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->dictSize > p->reduceSize) { unsigned i; - for (i = 15; i <= 30; i++) + for (i = 11; i <= 30; i++) { - if (p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } - if (p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } + if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } + if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } } } + if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; - if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST @@ -90,17 +99,18 @@ UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) return props.dictSize; } +#if (_MSC_VER >= 1400) +/* BSR code is fast for some new CPUs */ /* #define LZMA_LOG_BSR */ -/* Define it for Intel's CPU */ - +#endif #ifdef LZMA_LOG_BSR -#define kDicLogSizeMaxCompress 30 +#define kDicLogSizeMaxCompress 32 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } -UInt32 GetPosSlot1(UInt32 pos) +static UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res); @@ -111,27 +121,44 @@ UInt32 GetPosSlot1(UInt32 pos) #else -#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kNumLogBits (9 + sizeof(size_t) / 2) +/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) -void LzmaEnc_FastPosInit(Byte *g_FastPos) +static void LzmaEnc_FastPosInit(Byte *g_FastPos) { - int c = 2, slotFast; + unsigned slot; g_FastPos[0] = 0; g_FastPos[1] = 1; + g_FastPos += 2; - for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + for (slot = 2; slot < kNumLogBits * 2; slot++) { - UInt32 k = (1 << ((slotFast >> 1) - 1)); - UInt32 j; - for (j = 0; j < k; j++, c++) - g_FastPos[c] = (Byte)slotFast; + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; } } +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +#define BSR2_RET(pos, res) { UInt32 i = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> i] + (i * 2); } + /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \ @@ -211,6 +238,7 @@ typedef struct #define kNumStates 12 + typedef struct { CLzmaProb choice; @@ -220,14 +248,16 @@ typedef struct CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; + typedef struct { CLenEnc p; - UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; + typedef struct { UInt32 range; @@ -242,10 +272,14 @@ typedef struct SRes res; } CRangeEnc; + typedef struct { CLzmaProb *litProbs; + UInt32 state; + UInt32 reps[LZMA_NUM_REPS]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; @@ -259,15 +293,49 @@ typedef struct CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; } CSaveState; + typedef struct { - IMatchFinder matchFinder; void *matchFinderObj; + IMatchFinder matchFinder; + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + unsigned lclp; + + CLzmaProb *litProbs; + + Bool fastMode; + Bool writeEndMark; + Bool finished; + Bool multiThread; + Bool needInit; + + UInt64 nowPos64; + + UInt32 matchPriceCount; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + UInt32 dictSize; + SRes result; + + CRangeEnc rc; #ifndef _7ZIP_ST Bool mtMode; @@ -280,12 +348,6 @@ typedef struct Byte pad[128]; #endif - UInt32 optimumEndIndex; - UInt32 optimumCurrentIndex; - - UInt32 longestMatchLength; - UInt32 numPairs; - UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR @@ -294,22 +356,10 @@ typedef struct UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; - UInt32 numFastBytes; - UInt32 additionalOffset; - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; - UInt32 alignPriceCount; - - UInt32 distTableSize; - - unsigned lc, lp, pb; - unsigned lpMask, pbMask; - - CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; @@ -325,26 +375,14 @@ typedef struct CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - unsigned lclp; - - Bool fastMode; - - CRangeEnc rc; - - Bool writeEndMark; - UInt64 nowPos64; - UInt32 matchPriceCount; - Bool finished; - Bool multiThread; - - SRes result; - UInt32 dictSize; - - int needInit; - CSaveState saveState; + + #ifndef _7ZIP_ST + Byte pad2[128]; + #endif } CLzmaEnc; + void LzmaEnc_SaveState(CLzmaEncHandle pp) { CLzmaEnc *p = (CLzmaEnc *)pp; @@ -368,7 +406,7 @@ void LzmaEnc_SaveState(CLzmaEncHandle pp) memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp) @@ -394,7 +432,7 @@ void LzmaEnc_RestoreState(CLzmaEncHandle pp) memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) @@ -403,9 +441,13 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); - if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || - props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30)) + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX + || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) + || props.dictSize > kMaxHistorySize) return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; { unsigned fb = props.fb; @@ -419,7 +461,7 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); - p->matchFinderBase.btMode = props.btMode; + p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); { UInt32 numHashBytes = 4; if (props.btMode) @@ -463,8 +505,8 @@ static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, static void RangeEnc_Construct(CRangeEnc *p) { - p->outStream = 0; - p->bufBase = 0; + p->outStream = NULL; + p->bufBase = NULL; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) @@ -472,10 +514,10 @@ static void RangeEnc_Construct(CRangeEnc *p) #define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { - if (p->bufBase == 0) + if (!p->bufBase) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); - if (p->bufBase == 0) + if (!p->bufBase) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; } @@ -516,7 +558,7 @@ static void RangeEnc_FlushStream(CRangeEnc *p) static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) { - if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0) { Byte temp = p->cache; do @@ -542,7 +584,7 @@ static void RangeEnc_FlushData(CRangeEnc *p) RangeEnc_ShiftLow(p); } -static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits) { do { @@ -605,7 +647,7 @@ static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, while (symbol < 0x10000); } -void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) @@ -641,7 +683,7 @@ void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] -static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100; @@ -654,7 +696,7 @@ static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *Pro return price; } -static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100; @@ -698,7 +740,7 @@ static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLeve } } -static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels); @@ -710,7 +752,7 @@ static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 s return price; } -static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1; @@ -761,7 +803,7 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posSt } } -static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, const UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice); @@ -784,20 +826,20 @@ static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UIn prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } -static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, const UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } -static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, const UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } -static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, const UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice) @@ -811,9 +853,10 @@ static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 static void MovePos(CLzmaEnc *p, UInt32 num) { #ifdef SHOW_STAT - ttt += num; - printf("\n MovePos %d", num); + g_STAT_OFFSET += num; + printf("\n MovePos %u", num); #endif + if (num != 0) { p->additionalOffset += num; @@ -826,28 +869,32 @@ static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) UInt32 lenRes = 0, numPairs; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT - printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); - ttt++; + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); + g_STAT_OFFSET++; { UInt32 i; for (i = 0; i < numPairs; i += 2) - printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); } #endif + if (numPairs > 0) { lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { - const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { - const Byte *pby2 = pby - distance; - for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + const Byte *pbyCur = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *pby = pbyCur + lenRes; + ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[numPairs - 1]; + const Byte *pbyLim = pbyCur + numAvail; + for (; pby != pbyLim && *pby == pby[dif]; pby++); + lenRes = (UInt32)(pby - pbyCur); } } } @@ -932,7 +979,7 @@ static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) return p->optimumCurrentIndex; } -#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * (UInt32)0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { @@ -976,7 +1023,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; - data2 = data - (reps[i] + 1); + data2 = data - reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; @@ -1120,12 +1167,12 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) cur = 0; #ifdef SHOW_STAT2 - if (position >= 0) + /* if (position >= 0) */ { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) - printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); } #endif @@ -1277,7 +1324,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) /* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; - const Byte *data2 = data - (reps[0] + 1); + const Byte *data2 = data - reps[0] - 1; UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; @@ -1320,7 +1367,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; - const Byte *data2 = data - (reps[repIndex] + 1); + const Byte *data2 = data - reps[repIndex] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); @@ -1350,13 +1397,13 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = @@ -1437,16 +1484,16 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ - const Byte *data2 = data - (curBack + 1); + const Byte *data2 = data - curBack - 1; UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice + @@ -1520,7 +1567,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++); @@ -1589,7 +1636,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1; @@ -1685,6 +1732,7 @@ void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase; @@ -1701,15 +1749,15 @@ void LzmaEnc_Construct(CLzmaEnc *p) #endif LzmaEnc_InitPriceTables(p->ProbPrices); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); - if (p != 0) + if (p) LzmaEnc_Construct((CLzmaEnc *)p); return p; } @@ -1718,8 +1766,8 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) @@ -1727,6 +1775,7 @@ void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) #ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); @@ -1763,7 +1812,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; - curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++; @@ -1780,7 +1829,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 - printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + printf("\n pos = %4X, len = %u pos = %u", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask; @@ -1889,7 +1938,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } - else if (processed >= (1 << 15)) + else if (processed >= (1 << 17)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p); @@ -1905,22 +1954,21 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; - Bool btMode; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; - btMode = (p->matchFinderBase.btMode != 0); + #ifndef _7ZIP_ST - p->mtMode = (p->multiThread && !p->fastMode && btMode); + p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); #endif { unsigned lclp = p->lc + p->lp; - if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); - p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - if (p->litProbs == 0 || p->saveState.litProbs == 0) + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + if (!p->litProbs || !p->saveState.litProbs) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM; @@ -1929,7 +1977,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I } } - p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize; @@ -1949,6 +1997,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } + return SZ_OK; } @@ -1977,9 +2026,10 @@ void LzmaEnc_Init(CLzmaEnc *p) } { - UInt32 num = 0x300 << (p->lp + p->lc); + UInt32 num = (UInt32)0x300 << (p->lp + p->lc); + CLzmaProb *probs = p->litProbs; for (i = 0; i < num; i++) - p->litProbs[i] = kProbInitValue; + probs[i] = kProbInitValue; } { @@ -2086,10 +2136,11 @@ void LzmaEnc_Finish(CLzmaEncHandle pp) if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else - (void)pp; + UNUSED_VAR(pp); #endif } + typedef struct { ISeqOutStream funcTable; @@ -2119,12 +2170,14 @@ UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } + const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } + SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { @@ -2159,23 +2212,23 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, return res; } + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK; #ifndef _7ZIP_ST Byte allocaDummy[0x300]; - int i = 0; - for (i = 0; i < 16; i++) - allocaDummy[i] = (Byte)i; + allocaDummy[0] = 0; + allocaDummy[1] = allocaDummy[0]; #endif for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); - if (res != SZ_OK || p->finished != 0) + if (res != SZ_OK || p->finished) break; - if (progress != 0) + if (progress) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK) @@ -2185,10 +2238,19 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) } } } + LzmaEnc_Finish(p); + + /* + if (res == S_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + res = SZ_ERROR_FAIL; + } + */ + return res; } + SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { @@ -2196,28 +2258,27 @@ SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *i return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; - int i; + unsigned i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); - for (i = 11; i <= 30; i++) + if (dictSize >= ((UInt32)1 << 22)) { - if (dictSize <= ((UInt32)2 << i)) - { - dictSize = (2 << i); - break; - } - if (dictSize <= ((UInt32)3 << i)) - { - dictSize = (3 << i); - break; - } + UInt32 kDictMask = ((UInt32)1 << 20) - 1; + if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) + dictSize = (dictSize + kDictMask) & ~kDictMask; + } + else for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } + if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) @@ -2225,6 +2286,7 @@ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) return SZ_OK; } + SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { @@ -2233,19 +2295,22 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte CSeqOutStreamBuf outStream; - LzmaEnc_SetInputBuf(p, src, srcLen); - outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; - p->rc.outStream = &outStream.funcTable; + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + { res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } *destLen -= outStream.rem; if (outStream.overflow) @@ -2253,13 +2318,14 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte return res; } + SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; - if (p == 0) + if (!p) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props); diff --git a/lzma/C/LzmaEnc.h b/lzma/C/LzmaEnc.h index 7573ba01b..c2806b45f 100644 --- a/lzma/C/LzmaEnc.h +++ b/lzma/C/LzmaEnc.h @@ -1,10 +1,10 @@ /* LzmaEnc.h -- LZMA Encoder -2011-01-27 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_ENC_H #define __LZMA_ENC_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN @@ -16,7 +16,7 @@ typedef struct _CLzmaEncProps UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version (1 << 12) <= dictSize <= (1 << 30) for 64-bit version default = (1 << 24) */ - UInt32 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. + UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. Encoder uses this value to reduce dictionary size */ int lc; /* 0 <= lc <= 8, default = 3 */ int lp; /* 0 <= lp <= 4, default = 0 */ diff --git a/lzma/C/Ppmd.h b/lzma/C/Ppmd.h new file mode 100644 index 000000000..25ce2d28f --- /dev/null +++ b/lzma/C/Ppmd.h @@ -0,0 +1,85 @@ +/* Ppmd.h -- PPMD codec common code +2013-01-18 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +#pragma pack(push, 1) +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +#pragma pack(pop) + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ + p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/lzma/C/Ppmd7.c b/lzma/C/Ppmd7.c new file mode 100644 index 000000000..735651f5d --- /dev/null +++ b/lzma/C/Ppmd7.c @@ -0,0 +1,710 @@ +/* Ppmd7.c -- PPMdH codec +2015-09-28 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + )) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/lzma/C/Ppmd7.h b/lzma/C/Ppmd7.h new file mode 100644 index 000000000..56e81eb12 --- /dev/null +++ b/lzma/C/Ppmd7.h @@ -0,0 +1,140 @@ +/* Ppmd7.h -- PPMdH compression codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct +{ + UInt32 (*GetThreshold)(void *p, UInt32 total); + void (*Decode)(void *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void *p, UInt32 size0); +} IPpmd7_RangeDec; + +typedef struct +{ + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/lzma/C/Ppmd7Dec.c b/lzma/C/Ppmd7Dec.c new file mode 100644 index 000000000..3d01d7644 --- /dev/null +++ b/lzma/C/Ppmd7Dec.c @@ -0,0 +1,189 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (p->Stream->Read((void *)p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 Range_GetThreshold(void *pp, UInt32 total) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + return (p->Code) / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode; + p->p.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/lzma/C/Precomp.h b/lzma/C/Precomp.h new file mode 100644 index 000000000..edb581443 --- /dev/null +++ b/lzma/C/Precomp.h @@ -0,0 +1,10 @@ +/* Precomp.h -- StdAfx +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "Compiler.h" +/* #include "7zTypes.h" */ + +#endif diff --git a/lzma/C/Threads.c b/lzma/C/Threads.c index 4be44fb0f..ece07e618 100644 --- a/lzma/C/Threads.c +++ b/lzma/C/Threads.c @@ -1,7 +1,9 @@ /* Threads.c -- multithreading library -2009-09-20 : Igor Pavlov : Public domain */ +2014-09-21 : Igor Pavlov : Public domain */ -#ifndef _WIN32_WCE +#include "Precomp.h" + +#ifndef UNDER_CE #include #endif @@ -29,14 +31,21 @@ WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE) WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { - unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - *p = - #ifdef UNDER_CE - CreateThread(0, 0, func, param, 0, &threadId); - #else - (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); - #endif - /* maybe we must use errno here, but probably GetLastError() is also OK. */ + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + + #ifdef UNDER_CE + + DWORD threadId; + *p = CreateThread(0, 0, func, param, 0, &threadId); + + #else + + unsigned threadId; + *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + + #endif + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ return HandleToWRes(*p); } diff --git a/lzma/C/Threads.h b/lzma/C/Threads.h index 6a7afa829..e927208d7 100644 --- a/lzma/C/Threads.h +++ b/lzma/C/Threads.h @@ -1,15 +1,17 @@ /* Threads.h -- multithreading library -2009-03-27 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_THREADS_H #define __7Z_THREADS_H -#include "Types.h" - -#ifdef __cplusplus -extern "C" { +#ifdef _WIN32 +#include #endif +#include "7zTypes.h" + +EXTERN_C_BEGIN + WRes HandlePtr_Close(HANDLE *h); WRes Handle_WaitObject(HANDLE h); @@ -18,7 +20,15 @@ typedef HANDLE CThread; #define Thread_WasCreated(p) (*(p) != NULL) #define Thread_Close(p) HandlePtr_Close(p) #define Thread_Wait(p) Handle_WaitObject(*(p)) -typedef unsigned THREAD_FUNC_RET_TYPE; + +typedef +#ifdef UNDER_CE + DWORD +#else + unsigned +#endif + THREAD_FUNC_RET_TYPE; + #define THREAD_FUNC_CALL_TYPE MY_STD_CALL #define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); @@ -52,8 +62,6 @@ WRes CriticalSection_Init(CCriticalSection *p); #define CriticalSection_Enter(p) EnterCriticalSection(p) #define CriticalSection_Leave(p) LeaveCriticalSection(p) -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/CMakeLists.txt b/lzma/CMakeLists.txt index 7cd330cc8..9c9de9152 100644 --- a/lzma/CMakeLists.txt +++ b/lzma/CMakeLists.txt @@ -6,21 +6,27 @@ if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" ) endif( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_PPMD_SUPPPORT" ) + set( LZMA_FILES + C/7zArcIn.c C/7zBuf.c C/7zCrc.c C/7zCrcOpt.c C/7zDec.c - C/7zIn.c C/7zStream.c C/Bcj2.c C/Bra.c C/Bra86.c + C/BraIA64.c C/CpuArch.c + C/Delta.c C/LzFind.c C/Lzma2Dec.c C/LzmaDec.c - C/LzmaEnc.c ) + C/LzmaEnc.c + C/Ppmd7.c + C/Ppmd7Dec.c ) if( WIN32 ) set( LZMA_FILES ${LZMA_FILES} C/LzFindMt.c C/Threads.c ) diff --git a/lzma/history.txt b/lzma/history.txt index 36d01d7d9..6abb8248c 100644 --- a/lzma/history.txt +++ b/lzma/history.txt @@ -1,6 +1,62 @@ HISTORY of the LZMA SDK ----------------------- +15.12 2015-11-19 +------------------------- +- The BUG in C version of 7z decoder was fixed: + 7zDec.c : SzDecodeLzma2() + 7z decoder could mistakenly report about decoding error for some 7z archives + that use LZMA2 compression method. + The probability to get that mistaken decoding error report was about + one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). +- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed: + 7zArcIn.c : SzReadHeader2() + 7z decoder worked incorrectly for 7z archives that contain + empty solid blocks, that can be placed to 7z archive, if some file is + unavailable for reading during archive creation. + + +15.09 beta 2015-10-16 +------------------------- +- The BUG in LZMA / LZMA2 encoding code was fixed. + The BUG in LzFind.c::MatchFinder_ReadBlock() function. + If input data size is larger than (4 GiB - dictionary_size), + the following code worked incorrectly: + - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions + for compressing from memory to memory. + That BUG is not related to LZMA encoder version that works via streams. + - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if + default value of chunk size (CLzma2EncProps::blockSize) is changed + to value larger than (4 GiB - dictionary_size). + + +9.38 beta 2015-01-03 +------------------------- +- The BUG in 9.31-9.37 was fixed: + IArchiveGetRawProps interface was disabled for 7z archives. +- The BUG in 9.26-9.36 was fixed: + Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows. + + +9.36 beta 2014-12-26 +------------------------- +- The BUG in command line version was fixed: + 7-Zip created temporary archive in current folder during update archive + operation, if -w{Path} switch was not specified. + The fixed 7-Zip creates temporary archive in folder that contains updated archive. +- The BUG in 9.33-9.35 was fixed: + 7-Zip silently ignored file reading errors during 7z or gz archive creation, + and the created archive contained only part of file that was read before error. + The fixed 7-Zip stops archive creation and it reports about error. + + +9.35 beta 2014-12-07 +------------------------- +- 7zr.exe now support AES encryption. +- SFX mudules were added to LZMA SDK +- Some bugs were fixed. + + 9.21 beta 2011-04-11 ------------------------- - New class FString for file names at file systems. diff --git a/lzma/lzma.txt b/lzma/lzma.txt index 9d3cef003..4e74e8b5b 100644 --- a/lzma/lzma.txt +++ b/lzma/lzma.txt @@ -1,18 +1,27 @@ -LZMA SDK 9.22 -------------- +LZMA SDK 15.13 +-------------- -LZMA SDK provides the documentation, samples, header files, libraries, -and tools you need to develop applications that use LZMA compression. - -LZMA is default and general compression method of 7z format -in 7-Zip compression program (www.7-zip.org). LZMA provides high -compression ratio and very fast decompression. +LZMA SDK provides the documentation, samples, header files, +libraries, and tools you need to develop applications that +use 7z / LZMA / LZMA2 / XZ compression. LZMA is an improved version of famous LZ77 compression algorithm. It was improved in way of maximum increasing of compression ratio, keeping high decompression speed and low memory requirements for decompressing. +LZMA2 is a LZMA based compression method. LZMA2 provides better +multithreading support for compression than LZMA and some other improvements. + +7z is a file format for data compression and file archiving. +7z is a main file format for 7-Zip compression program (www.7-zip.org). +7z format supports different compression methods: LZMA, LZMA2 and others. +7z also supports AES-256 based encryption. + +XZ is a file format for data compression that uses LZMA2 compression. +XZ format provides additional features: SHA/CRC check, filters for +improved compression ratio, splitting to blocks and streams, + LICENSE @@ -24,8 +33,9 @@ Some code in LZMA SDK is based on public domain code from another developers: 1) PPMd var.H (2001): Dmitry Shkarin 2) SHA-256: Wei Dai (Crypto++ library) -You can copy, modify, distribute and perform LZMA SDK code, even for commercial purposes, -all without asking permission. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute the +original LZMA SDK code, either in source code form or as a compiled binary, for +any purpose, commercial or non-commercial, and by any means. LZMA SDK code is compatible with open source licenses, for example, you can include it to GNU GPL or GNU LGPL code. @@ -34,10 +44,20 @@ include it to GNU GPL or GNU LGPL code. LZMA SDK Contents ----------------- -LZMA SDK includes: + Source code: - - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing - - Compiled file->file LZMA compressing/decompressing program for Windows system + - C / C++ / C# / Java - LZMA compression and decompression + - C / C++ - LZMA2 compression and decompression + - C / C++ - XZ compression and decompression + - C - 7z decompression + - C++ - 7z compression and decompression + - C - small SFXs for installers (7z decompression) + - C++ - SFXs and SFXs for installers (7z decompression) + + Precomiled binaries: + + - console programs for lzma / 7z / xz compression and decompression + - SFX modules for installers. UNIX/Linux version @@ -51,70 +71,94 @@ In some UNIX/Linux versions you must compile LZMA with static libraries. To compile with static libraries, you can use LIB = -lm -static +Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux): + + http://p7zip.sourceforge.net/ + Files ---------------------- -lzma.txt - LZMA SDK description (this file) -7zFormat.txt - 7z Format description -7zC.txt - 7z ANSI-C Decoder description -methods.txt - Compression method IDs for .7z -lzma.exe - Compiled file->file LZMA encoder/decoder for Windows -7zr.exe - 7-Zip with 7z/lzma/xz support. -history.txt - history of the LZMA SDK +----- + +DOC/7zC.txt - 7z ANSI-C Decoder description +DOC/7zFormat.txt - 7z Format description +DOC/installer.txt - information about 7-Zip for installers +DOC/lzma.txt - LZMA compression description +DOC/lzma-sdk.txt - LZMA SDK description (this file) +DOC/lzma-history.txt - history of LZMA SDK +DOC/lzma-specification.txt - Specification of LZMA +DOC/Methods.txt - Compression method IDs for .7z + +bin/installer/ - example script to create installer that uses SFX module, + +bin/7zdec.exe - simplified 7z archive decoder +bin/7zr.exe - 7-Zip console program (reduced version) +bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version) +bin/lzma.exe - file->file LZMA encoder/decoder for Windows +bin/7zS2.sfx - small SFX module for installers (GUI version) +bin/7zS2con.sfx - small SFX module for installers (Console version) +bin/7zSD.sfx - SFX module for installers. + + +7zDec.exe +--------- +7zDec.exe is simplified 7z archive decoder. +It supports only LZMA, LZMA2, and PPMd methods. +7zDec decodes whole solid block from 7z archive to RAM. +The RAM consumption can be high. + + Source code structure --------------------- -C/ - C files - 7zCrc*.* - CRC code - Alloc.* - Memory allocation functions - Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code - LzFind.* - Match finder for LZ (LZMA) encoders - LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding - LzHash.h - Additional file for LZ match finder - LzmaDec.* - LZMA decoding - LzmaEnc.* - LZMA encoding - LzmaLib.* - LZMA Library for DLL calling - Types.h - Basic types for another .c files - Threads.* - The code for multithreading. - LzmaLib - LZMA Library (.DLL for Windows) - - LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder). +Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption) - Archive - files related to archiving - 7z - 7z ANSI-C Decoder +C/ - C files (compression / decompression and other) + Util/ + 7z - 7z decoder program (decoding 7z files) + Lzma - LZMA program (file->file LZMA encoder/decoder). + LzmaLib - LZMA library (.DLL for Windows) + SfxSetup - small SFX module for installers CPP/ -- CPP files Common - common files for C++ projects Windows - common files for Windows related code - 7zip - files related to 7-Zip Project - - Common - common files for 7-Zip - - Compress - files related to compression/decompression + 7zip - files related to 7-Zip Archive - files related to archiving Common - common files for archive handling 7z - 7z C++ Encoder/Decoder - Bundles - Modules that are bundles of other modules + Bundles - Modules that are bundles of other modules (files) - Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 - LzmaCon - lzma.exe: LZMA compression/decompression - Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 - Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. + Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version) + Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2. + Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2 + LzmaCon - lzma.exe: LZMA compression/decompression + LzmaSpec - example code for LZMA Specification + SFXCon - 7zCon.sfx: Console 7z SFX module + SFXSetup - 7zS.sfx: 7z SFX module for installers + SFXWin - 7z.sfx: GUI 7z SFX module - UI - User Interface files + Common - common files for 7-Zip + + Compress - files for compression/decompression + + Crypto - files for encryption / decompression + + UI - User Interface files - Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll + Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll Common - Common UI files - Console - Code for console archiver - + Console - Code for console program (7z.exe) + Explorer - Some code from 7-Zip Shell extension + FileManager - Some GUI code from 7-Zip File Manager + GUI - Some GUI code from 7-Zip CS/ - C# files @@ -134,8 +178,9 @@ Java/ - Java files RangeCoder - Range Coder (special code of compression/decompression) -C/C++ source code of LZMA SDK is part of 7-Zip project. -7-Zip source code can be downloaded from 7-Zip's SourceForge page: +Note: + Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code. + 7-Zip's source code can be downloaded from 7-Zip's SourceForge page: http://sourceforge.net/projects/sevenzip/ @@ -146,8 +191,8 @@ LZMA features - Variable dictionary size (up to 1 GB) - Estimated compressing speed: about 2 MB/s on 2 GHz CPU - Estimated decompressing speed: - - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64 - - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC + - 20-30 MB/s on modern 2 GHz cpu + - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC) - Small memory requirements for decompressing (16 KB + DictionarySize) - Small code size for decompressing: 5-8 KB @@ -156,7 +201,7 @@ implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). Some critical operations that affect the speed of LZMA decompression: 1) 32*16 bit integer multiply - 2) Misspredicted branches (penalty mostly depends from pipeline length) + 2) Mispredicted branches (penalty mostly depends from pipeline length) 3) 32-bit shift and arithmetic operations The speed of LZMA decompressing mostly depends from CPU speed. @@ -304,298 +349,6 @@ compressible. For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. -LZMA compressed file format ---------------------------- -Offset Size Description - 0 1 Special LZMA properties (lc,lp, pb in encoded form) - 1 4 Dictionary size (little endian) - 5 8 Uncompressed size (little endian). -1 means unknown size - 13 Compressed data - - -ANSI-C LZMA Decoder -~~~~~~~~~~~~~~~~~~~ - -Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. -If you want to use old interfaces you can download previous version of LZMA SDK -from sourceforge.net site. - -To use ANSI-C LZMA Decoder you need the following files: -1) LzmaDec.h + LzmaDec.c + Types.h -LzmaUtil/LzmaUtil.c is example application that uses these files. - - -Memory requirements for LZMA decoding -------------------------------------- - -Stack usage of LZMA decoding function for local variables is not -larger than 200-400 bytes. - -LZMA Decoder uses dictionary buffer and internal state structure. -Internal state structure consumes - state_size = (4 + (1.5 << (lc + lp))) KB -by default (lc=3, lp=0), state_size = 16 KB. - - -How To decompress data ----------------------- - -LZMA Decoder (ANSI-C version) now supports 2 interfaces: -1) Single-call Decompressing -2) Multi-call State Decompressing (zlib-like interface) - -You must use external allocator: -Example: -void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } -void SzFree(void *p, void *address) { p = p; free(address); } -ISzAlloc alloc = { SzAlloc, SzFree }; - -You can use p = p; operator to disable compiler warnings. - - -Single-call Decompressing -------------------------- -When to use: RAM->RAM decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h -Compile defines: no defines -Memory Requirements: - - Input buffer: compressed size - - Output buffer: uncompressed size - - LZMA Internal Structures: state_size (16 KB for default settings) - -Interface: - int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - In: - dest - output data - destLen - output data size - src - input data - srcLen - input data size - propData - LZMA properties (5 bytes) - propSize - size of propData buffer (5 bytes) - finishMode - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - You can use LZMA_FINISH_END, when you know that - current output buffer covers last bytes of stream. - alloc - Memory allocator. - - Out: - destLen - processed output size - srcLen - processed input size - - Output: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - - If LZMA decoder sees end_marker before reaching output limit, it returns OK result, - and output value of destLen will be less than output buffer size limit. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - - -Multi-call State Decompressing (zlib-like interface) ----------------------------------------------------- - -When to use: file->file decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h - -Memory Requirements: - - Buffer for input stream: any size (for example, 16 KB) - - Buffer for output stream: any size (for example, 16 KB) - - LZMA Internal Structures: state_size (16 KB for default settings) - - LZMA dictionary (dictionary size is encoded in LZMA properties header) - -1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: - unsigned char header[LZMA_PROPS_SIZE + 8]; - ReadFile(inFile, header, sizeof(header) - -2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties - - CLzmaDec state; - LzmaDec_Constr(&state); - res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); - if (res != SZ_OK) - return res; - -3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop - - LzmaDec_Init(&state); - for (;;) - { - ... - int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); - ... - } - - -4) Free all allocated structures - LzmaDec_Free(&state, &g_Alloc); - -For full code example, look at C/LzmaUtil/LzmaUtil.c code. - - -How To compress data --------------------- - -Compile files: LzmaEnc.h + LzmaEnc.c + Types.h + -LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h - -Memory Requirements: - - (dictSize * 11.5 + 6 MB) + state_size - -Lzma Encoder can use two memory allocators: -1) alloc - for small arrays. -2) allocBig - for big arrays. - -For example, you can use Large RAM Pages (2 MB) in allocBig allocator for -better compression speed. Note that Windows has bad implementation for -Large RAM Pages. -It's OK to use same allocator for alloc and allocBig. - - -Single-call Compression with callbacks --------------------------------------- - -Check C/LzmaUtil/LzmaUtil.c as example, - -When to use: file->file decompressing - -1) you must implement callback structures for interfaces: -ISeqInStream -ISeqOutStream -ICompressProgress -ISzAlloc - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - - CFileSeqInStream inStream; - CFileSeqOutStream outStream; - - inStream.funcTable.Read = MyRead; - inStream.file = inFile; - outStream.funcTable.Write = MyWrite; - outStream.file = outFile; - - -2) Create CLzmaEncHandle object; - - CLzmaEncHandle enc; - - enc = LzmaEnc_Create(&g_Alloc); - if (enc == 0) - return SZ_ERROR_MEM; - - -3) initialize CLzmaEncProps properties; - - LzmaEncProps_Init(&props); - - Then you can change some properties in that structure. - -4) Send LZMA properties to LZMA Encoder - - res = LzmaEnc_SetProps(enc, &props); - -5) Write encoded properties to header - - Byte header[LZMA_PROPS_SIZE + 8]; - size_t headerSize = LZMA_PROPS_SIZE; - UInt64 fileSize; - int i; - - res = LzmaEnc_WriteProperties(enc, header, &headerSize); - fileSize = MyGetFileLength(inFile); - for (i = 0; i < 8; i++) - header[headerSize++] = (Byte)(fileSize >> (8 * i)); - MyWriteFileAndCheck(outFile, header, headerSize) - -6) Call encoding function: - res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, - NULL, &g_Alloc, &g_Alloc); - -7) Destroy LZMA Encoder Object - LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); - - -If callback function return some error code, LzmaEnc_Encode also returns that code -or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. - - -Single-call RAM->RAM Compression --------------------------------- - -Single-call RAM->RAM Compression is similar to Compression with callbacks, -but you provide pointers to buffers instead of pointers to stream callbacks: - -HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); - -Return code: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) - - - -Defines -------- - -_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. - -_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for - some structures will be doubled in that case. - -_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. - -_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. - - -_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder. - - -C++ LZMA Encoder/Decoder -~~~~~~~~~~~~~~~~~~~~~~~~ -C++ LZMA code use COM-like interfaces. So if you want to use it, -you can study basics of COM/OLE. -C++ LZMA code is just wrapper over ANSI-C code. - - -C++ Notes -~~~~~~~~~~~~~~~~~~~~~~~~ -If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling), -you must check that you correctly work with "new" operator. -7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. -So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator: -operator new(size_t size) -{ - void *p = ::malloc(size); - if (p == 0) - throw CNewException(); - return p; -} -If you use MSCV that throws exception for "new" operator, you can compile without -"NewHandler.cpp". So standard exception will be used. Actually some code of -7-Zip catches any exception in internal code and converts it to HRESULT code. -So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. --- diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 1fb553932..65676fcf4 100644 --- a/src/resourcefiles/file_7z.cpp +++ b/src/resourcefiles/file_7z.cpp @@ -252,25 +252,26 @@ bool F7ZFile::Open(bool quiet) } return false; } - NumLumps = Archive->DB.db.NumFiles; + CSzArEx* const archPtr = &Archive->DB; + + NumLumps = archPtr->NumFiles; Lumps = new F7ZLump[NumLumps]; F7ZLump *lump_p = Lumps; TArray nameUTF16; TArray nameASCII; + for (DWORD i = 0; i < NumLumps; ++i) { - CSzFileItem *file = &Archive->DB.db.Files[i]; - // skip Directories - if (file->IsDir) + if (SzArEx_IsDir(archPtr, i)) { skipped++; continue; } - const size_t nameLength = SzArEx_GetFileNameUtf16(&Archive->DB, i, NULL); + const size_t nameLength = SzArEx_GetFileNameUtf16(archPtr, i, NULL); if (0 == nameLength) { @@ -280,7 +281,7 @@ bool F7ZFile::Open(bool quiet) nameUTF16.Resize((unsigned)nameLength); nameASCII.Resize((unsigned)nameLength); - SzArEx_GetFileNameUtf16(&Archive->DB, i, &nameUTF16[0]); + SzArEx_GetFileNameUtf16(archPtr, i, &nameUTF16[0]); for (size_t c = 0; c < nameLength; ++c) { nameASCII[c] = static_cast(nameUTF16[c]); @@ -291,7 +292,7 @@ bool F7ZFile::Open(bool quiet) name.ToLower(); lump_p->LumpNameSetup(name); - lump_p->LumpSize = int(file->Size); + lump_p->LumpSize = static_cast(SzArEx_GetFileSize(archPtr, i)); lump_p->Owner = this; lump_p->Flags = LUMPF_ZIPFILE; lump_p->Position = i; From d8af2e558fde7e494bd1f5b636f8989efb8391fb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 31 Dec 2015 15:28:18 -0600 Subject: [PATCH 226/335] Fix potentiol buffer overrun in MUSSong2::Precache() --- src/sound/music_mus_midiout.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index eaf7e4afb..cc9bc1b69 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -211,11 +211,11 @@ bool MUSSong2::CheckDone() void MUSSong2::Precache() { - WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD)); + TArray work(MusHeader->NumInstruments); const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE); - int i, j, k; + int i, k; - for (i = j = k = 0; i < MusHeader->NumInstruments; ++i) + for (i = k = 0; i < MusHeader->NumInstruments; ++i) { BYTE instr = used[k++]; WORD val; @@ -240,15 +240,15 @@ void MUSSong2::Precache() { for (int b = 0; b < numbanks; b++) { - work[j++] = val | (used[k++] << 7); + work.Push(val | (used[k++] << 7)); } } else { - work[j++] = val; + work.Push(val); } } - MIDI->PrecacheInstruments(&work[0], j); + MIDI->PrecacheInstruments(&work[0], work.Size()); } //========================================================================== From 5e975ac9f66a955cf19255555b725ce9170d33da Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 31 Dec 2015 23:03:53 +0100 Subject: [PATCH 227/335] - extended $mididevice to add an optional parameter, which has the following meaning for the different MIDI devices: * OPL: specify the core to use for playing this song * FluidSynth: specify a soundfont that should be used for playing the song. * WildMidi: specify a config file that should be used for playing the song. * Timidity++: specify an executable that should be used for playing the song. At least under Windows this allows using Timidity++ with different configs if the executable and each single config are placed in different directories. * GUS: currently not operational, but should later also specify the config. This will need some work, because right now this is initialized only when the sound system is initialized. * all other: no function. These options should mainly be for end users who want to fine-tune how to play the music. --- src/oplsynth/mlopl_io.cpp | 5 +-- src/oplsynth/music_opl_mididevice.cpp | 4 ++- src/oplsynth/music_opldumper_mididevice.cpp | 1 + src/s_advsound.cpp | 36 ++++++++++++++++----- src/s_sound.cpp | 7 ++-- src/s_sound.h | 13 +++++++- src/sound/i_music.cpp | 31 +++++++++--------- src/sound/i_music.h | 3 +- src/sound/i_musicinterns.h | 23 ++++++------- src/sound/music_fluidsynth_mididevice.cpp | 12 +++++-- src/sound/music_hmi_midiout.cpp | 4 +-- src/sound/music_midi_timidity.cpp | 14 ++++---- src/sound/music_midistream.cpp | 14 ++++---- src/sound/music_mus_midiout.cpp | 4 +-- src/sound/music_mus_opl.cpp | 15 +++++++-- src/sound/music_smf_midiout.cpp | 4 +-- src/sound/music_timidity_mididevice.cpp | 5 +-- src/sound/music_wildmidi_mididevice.cpp | 10 +++--- src/sound/music_xmi_midiout.cpp | 4 +-- src/timidity/timidity.cpp | 3 +- src/timidity/timidity.h | 2 +- 21 files changed, 135 insertions(+), 79 deletions(-) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 691463470..4ec41d6c9 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -48,6 +48,7 @@ #define HALF_PI (PI*0.5) EXTERN_CVAR(Int, opl_core) +extern int current_opl_core; OPLio::~OPLio() { @@ -323,7 +324,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); uint i; - IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3); + IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3); memset(chips, 0, sizeof(chips)); if (IsOPL3) @@ -332,7 +333,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); + OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); if (chip == NULL) { break; diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index 79bb10226..aa6cda7ee 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -53,6 +53,7 @@ #endif // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +void OPL_SetCore(const char *args); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -76,8 +77,9 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // //========================================================================== -OPLMIDIDevice::OPLMIDIDevice() +OPLMIDIDevice::OPLMIDIDevice(const char *args) { + OPL_SetCore(args); FullPan = opl_fullpan; FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 46dcdfef2..e6684e1a6 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -262,6 +262,7 @@ protected: //========================================================================== OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename) + : OPLMIDIDevice(NULL) { // Replace the standard OPL device with a disk writer. delete io; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index cb0f26ae6..8170c1a30 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1364,16 +1364,36 @@ static void S_AddSNDINFO (int lump) case SI_MidiDevice: { sc.MustGetString(); FName nm = sc.String; + FScanner::SavedPos save = sc.SavePos(); + + sc.SetCMode(true); sc.MustGetString(); - if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY; - else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS; - else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; - else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; - else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; - else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; - else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS; - else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI; + MidiDeviceSetting devset; + if (sc.Compare("timidity")) devset.device = MDEV_TIMIDITY; + else if (sc.Compare("fmod") || sc.Compare("sndsys")) devset.device = MDEV_SNDSYS; + else if (sc.Compare("standard")) devset.device = MDEV_MMAPI; + else if (sc.Compare("opl")) devset.device = MDEV_OPL; + else if (sc.Compare("default")) devset.device = MDEV_DEFAULT; + else if (sc.Compare("fluidsynth")) devset.device = MDEV_FLUIDSYNTH; + else if (sc.Compare("gus")) devset.device = MDEV_GUS; + else if (sc.Compare("wildmidi")) devset.device = MDEV_WILDMIDI; else sc.ScriptError("Unknown MIDI device %s\n", sc.String); + + if (sc.CheckString(",")) + { + sc.SetCMode(false); + sc.MustGetString(); + devset.args = sc.String; + } + else + { + // This does not really do what one might expect, because the next token has already been parsed and can be a '$'. + // So in order to continue parsing without C-Mode, we need to reset and parse the last token again. + sc.SetCMode(false); + sc.RestorePos(save); + sc.MustGetString(); + } + MidiDevices[nm] = devset; } break; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 7b38e816c..f388246a9 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2421,11 +2421,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { int lumpnum = -1; int length = 0; - int device = MDEV_DEFAULT; MusInfo *handle = NULL; - - int *devp = MidiDevices.CheckKey(musicname); - if (devp != NULL) device = *devp; + MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); // Strip off any leading file:// component. if (strncmp(musicname, "file://", 7) == 0) @@ -2495,7 +2492,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else { - mus_playing.handle = I_RegisterSong (reader, device); + mus_playing.handle = I_RegisterSong (reader, devp); } } diff --git a/src/s_sound.h b/src/s_sound.h index 16aa8b333..a72f3be0c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -397,8 +397,19 @@ enum EMidiDevice MDEV_WILDMIDI = 6, }; +struct MidiDeviceSetting +{ + int device; + FString args; + + MidiDeviceSetting() + { + device = MDEV_DEFAULT; + } +}; + typedef TMap MusicAliasMap; -typedef TMap MidiDeviceMap; +typedef TMap MidiDeviceMap; extern MusicAliasMap MusicAliases; extern MidiDeviceMap MidiDevices; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index a46401f3e..5723a18dc 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -311,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) // //========================================================================== -static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype) +static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args) { switch (miditype) { case MIDI_MUS: - return new MUSSong2(reader, devtype); + return new MUSSong2(reader, devtype, args); case MIDI_MIDI: - return new MIDISong2(reader, devtype); + return new MIDISong2(reader, devtype, args); case MIDI_HMI: - return new HMISong(reader, devtype); + return new HMISong(reader, devtype, args); case MIDI_XMI: - return new XMISong(reader, devtype); + return new XMISong(reader, devtype, args); default: return NULL; @@ -387,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size) // //========================================================================== -MusInfo *I_RegisterSong (FileReader *reader, int device) +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device) { MusInfo *info = NULL; const char *fmt; @@ -405,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) return 0; } -#ifndef _WIN32 - // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS - if (device == MDEV_MMAPI) - device = MDEV_SNDSYS; -#endif - // Check for gzip compression. Some formats are expected to have players // that can handle it, so it simplifies things if we make all songs // gzippable. @@ -447,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { - EMidiDevice devtype = (EMidiDevice)device; + EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device; +#ifndef _WIN32 + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS + if (devtype == MDEV_MMAPI) + devtype = MDEV_SNDSYS; +#endif retry_as_sndsys: - info = CreateMIDIStreamer(*reader, devtype, miditype); + info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : ""); if (info != NULL && !info->IsValid()) { delete info; @@ -464,7 +463,7 @@ retry_as_sndsys: #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) { - info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype); + info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, ""); } #endif } @@ -475,7 +474,7 @@ retry_as_sndsys: (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - info = new OPLMUSSong (*reader); + info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : ""); } // Check for game music else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') diff --git a/src/sound/i_music.h b/src/sound/i_music.h index 03e0a3212..514400e5d 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -53,7 +53,8 @@ void I_SetMusicVolume (float volume); // Registers a song handle to song data. class MusInfo; -MusInfo *I_RegisterSong (FileReader *reader, int device); +struct MidiDeviceSetting; +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 275253d84..52364ab58 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -185,7 +185,7 @@ public: class TimidityPPMIDIDevice : public PseudoMIDIDevice { public: - TimidityPPMIDIDevice(); + TimidityPPMIDIDevice(const char *args); ~TimidityPPMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -270,7 +270,7 @@ protected: class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock { public: - OPLMIDIDevice(); + OPLMIDIDevice(const char *args); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); void Close(); int GetTechnology() const; @@ -303,7 +303,7 @@ namespace Timidity { struct Renderer; } class TimidityMIDIDevice : public SoftSynthMIDIDevice { public: - TimidityMIDIDevice(); + TimidityMIDIDevice(const char *args); ~TimidityMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -337,7 +337,7 @@ protected: class WildMIDIDevice : public SoftSynthMIDIDevice { public: - WildMIDIDevice(); + WildMIDIDevice(const char *args); ~WildMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -366,7 +366,7 @@ struct fluid_synth_t; class FluidSynthMIDIDevice : public SoftSynthMIDIDevice { public: - FluidSynthMIDIDevice(); + FluidSynthMIDIDevice(const char *args); ~FluidSynthMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -431,7 +431,7 @@ protected: class MIDIStreamer : public MusInfo { public: - MIDIStreamer(EMidiDevice type); + MIDIStreamer(EMidiDevice type, const char *args); ~MIDIStreamer(); void MusicVolumeChanged(); @@ -517,6 +517,7 @@ protected: bool CallbackIsThreaded; int LoopLimit; FString DumpFilename; + FString Args; }; // MUS file played with a MIDI stream --------------------------------------- @@ -524,7 +525,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(FileReader &reader, EMidiDevice type); + MUSSong2(FileReader &reader, EMidiDevice type, const char *args); ~MUSSong2(); MusInfo *GetOPLDumper(const char *filename); @@ -550,7 +551,7 @@ protected: class MIDISong2 : public MIDIStreamer { public: - MIDISong2(FileReader &reader, EMidiDevice type); + MIDISong2(FileReader &reader, EMidiDevice type, const char *args); ~MIDISong2(); MusInfo *GetOPLDumper(const char *filename); @@ -607,7 +608,7 @@ protected: class HMISong : public MIDIStreamer { public: - HMISong(FileReader &reader, EMidiDevice type); + HMISong(FileReader &reader, EMidiDevice type, const char *args); ~HMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -650,7 +651,7 @@ protected: class XMISong : public MIDIStreamer { public: - XMISong(FileReader &reader, EMidiDevice type); + XMISong(FileReader &reader, EMidiDevice type, const char *args); ~XMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -713,7 +714,7 @@ protected: class OPLMUSSong : public StreamSong { public: - OPLMUSSong (FileReader &reader); + OPLMUSSong (FileReader &reader, const char *args); ~OPLMUSSong (); void Play (bool looping, int subsong); bool IsPlaying (); diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index af8fe6667..3be4de56b 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR // //========================================================================== -FluidSynthMIDIDevice::FluidSynthMIDIDevice() +FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args) { FluidSynth = NULL; FluidSettings = NULL; @@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() fluid_reverb_width, fluid_reverb_level); fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level, fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type); - if (0 == LoadPatchSets(fluid_patchset)) + + // try loading a patch set that got specified with $mididevice. + int res = 0; + if (args != NULL && *args != 0) + { + res = LoadPatchSets(args); + } + + if (res == 0 && 0 == LoadPatchSets(fluid_patchset)) { #ifdef __unix__ // This is the standard location on Ubuntu. diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 5fef706dd..ca3ae0905 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -HMISong::HMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index dbc56cc56..9f50b4155 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice() +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : DiskName("zmid"), #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), @@ -85,7 +85,13 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice() #ifndef _WIN32 WavePipe[0] = WavePipe[1] = -1; #endif - + + if (args == NULL || *args == 0) args = timidity_exe; + + CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", + args, *timidity_extargs, + *timidity_chorus, *timidity_reverb, *timidity_frequency); + if (DiskName == NULL) { Printf(PRINT_BOLD, "Could not create temp music file\n"); @@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO Validated = true; #endif // WIN32 - CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", - *timidity_exe, *timidity_extargs, - *timidity_chorus, *timidity_reverb, *timidity_frequency); - pipeSize = (timidity_pipe * timidity_frequency / 1000) << (timidity_stereo + !timidity_8bit); diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index a6fb5f4d8..579fd7851 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] = // //========================================================================== -MIDIStreamer::MIDIStreamer(EMidiDevice type) +MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) : #ifdef _WIN32 PlayerThread(0), ExitEvent(0), BufferDoneEvent(0), #endif - MIDI(0), Division(0), InitialTempo(500000), DeviceType(type) + MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args) { #ifdef _WIN32 BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -269,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const #ifdef HAVE_FLUIDSYNTH case MDEV_FLUIDSYNTH: - return new FluidSynthMIDIDevice; + return new FluidSynthMIDIDevice(Args); #endif case MDEV_SNDSYS: return new SndSysMIDIDevice; case MDEV_GUS: - return new TimidityMIDIDevice; + return new TimidityMIDIDevice(Args); case MDEV_OPL: try { - return new OPLMIDIDevice; + return new OPLMIDIDevice(Args); } catch (CRecoverableError &err) { @@ -291,10 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const } case MDEV_TIMIDITY: - return new TimidityPPMIDIDevice; + return new TimidityPPMIDIDevice(Args); case MDEV_WILDMIDI: - return new WildMIDIDevice; + return new WildMIDIDevice(Args); default: return NULL; diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index eaf7e4afb..fd1601ee4 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -93,8 +93,8 @@ static const BYTE CtrlTranslate[15] = // //========================================================================== -MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), MusBuffer(0) +MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), MusBuffer(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 3b5012ad9..562330ef9 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +int current_opl_core; -OPLMUSSong::OPLMUSSong (FileReader &reader) +// Get OPL core override from $mididevice +void OPL_SetCore(const char *args) +{ + current_opl_core = opl_core; + if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0'; +} + +OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args) { int samples = int(OPL_SAMPLE_RATE / 14); + OPL_SetCore(args); Music = new OPLmusicFile (&reader); m_Stream = GSnd->CreateStream (FillStream, samples*4, - (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); + (current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 49fd12502..43755eb08 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // //========================================================================== -MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { int p; int i; diff --git a/src/sound/music_timidity_mididevice.cpp b/src/sound/music_timidity_mididevice.cpp index 9e5be625b..a63e1d723 100644 --- a/src/sound/music_timidity_mididevice.cpp +++ b/src/sound/music_timidity_mididevice.cpp @@ -86,10 +86,10 @@ struct FmtChunk // //========================================================================== -TimidityMIDIDevice::TimidityMIDIDevice() +TimidityMIDIDevice::TimidityMIDIDevice(const char *args) { Renderer = NULL; - Renderer = new Timidity::Renderer((float)SampleRate); + Renderer = new Timidity::Renderer((float)SampleRate, args); } //========================================================================== @@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats() //========================================================================== TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate) + :TimidityMIDIDevice(NULL) { File = fopen(filename, "wb"); if (File != NULL) diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp index c3fd674c9..88550226a 100644 --- a/src/sound/music_wildmidi_mididevice.cpp +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -81,7 +81,7 @@ CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBAL // //========================================================================== -WildMIDIDevice::WildMIDIDevice() +WildMIDIDevice::WildMIDIDevice(const char *args) { Renderer = NULL; @@ -94,16 +94,18 @@ WildMIDIDevice::WildMIDIDevice() SampleRate = clamp(SampleRate, 11025, 65535); } - if (CurrentConfig.CompareNoCase(wildmidi_config) != 0 || SampleRate != WildMidi_GetSampleRate()) + if (args == NULL || *args == 0) args = wildmidi_config; + + if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate()) { if (CurrentConfig.IsNotEmpty()) { WildMidi_Shutdown(); CurrentConfig = ""; } - if (!WildMidi_Init(wildmidi_config, SampleRate, 0)) + if (!WildMidi_Init(args, SampleRate, 0)) { - CurrentConfig = wildmidi_config; + CurrentConfig = args; } } if (CurrentConfig.IsNotEmpty()) diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 6c179a16a..71246f518 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -XMISong::XMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Songs(0) +XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Songs(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 09b5ae7b5..807bc07b7 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -678,8 +678,9 @@ int LoadDMXGUS() return 0; } -Renderer::Renderer(float sample_rate) +Renderer::Renderer(float sample_rate, const char *args) { + // 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first rate = sample_rate; patches = NULL; resample_buffer_size = 0; diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 59ba5f8ad..45e23a9f9 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -630,7 +630,7 @@ struct Renderer int voices; int lost_notes, cut_notes; - Renderer(float sample_rate); + Renderer(float sample_rate, const char *args); ~Renderer(); void HandleEvent(int status, int parm1, int parm2); From eed6680a6722994c2936cc4c5730e0e4e43dc637 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sun, 13 Dec 2015 17:01:33 -0600 Subject: [PATCH 228/335] Added support for weapon states User#. - Added keybinds for the user state triggering. - Added WRF_USER# flags which must be specified in order to use. - # can be 1-4. --- src/d_player.h | 4 ++ src/g_shared/a_pickups.h | 1 + src/g_shared/a_weapons.cpp | 24 +++++++ src/namedef.h | 4 ++ src/p_pspr.cpp | 108 ++++++++++++++++++++++++++--- wadsrc/static/actors/constants.txt | 5 ++ wadsrc/static/menudef.txt | 8 ++- 7 files changed, 143 insertions(+), 11 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e27bf1087..1e7eef61e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -221,6 +221,10 @@ enum WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire + WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4 + WF_USER2OK = 1 << 9, + WF_USER3OK = 1 << 10, + WF_USER4OK = 1 << 11, }; #define WPIECE1 1 diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 74b10206b..80e1744e6 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -307,6 +307,7 @@ public: virtual FState *GetAltAtkState (bool hold); virtual FState *GetRelState (); virtual FState *GetZoomState (); + virtual FState *GetUserState(int state); virtual void PostMorphWeapon (); virtual void EndPowerup (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index fae232557..79546737e 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -703,6 +703,30 @@ FState *AWeapon::GetZoomState () return FindState(NAME_Zoom); } +//=========================================================================== +// +// AWeapon :: GetUserState +// +//=========================================================================== + +FState *AWeapon::GetUserState(int state) +{ + switch (state) + { + case 4: + return FindState(NAME_User4); + case 3: + return FindState(NAME_User3); + case 2: + return FindState(NAME_User2); + case 1: + return FindState(NAME_User1); + default: + return NULL; + } +} + + /* Weapon giver ***********************************************************/ IMPLEMENT_CLASS(AWeaponGiver) diff --git a/src/namedef.h b/src/namedef.h index 22dbe1b51..f9d436f28 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -221,6 +221,10 @@ xx(Flash) xx(AltFlash) xx(Reload) xx(Zoom) +xx(User1) +xx(User2) +xx(User3) +xx(User4) // State names used by ASwitchableDecoration xx(Active) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 63f3bc648..df05b9611 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -95,7 +95,8 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK); + player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK | + WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK); } psp = &player->psprites[position]; @@ -349,6 +350,34 @@ void P_ZoomWeapon (player_t *player, FState *state) P_SetPsprite (player, ps_weapon, state); } +//-------------------------------------------------------------------------- - +// +// PROC P_UserStateWeapon +// +//--------------------------------------------------------------------------- + +void P_UserStateWeapon(player_t *player, FState *state, int userstate) +{ + if (!userstate) + return; + + AWeapon *weapon; + if (player->Bot == NULL && bot_observer) + return; + + weapon = player->ReadyWeapon; + if (weapon == NULL) + return; + + if (state == NULL) + { + state = weapon->GetUserState(userstate); + } + if (state != NULL) + P_SetPsprite(player, ps_weapon, state); +} + + //--------------------------------------------------------------------------- // // PROC P_DropWeapon @@ -573,13 +602,24 @@ void DoReadyWeaponToReload (AActor *self) void DoReadyWeaponToZoom (AActor *self) { - // Prepare for reload action. + // Prepare for zoom action. player_t *player; if (self && (player = self->player)) player->WeaponState |= WF_WEAPONZOOMOK; return; } +void DoReadyWeaponToUser(AActor *self, int userStates) +{ + // Prepare for user state action. + player_t *player; + if (self && (player = self->player) && userStates) + { + player->WeaponState |= userStates; + } + return; +} + // This function replaces calls to A_WeaponReady in other codepointers. void DoReadyWeapon(AActor *self) { @@ -588,18 +628,23 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToSwitch(self); DoReadyWeaponToReload(self); DoReadyWeaponToZoom(self); + DoReadyWeaponToUser(self, (WF_USER1OK + WF_USER2OK + WF_USER3OK + WF_USER4OK)); } enum EWRF_Options { - WRF_NoBob = 1, - WRF_NoSwitch = 2, - WRF_NoPrimary = 4, - WRF_NoSecondary = 8, + WRF_NoBob = 1, + WRF_NoSwitch = 1 << 1, + WRF_NoPrimary = 1 << 2, + WRF_NoSecondary = 1 << 3, WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, - WRF_AllowReload = 16, - WRF_AllowZoom = 32, - WRF_DisableSwitch = 64, + WRF_AllowReload = 1 << 4, + WRF_AllowZoom = 1 << 5, + WRF_DisableSwitch = 1 << 6, + WRF_User1 = 1 << 7, + WRF_User2 = 1 << 8, + WRF_User3 = 1 << 9, + WRF_User4 = 1 << 10, }; DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) @@ -613,6 +658,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); + int userStates = 0; + if (paramflags & WRF_User1) userStates |= WF_USER1OK; + if (paramflags & WRF_User2) userStates |= WF_USER2OK; + if (paramflags & WRF_User3) userStates |= WF_USER3OK; + if (paramflags & WRF_User4) userStates |= WF_USER4OK; + if (userStates) DoReadyWeaponToUser(self, userStates); + DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); } @@ -732,6 +784,40 @@ void P_CheckWeaponZoom (player_t *player) } } +//--------------------------------------------------------------------------- +// +// PROC P_CheckWeaponUserState +// +// The player can use the weapon's user state functionalities. +// +//--------------------------------------------------------------------------- + +void P_CheckWeaponUserState(player_t *player) +{ + AWeapon *weapon = player->ReadyWeapon; + + if (weapon == NULL) + return; + + // Check for user state(s). + if ((player->WeaponState & WF_USER1OK) && (player->cmd.ucmd.buttons & BT_USER1)) + { + P_UserStateWeapon(player, NULL, 1); + } + else if ((player->WeaponState & WF_USER2OK) && (player->cmd.ucmd.buttons & BT_USER2)) + { + P_UserStateWeapon(player, NULL, 2); + } + else if ((player->WeaponState & WF_USER3OK) && (player->cmd.ucmd.buttons & BT_USER3)) + { + P_UserStateWeapon(player, NULL, 3); + } + else if ((player->WeaponState & WF_USER4OK) && (player->cmd.ucmd.buttons & BT_USER4)) + { + P_UserStateWeapon(player, NULL, 4); + } +} + //--------------------------------------------------------------------------- // // PROC A_ReFire @@ -1103,6 +1189,10 @@ void P_MovePsprites (player_t *player) { P_CheckWeaponZoom (player); } + if (player->WeaponState & (WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK)) + { + P_CheckWeaponUserState(player); + } } } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 956ed119f..32a45e54c 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -129,6 +129,11 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWZOOM = 32; const int WRF_DISABLESWITCH = 64; +const int WRF_USER1 = 128; +const int WRF_USER2 = 256; +const int WRF_USER3 = 512; +const int WRF_USER4 = 1024; +const int WRF_ALLUSER = WRF_USER1 | WRF_USER2 | WRF_USER3 | WRF_USER4; // Morph constants const int MRF_ADDSTAMINA = 1; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 244b14691..087c067d1 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -435,8 +435,12 @@ OptionMenu "CustomizeControls" StaticText "Controls", 1 Control "Fire", "+attack" Control "Secondary Fire", "+altattack" - Control "Weapon Reload", "+reload" - Control "Weapon Zoom", "+zoom" + Control "Weapon Reload", "+reload" + Control "Weapon Zoom", "+zoom" + Control "Weapon State 1", "+user1" + Control "Weapon State 2", "+user2" + Control "Weapon State 3", "+user3" + Control "Weapon State 4", "+user4" Control "Use / Open", "+use" Control "Move forward", "+forward" Control "Move backward", "+back" From b09a81126fc5fb2979f7ef11c5f8bb93b3bfdb24 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 14 Dec 2015 23:50:58 -0600 Subject: [PATCH 229/335] - Changed WeaponState from 8-bit to 16-bit integer. - Because the flags for WF_USER#OK are 256 on up, this is required in order to work. --- src/d_player.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index 1e7eef61e..4e29da8f0 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -409,7 +409,7 @@ public: int lastkilltime; // [RH] For multikills BYTE multicount; BYTE spreecount; // [RH] Keep track of killing sprees - BYTE WeaponState; + WORD WeaponState; AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing From 6478b98eeaa06df4bcac4968f36221f18470c3df Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 15 Dec 2015 07:19:41 -0600 Subject: [PATCH 230/335] Update serialization to BYTE from WORD for older save games. --- src/p_user.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/p_user.cpp b/src/p_user.cpp index 331a978b7..15c5055c9 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3043,6 +3043,12 @@ void player_t::Serialize (FArchive &arc) WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); cheats &= ~((1 << 14) | (0x37 << 24)); } + if (SaveVersion < 4526) + { + BYTE oldWeaponState; + arc << oldWeaponState; + WeaponState = oldWeaponState; + } else { arc << WeaponState; From 3566d3157a6bb4f56f149a83fb475acb51adea2d Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Tue, 15 Dec 2015 09:04:52 -0600 Subject: [PATCH 231/335] Use | instead of +. --- src/p_pspr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index df05b9611..9f3a24bad 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -628,7 +628,7 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToSwitch(self); DoReadyWeaponToReload(self); DoReadyWeaponToZoom(self); - DoReadyWeaponToUser(self, (WF_USER1OK + WF_USER2OK + WF_USER3OK + WF_USER4OK)); + DoReadyWeaponToUser(self, (WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK)); } enum EWRF_Options From 4931c90839577c101593c3bdd62b9c76703b3875 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 31 Dec 2015 15:44:52 -0600 Subject: [PATCH 232/335] Bump save version for bigger WeaponState property --- src/p_user.cpp | 2 +- src/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 15c5055c9..1eb838176 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3043,7 +3043,7 @@ void player_t::Serialize (FArchive &arc) WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); cheats &= ~((1 << 14) | (0x37 << 24)); } - if (SaveVersion < 4526) + if (SaveVersion < 4527) { BYTE oldWeaponState; arc << oldWeaponState; diff --git a/src/version.h b/src/version.h index c1288f02f..682c5165e 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4526 +#define SAVEVER 4527 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From afbf88cc639a3c29d98ed458fa7a1f48486f41bf Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 31 Dec 2015 16:03:38 -0600 Subject: [PATCH 233/335] Remove WRF_ALLUSER. --- wadsrc/static/actors/constants.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 32a45e54c..1e4db4092 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -133,7 +133,6 @@ const int WRF_USER1 = 128; const int WRF_USER2 = 256; const int WRF_USER3 = 512; const int WRF_USER4 = 1024; -const int WRF_ALLUSER = WRF_USER1 | WRF_USER2 | WRF_USER3 | WRF_USER4; // Morph constants const int MRF_ADDSTAMINA = 1; From 1d759283c07e99ec8784ba01e6e286fbe03703fd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 31 Dec 2015 16:41:09 -0600 Subject: [PATCH 234/335] Cleanup the zoom/reload/userX handling for A_WeaponReady - There was lots of code duplication. Consolidated it. - Renamed WRF_UserX to WRF_AllowUserX for consistancy. --- src/d_player.h | 2 +- src/g_shared/a_pickups.h | 4 +- src/g_shared/a_weapons.cpp | 40 +--- src/p_pspr.cpp | 287 ++++++++--------------------- wadsrc/static/actors/constants.txt | 8 +- 5 files changed, 82 insertions(+), 259 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 4e29da8f0..11611cded 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -225,7 +225,7 @@ enum WF_USER2OK = 1 << 9, WF_USER3OK = 1 << 10, WF_USER4OK = 1 << 11, -}; +}; #define WPIECE1 1 #define WPIECE2 2 diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 80e1744e6..413b01db3 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -305,9 +305,7 @@ public: virtual FState *GetReadyState (); virtual FState *GetAtkState (bool hold); virtual FState *GetAltAtkState (bool hold); - virtual FState *GetRelState (); - virtual FState *GetZoomState (); - virtual FState *GetUserState(int state); + virtual FState *GetStateForButtonName (FName button); virtual void PostMorphWeapon (); virtual void EndPowerup (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 79546737e..9c71ab0ea 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -683,47 +683,13 @@ FState *AWeapon::GetAltAtkState (bool hold) //=========================================================================== // -// AWeapon :: GetRelState +// AWeapon :: GetStateForButtonName // //=========================================================================== -FState *AWeapon::GetRelState () +FState *AWeapon::GetStateForButtonName (FName button) { - return FindState(NAME_Reload); -} - -//=========================================================================== -// -// AWeapon :: GetZoomState -// -//=========================================================================== - -FState *AWeapon::GetZoomState () -{ - return FindState(NAME_Zoom); -} - -//=========================================================================== -// -// AWeapon :: GetUserState -// -//=========================================================================== - -FState *AWeapon::GetUserState(int state) -{ - switch (state) - { - case 4: - return FindState(NAME_User4); - case 3: - return FindState(NAME_User3); - case 2: - return FindState(NAME_User2); - case 1: - return FindState(NAME_User1); - default: - return NULL; - } + return FindState(button); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 9f3a24bad..ed7d675d3 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -38,6 +38,30 @@ // TYPES ------------------------------------------------------------------- +struct FGenericButtons +{ + int ReadyFlag; // Flag passed to A_WeaponReady + int StateFlag; // Flag set in WeaponState + int ButtonFlag; // Button to press + ENamedName StateName; // Name of the button/state +}; + +enum EWRF_Options +{ + WRF_NoBob = 1, + WRF_NoSwitch = 1 << 1, + WRF_NoPrimary = 1 << 2, + WRF_NoSecondary = 1 << 3, + WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary, + WRF_AllowReload = 1 << 4, + WRF_AllowZoom = 1 << 5, + WRF_DisableSwitch = 1 << 6, + WRF_AllowUser1 = 1 << 7, + WRF_AllowUser2 = 1 << 8, + WRF_AllowUser3 = 1 << 9, + WRF_AllowUser4 = 1 << 10, +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -57,6 +81,16 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); static FRandom pr_wpnreadysnd ("WpnReadySnd"); static FRandom pr_gunshot ("GunShot"); +static const FGenericButtons ButtonChecks[] = +{ + { WRF_AllowReload, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom }, + { WRF_AllowZoom, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload }, + { WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 }, + { WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 }, + { WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 }, + { WRF_AllowUser4, WF_USER4OK, BT_USER4, NAME_User4 }, +}; + // CODE -------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -290,94 +324,6 @@ void P_FireWeaponAlt (player_t *player, FState *state) } } -//--------------------------------------------------------------------------- -// -// PROC P_ReloadWeapon -// -//--------------------------------------------------------------------------- - -void P_ReloadWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetRelState(); - } - // [XA] don't change state if still null, so if the modder sets - // WRF_RELOAD to true but forgets to define the Reload state, the weapon - // won't disappear. ;) - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - -//--------------------------------------------------------------------------- -// -// PROC P_ZoomWeapon -// -//--------------------------------------------------------------------------- - -void P_ZoomWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetZoomState(); - } - // [XA] don't change state if still null. Same reasons as above. - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - -//-------------------------------------------------------------------------- - -// -// PROC P_UserStateWeapon -// -//--------------------------------------------------------------------------- - -void P_UserStateWeapon(player_t *player, FState *state, int userstate) -{ - if (!userstate) - return; - - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - return; - - weapon = player->ReadyWeapon; - if (weapon == NULL) - return; - - if (state == NULL) - { - state = weapon->GetUserState(userstate); - } - if (state != NULL) - P_SetPsprite(player, ps_weapon, state); -} - - //--------------------------------------------------------------------------- // // PROC P_DropWeapon @@ -591,33 +537,21 @@ void DoReadyWeaponToBob (AActor *self) } } -void DoReadyWeaponToReload (AActor *self) +void DoReadyWeaponToGeneric(AActor *self, int paramflags) { - // Prepare for reload action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONRELOADOK; - return; -} + int flags = 0; -void DoReadyWeaponToZoom (AActor *self) -{ - // Prepare for zoom action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONZOOMOK; - return; -} - -void DoReadyWeaponToUser(AActor *self, int userStates) -{ - // Prepare for user state action. - player_t *player; - if (self && (player = self->player) && userStates) + for (size_t i = 0; i < countof(ButtonChecks); ++i) { - player->WeaponState |= userStates; + if (paramflags & ButtonChecks[i].ReadyFlag) + { + flags |= ButtonChecks[i].StateFlag; + } + } + if (self != NULL && self->player != NULL) + { + self->player->WeaponState |= flags; } - return; } // This function replaces calls to A_WeaponReady in other codepointers. @@ -626,27 +560,9 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToBob(self); DoReadyWeaponToFire(self); DoReadyWeaponToSwitch(self); - DoReadyWeaponToReload(self); - DoReadyWeaponToZoom(self); - DoReadyWeaponToUser(self, (WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK)); + DoReadyWeaponToGeneric(self, ~0); } -enum EWRF_Options -{ - WRF_NoBob = 1, - WRF_NoSwitch = 1 << 1, - WRF_NoPrimary = 1 << 2, - WRF_NoSecondary = 1 << 3, - WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, - WRF_AllowReload = 1 << 4, - WRF_AllowZoom = 1 << 5, - WRF_DisableSwitch = 1 << 6, - WRF_User1 = 1 << 7, - WRF_User2 = 1 << 8, - WRF_User3 = 1 << 9, - WRF_User4 = 1 << 10, -}; - DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) { ACTION_PARAM_START(1); @@ -655,17 +571,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); - if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); - - int userStates = 0; - if (paramflags & WRF_User1) userStates |= WF_USER1OK; - if (paramflags & WRF_User2) userStates |= WF_USER2OK; - if (paramflags & WRF_User3) userStates |= WF_USER3OK; - if (paramflags & WRF_User4) userStates |= WF_USER4OK; - if (userStates) DoReadyWeaponToUser(self, userStates); - - DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); + DoReadyWeaponToGeneric(self, paramflags); + DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); } //--------------------------------------------------------------------------- @@ -742,79 +649,40 @@ void P_CheckWeaponSwitch (player_t *player) //--------------------------------------------------------------------------- // -// PROC P_CheckWeaponReload +// PROC P_CheckWeaponButtons // -// The player can reload the weapon. +// Check extra button presses for weapons. // //--------------------------------------------------------------------------- -void P_CheckWeaponReload (player_t *player) +static void P_CheckWeaponButtons (player_t *player) { - AWeapon *weapon = player->ReadyWeapon; - - if (weapon == NULL) + if (player->Bot == NULL && bot_observer) + { return; - - // Check for reload. - if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) - { - P_ReloadWeapon (player, NULL); } -} - -//--------------------------------------------------------------------------- -// -// PROC P_CheckWeaponZoom -// -// The player can use the weapon's zoom function. -// -//--------------------------------------------------------------------------- - -void P_CheckWeaponZoom (player_t *player) -{ AWeapon *weapon = player->ReadyWeapon; - if (weapon == NULL) + { return; - - // Check for zoom. - if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) - { - P_ZoomWeapon (player, NULL); } -} - -//--------------------------------------------------------------------------- -// -// PROC P_CheckWeaponUserState -// -// The player can use the weapon's user state functionalities. -// -//--------------------------------------------------------------------------- - -void P_CheckWeaponUserState(player_t *player) -{ - AWeapon *weapon = player->ReadyWeapon; - - if (weapon == NULL) - return; - - // Check for user state(s). - if ((player->WeaponState & WF_USER1OK) && (player->cmd.ucmd.buttons & BT_USER1)) + // The button checks are ordered by precedence. The first one to match a + // button press and affect a state change wins. + for (size_t i = 0; i < countof(ButtonChecks); ++i) { - P_UserStateWeapon(player, NULL, 1); - } - else if ((player->WeaponState & WF_USER2OK) && (player->cmd.ucmd.buttons & BT_USER2)) - { - P_UserStateWeapon(player, NULL, 2); - } - else if ((player->WeaponState & WF_USER3OK) && (player->cmd.ucmd.buttons & BT_USER3)) - { - P_UserStateWeapon(player, NULL, 3); - } - else if ((player->WeaponState & WF_USER4OK) && (player->cmd.ucmd.buttons & BT_USER4)) - { - P_UserStateWeapon(player, NULL, 4); + if ((player->WeaponState & ButtonChecks[i].StateFlag) && + (player->cmd.ucmd.buttons & ButtonChecks[i].ButtonFlag)) + { + FState *state = weapon->GetStateForButtonName(ButtonChecks[i].StateName); + // [XA] don't change state if still null, so if the modder + // sets WRF_xxx to true but forgets to define the corresponding + // state, the weapon won't disappear. ;) + if (state != NULL) + { + P_SetPsprite(player, ps_weapon, state); + return; + } + } } } @@ -1181,18 +1049,9 @@ void P_MovePsprites (player_t *player) { P_CheckWeaponFire (player); } - if (player->WeaponState & WF_WEAPONRELOADOK) - { - P_CheckWeaponReload (player); - } - if (player->WeaponState & WF_WEAPONZOOMOK) - { - P_CheckWeaponZoom (player); - } - if (player->WeaponState & (WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK)) - { - P_CheckWeaponUserState(player); - } + + // Check custom buttons + P_CheckWeaponButtons(player); } } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 1e4db4092..213e2109d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -129,10 +129,10 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWZOOM = 32; const int WRF_DISABLESWITCH = 64; -const int WRF_USER1 = 128; -const int WRF_USER2 = 256; -const int WRF_USER3 = 512; -const int WRF_USER4 = 1024; +const int WRF_ALLOWUSER1 = 128; +const int WRF_ALLOWUSER2 = 256; +const int WRF_ALLOWUSER3 = 512; +const int WRF_ALLOWUSER4 = 1024; // Morph constants const int MRF_ADDSTAMINA = 1; From b8b81e9809fb1fb7a0e727810f117fddb55e3da9 Mon Sep 17 00:00:00 2001 From: John Palomo Jr Date: Fri, 1 Jan 2016 13:27:44 -0500 Subject: [PATCH 235/335] Added turn180 to the controls menu. --- wadsrc/static/menudef.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 087c067d1..add844455 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -448,6 +448,7 @@ OptionMenu "CustomizeControls" Control "Strafe right", "+moveright" Control "Turn left", "+left" Control "Turn right", "+right" + Control "Quick Turn", "turn180" Control "Jump", "+jump" Control "Crouch", "+crouch" Control "Crouch Toggle", "crouch" From 77013877d1bb213a8c803fdd28f6924f4c791ce5 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 2 Jan 2016 11:27:02 -0600 Subject: [PATCH 236/335] A_WeaponReady Fix - Zoom and Reload keys triggered the other states instead of themselves (i.e. zoom keybind triggered reload states instead of zoom) --- src/p_pspr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index ed7d675d3..7cdef059c 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -83,8 +83,8 @@ static FRandom pr_gunshot ("GunShot"); static const FGenericButtons ButtonChecks[] = { - { WRF_AllowReload, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom }, - { WRF_AllowZoom, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload }, + { WRF_AllowZoom, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom }, + { WRF_AllowReload, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload }, { WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 }, { WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 }, { WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 }, From a75e65a3d8df1e29f83d098ae5bf061159053c11 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 3 Jan 2016 11:32:23 +0100 Subject: [PATCH 237/335] - added BLOCKF_SOUND to flag list supported by Line_SetBlocking, --- src/p_lnspec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9c93ca15c..9b38e149b 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2587,6 +2587,7 @@ FUNC(LS_Line_SetBlocking) ML_BLOCKUSE, ML_BLOCKSIGHT, ML_BLOCKHITSCAN, + ML_SOUNDBLOCK, -1 }; From 699f274b06dc44d5135c8bc6321f0e59997ef821 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 4 Jan 2016 10:51:54 +0200 Subject: [PATCH 238/335] Fixed mouse cursor centering in fullscreen mode Native OS X backed didn't center mouse cursor in fullscreen mode with Retina/HiDPI support enabled Incorrect size of content view led to placement of cursor in upper right corner of the screen upon releasing of mouse capture When some action is assigned to this corner using system Hot Corners feature, the given action was triggered on acquiring mouse capture --- src/posix/cocoa/i_video.mm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3fc2b2aed..e99443ee8 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -625,7 +625,7 @@ void CocoaVideo::SetFullscreenMode(const int width, const int height) [m_window setHidesOnDeactivate:YES]; } - [m_window setFrame:displayRect display:YES]; + [m_window setFrame:screenFrame display:YES]; [m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)]; } @@ -1231,10 +1231,7 @@ NSSize I_GetContentViewSize(const NSWindow* const window) const NSView* const view = [window contentView]; const NSSize frameSize = [view frame].size; - // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window - // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window - - return (vid_hidpi && !fullscreen) + return (vid_hidpi) ? [view convertSizeToBacking:frameSize] : frameSize; } From 02ff3291bdfc8e7f3e75306204e18fe94aa39fa6 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 4 Jan 2016 12:15:14 +0200 Subject: [PATCH 239/335] Fixed division by zero in RNG Random number generator now returns zero for range [0, 0) --- src/m_random.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/m_random.h b/src/m_random.h index b5e21c63c..452ef41fc 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -57,7 +57,9 @@ public: // Returns a random number in the range [0,mod) int operator() (int mod) { - return GenRand32() % mod; + return (0 == mod) + ? 0 + : (GenRand32() % mod); } // Returns rand# - rand# From bd95c5eadf9c1ef79e9ca10de3844d73a1f7b0e5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 4 Jan 2016 11:52:07 +0100 Subject: [PATCH 240/335] - fixed: the ambient sound things need both the args from the DoomEdNum mapping and the actual map. --- src/g_doomedmap.cpp | 13 +++- src/info.h | 2 +- src/p_mobj.cpp | 4 +- wadsrc/static/mapinfo/common.txt | 128 +++++++++++++++---------------- 4 files changed, 77 insertions(+), 70 deletions(-) diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 08d5aa2e2..42157101d 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -81,7 +81,7 @@ struct MapinfoEdMapItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. short special; - bool argsdefined; + signed char argsdefined; int args[5]; // These are for error reporting. We must store the file information because it's no longer available when these items get resolved. FString filename; @@ -181,14 +181,14 @@ void FMapInfoParser::ParseDoomEdNums() editem.special = -1; } memset(editem.args, 0, sizeof(editem.args)); - editem.argsdefined = false; + editem.argsdefined = 0; int minargs = 0; int maxargs = 5; FString specialname; if (sc.CheckString(",")) { - editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + editem.argsdefined = 5; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. if (editem.special < 0) editem.special = 0; if (!sc.CheckNumber()) { @@ -221,7 +221,14 @@ void FMapInfoParser::ParseDoomEdNums() editem.args[i] = sc.Number; i++; if (!sc.CheckString(",")) break; + // special check for the ambient sounds which combine the arg being set here with the ones on the mapthing. + if (sc.CheckString("+")) + { + editem.argsdefined = i; + break; + } sc.MustGetNumber(); + } if (specialname.IsNotEmpty() && (i < minargs || i > maxargs)) { diff --git a/src/info.h b/src/info.h index bdbb69940..22e3b2f5c 100644 --- a/src/info.h +++ b/src/info.h @@ -283,7 +283,7 @@ struct FDoomEdEntry { const PClass *Type; short Special; - bool ArgsDefined; + signed char ArgsDefined; int Args[5]; }; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ab89ae04c..bc314dc0e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4674,10 +4674,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) } // copy args to mapthing so that we have them in one place for the rest of this function - if (mentry->ArgsDefined) + if (mentry->ArgsDefined > 0) { if (mentry->Type!= NULL) mthing->special = mentry->Special; - memcpy(mthing->args, mentry->Args, sizeof(mthing->args)); + memcpy(mthing->args, mentry->Args, sizeof(mthing->args[0]) * mentry->ArgsDefined); } int pnum = -1; diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index f26ca6731..4b663047c 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -118,70 +118,70 @@ DoomEdNums 9997 = SecActExit 9998 = SecActEnter 9999 = SecActHitFloor - 14001 = AmbientSound, 1 - 14002 = AmbientSound, 2 - 14003 = AmbientSound, 3 - 14004 = AmbientSound, 4 - 14005 = AmbientSound, 5 - 14006 = AmbientSound, 6 - 14007 = AmbientSound, 7 - 14008 = AmbientSound, 8 - 14009 = AmbientSound, 9 - 14010 = AmbientSound, 10 - 14011 = AmbientSound, 11 - 14012 = AmbientSound, 12 - 14013 = AmbientSound, 13 - 14014 = AmbientSound, 14 - 14015 = AmbientSound, 15 - 14016 = AmbientSound, 16 - 14017 = AmbientSound, 17 - 14018 = AmbientSound, 18 - 14019 = AmbientSound, 19 - 14020 = AmbientSound, 20 - 14021 = AmbientSound, 21 - 14022 = AmbientSound, 22 - 14023 = AmbientSound, 23 - 14024 = AmbientSound, 24 - 14025 = AmbientSound, 25 - 14026 = AmbientSound, 26 - 14027 = AmbientSound, 27 - 14028 = AmbientSound, 28 - 14029 = AmbientSound, 29 - 14030 = AmbientSound, 30 - 14031 = AmbientSound, 31 - 14032 = AmbientSound, 32 - 14033 = AmbientSound, 33 - 14034 = AmbientSound, 34 - 14035 = AmbientSound, 35 - 14036 = AmbientSound, 36 - 14037 = AmbientSound, 37 - 14038 = AmbientSound, 38 - 14039 = AmbientSound, 39 - 14040 = AmbientSound, 40 - 14041 = AmbientSound, 41 - 14042 = AmbientSound, 42 - 14043 = AmbientSound, 43 - 14044 = AmbientSound, 44 - 14045 = AmbientSound, 45 - 14046 = AmbientSound, 46 - 14047 = AmbientSound, 47 - 14048 = AmbientSound, 48 - 14049 = AmbientSound, 49 - 14050 = AmbientSound, 50 - 14051 = AmbientSound, 51 - 14052 = AmbientSound, 52 - 14053 = AmbientSound, 53 - 14054 = AmbientSound, 54 - 14055 = AmbientSound, 55 - 14056 = AmbientSound, 56 - 14057 = AmbientSound, 57 - 14058 = AmbientSound, 58 - 14059 = AmbientSound, 59 - 14060 = AmbientSound, 60 - 14061 = AmbientSound, 61 - 14062 = AmbientSound, 62 - 14063 = AmbientSound, 63 - 14064 = AmbientSound, 64 + 14001 = AmbientSound, 1, + + 14002 = AmbientSound, 2, + + 14003 = AmbientSound, 3, + + 14004 = AmbientSound, 4, + + 14005 = AmbientSound, 5, + + 14006 = AmbientSound, 6, + + 14007 = AmbientSound, 7, + + 14008 = AmbientSound, 8, + + 14009 = AmbientSound, 9, + + 14010 = AmbientSound, 10, + + 14011 = AmbientSound, 11, + + 14012 = AmbientSound, 12, + + 14013 = AmbientSound, 13, + + 14014 = AmbientSound, 14, + + 14015 = AmbientSound, 15, + + 14016 = AmbientSound, 16, + + 14017 = AmbientSound, 17, + + 14018 = AmbientSound, 18, + + 14019 = AmbientSound, 19, + + 14020 = AmbientSound, 20, + + 14021 = AmbientSound, 21, + + 14022 = AmbientSound, 22, + + 14023 = AmbientSound, 23, + + 14024 = AmbientSound, 24, + + 14025 = AmbientSound, 25, + + 14026 = AmbientSound, 26, + + 14027 = AmbientSound, 27, + + 14028 = AmbientSound, 28, + + 14029 = AmbientSound, 29, + + 14030 = AmbientSound, 30, + + 14031 = AmbientSound, 31, + + 14032 = AmbientSound, 32, + + 14033 = AmbientSound, 33, + + 14034 = AmbientSound, 34, + + 14035 = AmbientSound, 35, + + 14036 = AmbientSound, 36, + + 14037 = AmbientSound, 37, + + 14038 = AmbientSound, 38, + + 14039 = AmbientSound, 39, + + 14040 = AmbientSound, 40, + + 14041 = AmbientSound, 41, + + 14042 = AmbientSound, 42, + + 14043 = AmbientSound, 43, + + 14044 = AmbientSound, 44, + + 14045 = AmbientSound, 45, + + 14046 = AmbientSound, 46, + + 14047 = AmbientSound, 47, + + 14048 = AmbientSound, 48, + + 14049 = AmbientSound, 49, + + 14050 = AmbientSound, 50, + + 14051 = AmbientSound, 51, + + 14052 = AmbientSound, 52, + + 14053 = AmbientSound, 53, + + 14054 = AmbientSound, 54, + + 14055 = AmbientSound, 55, + + 14056 = AmbientSound, 56, + + 14057 = AmbientSound, 57, + + 14058 = AmbientSound, 58, + + 14059 = AmbientSound, 59, + + 14060 = AmbientSound, 60, + + 14061 = AmbientSound, 61, + + 14062 = AmbientSound, 62, + + 14063 = AmbientSound, 63, + + 14064 = AmbientSound, 64, + 14065 = AmbientSound 14066 = SoundSequence 14067 = AmbientSoundNoGravity From 111479063f7120ff2b05b19ee558a0d3c98f8a6d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 4 Jan 2016 21:05:09 +0100 Subject: [PATCH 241/335] - fixed a potential overflow issue with calculating a portal's origin point. - fixed: Sector_SetPortal's Eternity translation was not correct. The ZDoom variant allows specifying the plane as part of the portal, Eternity does not. Added a new 'plane' type 3 which just means 'any'. --- src/p_spec.cpp | 11 ++++++----- wadsrc/static/xlat/eternity.txt | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e2cc0025b..95995bdab 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1125,10 +1125,11 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) lines[i].args[2] == plane && lines[i].args[3] == 1) { - fixed_t x1 = (line->v1->x + line->v2->x) >> 1; - fixed_t y1 = (line->v1->y + line->v2->y) >> 1; - fixed_t x2 = (lines[i].v1->x + lines[i].v2->x) >> 1; - fixed_t y2 = (lines[i].v1->y + lines[i].v2->y) >> 1; + // beware of overflows. + fixed_t x1 = fixed_t((SQWORD(line->v1->x) + SQWORD(line->v2->x)) >> 1); + fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1); + fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1); + fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1); fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255); AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE); @@ -1155,7 +1156,7 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) // This must be done here to ensure that it gets done only after the portal is set up if (lines[j].special == Sector_SetPortal && lines[j].args[1] == 1 && - lines[j].args[2] == plane && + (lines[j].args[2] == plane || lines[j].args[2] == 3) && lines[j].args[3] == sectortag) { if (lines[j].args[0] == 0) diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index ad270beb4..7b4367ee3 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -170,7 +170,7 @@ define Unsupported (0) 384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl" // Attach tagged portal to front sector -385 = 0, Sector_SetPortal(0, 1, 2, tag) // "Apply_PortalToFrontsector" +385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector" // Slopes! 386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor" From c9afb199caf363e1387bd9111b31137d5c44d972 Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Tue, 5 Jan 2016 13:58:00 +1000 Subject: [PATCH 242/335] Added "pufftid" parameter for LineAttack. --- src/p_acs.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b94d63b79..f9744884c 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5397,6 +5397,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None; fixed_t range = argCount > 6 && args[6]? args[6] : MISSILERANGE; int flags = argCount > 7 && args[7]? args[7] : 0; + int pufftid = argCount > 8 && args[8]? args[8] : 0; int fhflags = 0; if (flags & FHF_NORANDOMPUFFZ) fhflags |= LAF_NORANDOMPUFFZ; @@ -5404,7 +5405,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const if (args[0] == 0) { - P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); + AActor *puff = P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); + if (pufftid != 0) + { + puff->tid = pufftid; + puff->AddToHash(); + } } else { @@ -5413,7 +5419,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const while ((source = it.Next()) != NULL) { - P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags); + AActor *puff = P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags); + if (pufftid != 0) + { + puff->tid = pufftid; + puff->AddToHash(); + } } } } From b2f860d7ae6842ab0bdf168f6b2bb4a03bf5e9b0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 11:07:59 +0100 Subject: [PATCH 243/335] - better add a NULL pointer check here. --- src/p_acs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f9744884c..663d316dc 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5406,7 +5406,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const if (args[0] == 0) { AActor *puff = P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); - if (pufftid != 0) + if (puff != NULL && pufftid != 0) { puff->tid = pufftid; puff->AddToHash(); @@ -5420,7 +5420,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const while ((source = it.Next()) != NULL) { AActor *puff = P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags); - if (pufftid != 0) + if (puff != NULL && pufftid != 0) { puff->tid = pufftid; puff->AddToHash(); From 99bf01365249f3db6ef3ea266c1a95f792aa40f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 11:16:38 +0100 Subject: [PATCH 244/335] - added new IWAD name HERETICSR.WAD so that commercial Heretic and Shadows of the Serpent Riders can coexist. --- wadsrc/static/iwadinfo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 6c958ddfa..401f3ca4c 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -370,6 +370,7 @@ Names "doom.wad" "doom1.wad" "heretic.wad" + "hereticsr.wad" "heretic1.wad" "hexen.wad" "hexdd.wad" From a5a069a4b0835191652bb211dfa2a57a6f641042 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 14:06:07 +0100 Subject: [PATCH 245/335] - use DMENUPIC as titlepic in doom2bfg. --- wadsrc/static/mapinfo/doom2bfg.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt index cc82c4e19..28bea129d 100644 --- a/wadsrc/static/mapinfo/doom2bfg.txt +++ b/wadsrc/static/mapinfo/doom2bfg.txt @@ -3,7 +3,7 @@ include "mapinfo/doom2.txt" gameinfo { - titlepage = "INTERPIC" + titlepage = "DMENUPIC" } clearepisodes From 8ded18a96c79f69211d80bce532bc283e4e16758 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 14:09:34 +0100 Subject: [PATCH 246/335] - changed default frequency for Timidity++ to 44100kHz. --- src/sound/music_midi_timidity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 9f50b4155..667de8842 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -58,7 +58,7 @@ CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { // Clamp frequency to Timidity's limits if (self < 4000) self = 4000; From d432df55e9be1d56f98a1b3e8b5966aeecae4e3a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 15:37:59 +0100 Subject: [PATCH 247/335] - changed Sector_SetDamage so that it can explicitly set the damage interval and the leakiness probability, instead of hardcoding it to fixed damage ranges. - fixed: FCajunMaster::IsDangerous did not check for Heretic's sludge type. --- src/b_move.cpp | 3 ++- src/p_3dfloors.cpp | 2 +- src/p_lnspec.cpp | 26 +++++++++++++++++++++++--- src/p_saveg.cpp | 32 ++++++++++++++++++++++++++++---- src/p_spec.cpp | 39 +++++++++++++++++++++------------------ src/p_user.cpp | 2 +- src/r_defs.h | 8 +++++--- src/version.h | 2 +- 8 files changed, 82 insertions(+), 32 deletions(-) diff --git a/src/b_move.cpp b/src/b_move.cpp index fd0405457..2a76f1925 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -357,7 +357,7 @@ bool FCajunMaster::IsDangerous (sector_t *sec) int special; return - sec->damage + sec->damageamount || sec->special & DAMAGE_MASK || (special = sec->special & 0xff, special == dLight_Strobe_Hurt) || special == dDamage_Hellslime @@ -367,6 +367,7 @@ bool FCajunMaster::IsDangerous (sector_t *sec) || special == dDamage_LavaWimpy || special == dDamage_LavaHefty || special == dScroll_EastLavaDamage + || special == hDamage_Sludge || special == sLight_Strobe_Hurt || special == Damage_InstantDeath || special == sDamage_SuperHellslime; diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 5b29959cb..6af26652f 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -342,7 +342,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) } // Apply sector specials - if (rover->model->special || rover->model->damage) + if (rover->model->special || rover->model->damageamount) P_PlayerInSpecialSector(player, rover->model); // Apply flat specials (using the ceiling!) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9b38e149b..fb9858bc2 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2246,7 +2246,7 @@ FUNC(LS_PointPush_SetForce) } FUNC(LS_Sector_SetDamage) -// Sector_SetDamage (tag, amount, mod) +// Sector_SetDamage (tag, amount, mod, interval, leaky) { // The sector still stores the mod in its old format because // adding an FName to the sector_t structure might cause @@ -2257,8 +2257,28 @@ FUNC(LS_Sector_SetDamage) int secnum; while ((secnum = itr.Next()) >= 0) { - sectors[secnum].damage = arg1; - sectors[secnum].mod = arg2; + if (arg3 <= 0) // emulate old and hacky method to handle leakiness. + { + if (arg1 < 20) + { + arg4 = 0; + arg3 = 32; + } + else if (arg1 < 50) + { + arg4 = 5; + arg3 = 32; + } + else + { + arg4 = 256; + arg3 = 1; + } + } + sectors[secnum].damageamount = (short)arg1; + sectors[secnum].damagemod = (short)arg2; + sectors[secnum].damageinterval = (short)arg3; + sectors[secnum].leakydamage = (short)arg4; } return true; } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 480494320..462c1e757 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -354,7 +354,7 @@ void P_SerializeWorld (FArchive &arc) short tag; arc << tag; } - arc << sec->soundtraversed + arc << sec->soundtraversed << sec->seqType << sec->friction << sec->movefactor @@ -369,9 +369,33 @@ void P_SerializeWorld (FArchive &arc) << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap << sec->gravity - << sec->damage - << sec->mod - << sec->SoundTarget + << sec->damageamount + << sec->damagemod; + if (SaveVersion >= 4528) + { + arc << sec->damageinterval + << sec->leakydamage; + } + else + { + if (sec->damageamount < 20) + { + sec->leakydamage = 0; + sec->damageinterval = 32; + } + else if (sec->damageamount < 50) + { + sec->leakydamage = 5; + sec->damageinterval = 32; + } + else + { + sec->leakydamage = 256; + sec->damageinterval = 1; + } + } + + arc << sec->SoundTarget << sec->SecActTarget << sec->sky << sec->MoreFlags diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 95995bdab..e0b11dd7e 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -566,24 +566,11 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } // [RH] Apply any customizable damage - if (sector->damage) + if (sector->damageamount != 0) { - if (sector->damage < 20) + if (level.time % sector->damageinterval == 0 && (ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) { - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); - } - else if (sector->damage < 50) - { - if ((ironfeet == NULL || (pr_playerinspecialsector()<5)) - && !(level.time&0x1f)) - { - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); - } - } - else - { - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); + P_DamageMobj (player->mo, NULL, NULL, sector->damageamount, MODtoDamageType (sector->damagemod)); } } @@ -1450,8 +1437,24 @@ void P_SpawnSpecials (void) FSectorTagIterator itr(lines[i].args[0]); while ((s = itr.Next()) >= 0) { - sectors[s].damage = damage; - sectors[s].mod = 0;//MOD_UNKNOWN; + sector_t *sec = §ors[s]; + sec->damageamount = damage; + sec->damagemod = 0;//MOD_UNKNOWN; + if (sec->damageamount < 20) + { + sec->leakydamage = 0; + sec->damageinterval = 32; + } + else if (sec->damageamount < 50) + { + sec->leakydamage = 5; + sec->damageinterval = 32; + } + else + { + sec->leakydamage = 256; + sec->damageinterval = 1; + } } } break; diff --git a/src/p_user.cpp b/src/p_user.cpp index 1eb838176..8f8a93fdb 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2538,7 +2538,7 @@ void P_PlayerThink (player_t *player) if (!(player->cheats & CF_PREDICTING)) { P_PlayerOnSpecial3DFloor (player); - if (player->mo->Sector->special || player->mo->Sector->damage) + if (player->mo->Sector->special || player->mo->Sector->damageamount != 0) { P_PlayerInSpecialSector (player); } diff --git a/src/r_defs.h b/src/r_defs.h index b741b5f6b..2360328e6 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -709,9 +709,11 @@ struct sector_t // thinglist is a subset of touching_thinglist struct msecnode_t *touching_thinglist; // phares 3/14/98 - float gravity; // [RH] Sector gravity (1.0 is normal) - short damage; // [RH] Damage to do while standing on floor - short mod; // [RH] Means-of-death for applied damage + float gravity; // [RH] Sector gravity (1.0 is normal) + short damageamount; // [RH] Damage to do while standing on floor + short damagemod; // [RH] Means-of-death for applied damage + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit WORD ZoneNumber; // [RH] Zone this sector belongs to WORD MoreFlags; // [RH] Internal sector flags diff --git a/src/version.h b/src/version.h index 682c5165e..d7026786e 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4527 +#define SAVEVER 4528 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 3e13e772ef75eea0654b5ae816fb6aa16f1c88f7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 16:10:04 +0100 Subject: [PATCH 248/335] - after realizing that changing the sector's MOD variable to an FNameNoInit doesn't do anything bad, I just went ahead and got rid of the last place in the engine that still used this data type for internal storage. --- src/p_lnspec.cpp | 2 +- src/p_saveg.cpp | 9 ++++++--- src/p_spec.cpp | 4 ++-- src/r_defs.h | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index fb9858bc2..8fa8691b2 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2276,7 +2276,7 @@ FUNC(LS_Sector_SetDamage) } } sectors[secnum].damageamount = (short)arg1; - sectors[secnum].damagemod = (short)arg2; + sectors[secnum].damagetype = MODtoDamageType(arg2); sectors[secnum].damageinterval = (short)arg3; sectors[secnum].leakydamage = (short)arg4; } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 462c1e757..fdf57ddb0 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -369,15 +369,18 @@ void P_SerializeWorld (FArchive &arc) << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap << sec->gravity - << sec->damageamount - << sec->damagemod; + << sec->damageamount; if (SaveVersion >= 4528) { arc << sec->damageinterval - << sec->leakydamage; + << sec->leakydamage + << sec->damagetype; } else { + short damagemod; + arc << damagemod; + sec->damagetype = MODtoDamageType(damagemod); if (sec->damageamount < 20) { sec->leakydamage = 0; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e0b11dd7e..c439ac50e 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -570,7 +570,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { if (level.time % sector->damageinterval == 0 && (ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) { - P_DamageMobj (player->mo, NULL, NULL, sector->damageamount, MODtoDamageType (sector->damagemod)); + P_DamageMobj (player->mo, NULL, NULL, sector->damageamount, sector->damagetype); } } @@ -1439,7 +1439,7 @@ void P_SpawnSpecials (void) { sector_t *sec = §ors[s]; sec->damageamount = damage; - sec->damagemod = 0;//MOD_UNKNOWN; + sec->damagetype = NAME_None; if (sec->damageamount < 20) { sec->leakydamage = 0; diff --git a/src/r_defs.h b/src/r_defs.h index 2360328e6..89449f446 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -710,8 +710,8 @@ struct sector_t struct msecnode_t *touching_thinglist; // phares 3/14/98 float gravity; // [RH] Sector gravity (1.0 is normal) + FNameNoInit damagetype; // [RH] Means-of-death for applied damage short damageamount; // [RH] Damage to do while standing on floor - short damagemod; // [RH] Means-of-death for applied damage short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit From 2b519a92b166e06cd0bec48ca25e9117df878cdd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 16:19:55 +0100 Subject: [PATCH 249/335] - allow setting the sector's damage properties through UDMF. --- specs/udmf_zdoom.txt | 10 +++++++++- src/namedef.h | 4 ++++ src/p_udmf.cpp | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index e79ae196b..f20525d13 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -203,7 +203,11 @@ Note: All fields default to false unless mentioned otherwise. // sound sequence thing in the sector will override this property. hidden = ; // if true this sector will not be drawn on the textured automap. waterzone = ; // Sector is under water and swimmable - moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + damageamount = ; // Amount of damage inflicted by this sector, default = 0 + damagetype = ; // Damage type for sector damage, Default = "None". (generic damage) + damageinterval = ; // Interval in tics between damage application, default = 32. + leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. * Note about dropactors @@ -377,6 +381,10 @@ Changed language describing the DIALOGUE lump to mention USDF as an option. 1.25 19.04.2015 Added 'moreids' for linedefs and sectors. +1.26 05.01.2016 +added clarification about character encoding +added sector damage properties. + =============================================================================== EOF =============================================================================== diff --git a/src/namedef.h b/src/namedef.h index f9d436f28..cad58bfa3 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -506,6 +506,10 @@ xx(floorplane_a) xx(floorplane_b) xx(floorplane_c) xx(floorplane_d) +xx(damageamount) +xx(damagetype) +xx(damageinterval) +xx(leakiness) // USDF keywords xx(Amount) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index db0c952cf..89c039aef 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1299,6 +1299,8 @@ public: sec->prevsec = -1; // stair retriggering until build completes sec->heightsec = NULL; // sector used to get floor and ceiling height sec->sectornum = index; + sec->damageinterval = 32; + sec->leakydamage = 5; if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes @@ -1524,6 +1526,23 @@ public: cp[3] = CheckFloat(key); break; + case NAME_damageamount: + sec->damageamount = CheckInt(key); + break; + + case NAME_damagetype: + sec->damagetype = CheckString(key); + break; + + case NAME_damageinterval: + sec->damageinterval = CheckInt(key); + if (sec->damageinterval < 1) sec->damageinterval = 1; + break; + + case NAME_leakiness: + sec->leakydamage = CheckInt(key); + break; + case NAME_MoreIds: // delay parsing of the tag string until parsing of the sector is complete // This ensures that the ID is always the first tag in the list. From d0c372692bd6388b699da253a4f9eb93c7f90fdf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 16:29:04 +0100 Subject: [PATCH 250/335] - added new ACS function SetSectorDamage which allows the use of actual damage types, unlike the old Sector_SetDamage. Unlike Sector_SetDamage this function does not use damage amount dependent defaults for the interval and the leakiness if none are passed. --- src/p_acs.cpp | 18 ++++++++++++++++++ src/p_udmf.cpp | 1 - 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 663d316dc..aacd5cc4a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4458,6 +4458,7 @@ enum EACSFunctions ACSF_QuakeEx, ACSF_Warp, // 92 ACSF_GetMaxInventory, + ACSF_SetSectorDamage, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5950,6 +5951,23 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } break; + case ACSF_SetSectorDamage: + if (argCount >= 2) + { + FSectorTagIterator it(args[0]); + int s; + while ((s = it.Next()) >= 0) + { + sector_t *sec = §ors[s]; + + sec->damageamount = args[1]; + sec->damagetype = argCount >= 3 ? FName(FBehavior::StaticLookupString(args[2])) : FName(NAME_None); + sec->damageinterval = argCount >= 4 ? clamp(args[3], 1, INT_MAX) : 32; + sec->leakydamage = argCount >= 5 ? args[4] : 0; + } + } + break; + default: break; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 89c039aef..2169da49f 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1300,7 +1300,6 @@ public: sec->heightsec = NULL; // sector used to get floor and ceiling height sec->sectornum = index; sec->damageinterval = 32; - sec->leakydamage = 5; if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes From 006d3022ca60e1f8048a682668ee41a649695bba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 17:10:47 +0100 Subject: [PATCH 251/335] - changed the BFG decal for Freedoom to blue. With the software renderer this will be displayed as gray due to lack of blue in the palette. (Itz's still better than green, though.) --- wadsrc/static/filter/doom.freedoom/decaldef.z | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 wadsrc/static/filter/doom.freedoom/decaldef.z diff --git a/wadsrc/static/filter/doom.freedoom/decaldef.z b/wadsrc/static/filter/doom.freedoom/decaldef.z new file mode 100644 index 000000000..68b85a848 --- /dev/null +++ b/wadsrc/static/filter/doom.freedoom/decaldef.z @@ -0,0 +1,29 @@ + +/***** BFG Scorches ********************************************************/ + +decal BFGLightning1 +{ + pic BFGLITE1 + shade "80 80 ff" + fullbright + randomflipx + animator GoAway2 + lowerdecal BFGScorch +} + +decal BFGLightning2 +{ + pic BFGLITE2 + shade "80 80 ff" + fullbright + randomflipy + animator GoAway2 + lowerdecal BFGScorch +} + +decalgroup BFGLightning +{ + BFGLightning1 1 + BFGLightning2 1 +} + From 1c6a00059f9ede7d913d06bae7f8c4994964649b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 5 Jan 2016 20:41:59 +0100 Subject: [PATCH 252/335] - fixed: MAPINFO option fs_nocheckposition parsed the '=' twice. --- src/fragglescript/t_load.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp index eedb68f7c..cd40d809a 100644 --- a/src/fragglescript/t_load.cpp +++ b/src/fragglescript/t_load.cpp @@ -87,7 +87,6 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false) { FFsOptions *opt = info->GetOptData("fragglescript"); - parse.ParseAssign(); if (parse.CheckAssign()) { parse.sc.MustGetNumber(); From 6a63effa1fbcdb8619383c565394317869ab7ac1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 01:50:45 +0100 Subject: [PATCH 253/335] - fixed: A_CheckTerrain did not use the proper damage type for processing an instant death sector. - moved sector secret information from sector_t::special and secretsector to two flag bits in sector_t::Flags. This is to get rid of the bit masking madness in the floor/ceiling thinkers which need to preserve this bit when they change a sector's type. --- src/am_map.cpp | 8 ++++---- src/c_cmds.cpp | 7 ++----- src/g_strife/a_strifestuff.cpp | 2 +- src/p_3dfloors.cpp | 3 +-- src/p_floor.cpp | 16 ++++++++-------- src/p_lnspec.cpp | 3 +++ src/p_lnspec.h | 2 ++ src/p_plats.cpp | 4 ++-- src/p_saveg.cpp | 18 ++++++++++++++---- src/p_setup.cpp | 1 - src/p_spec.cpp | 10 +++++++--- src/p_udmf.cpp | 2 -- src/p_user.cpp | 6 ++---- src/r_defs.h | 21 ++++++++++++++++++++- src/version.h | 2 +- 15 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 81e45c685..606a65ae8 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2071,17 +2071,17 @@ static bool AM_CheckSecret(line_t *line) { if (line->frontsector != NULL) { - if (line->frontsector->secretsector) + if (line->frontsector->wasSecret()) { - if (am_map_secrets!=0 && !(line->frontsector->special&SECRET_MASK)) return true; + if (am_map_secrets!=0 && !line->frontsector->isSecret()) return true; if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true; } } if (line->backsector != NULL) { - if (line->backsector->secretsector) + if (line->backsector->wasSecret()) { - if (am_map_secrets!=0 && !(line->backsector->special&SECRET_MASK)) return true; + if (am_map_secrets!=0 && !line->backsector->isSecret()) return true; if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true; } } diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 0a9e4f0e3..57290a98a 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1106,11 +1106,8 @@ static void PrintSecretString(const char *string, bool thislevel) if (*string == ';') string++; if (thislevel && secnum >= 0 && secnum < numsectors) { - if (sectors[secnum].secretsector) - { - if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED; - else colstr = TEXTCOLOR_GREEN; - } + if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED; + else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN; else colstr = TEXTCOLOR_ORANGE; } } diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 1edea19fa..7e9330990 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -632,7 +632,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { if ((sec->special & 0xFF) == Damage_InstantDeath) { - P_DamageMobj (self, NULL, NULL, 999, NAME_None); + P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath); } else if ((sec->special & 0xFF) == Scroll_StrifeCurrent) { diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 6af26652f..3fbbfeab7 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -342,8 +342,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) } // Apply sector specials - if (rover->model->special || rover->model->damageamount) - P_PlayerInSpecialSector(player, rover->model); + P_PlayerInSpecialSector(player, rover->model); // Apply flat specials (using the ceiling!) P_PlayerOnSpecialFlat( diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 9e7806039..42372888b 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -159,7 +159,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->special = m_Sector->special | m_NewSpecial; //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -175,7 +175,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->special = m_Sector->special | m_NewSpecial; //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -240,7 +240,7 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change) m_Type = DFloor::genFloorChg; break; case 3: - m_NewSpecial = sec->special & ~SECRET_MASK; + m_NewSpecial = sec->special; m_Type = DFloor::genFloorChgT; break; } @@ -438,11 +438,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, { FTextureID oldpic = sec->GetTexture(sector_t::floor); sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK); + sec->special = line->frontsector->special; } else { - sec->special &= SECRET_MASK; + sec->special = 0; } break; @@ -454,7 +454,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, // jff 1/24/98 make sure floor->m_NewSpecial gets initialized // in case no surrounding sector is at floordestheight // --> should not affect compatibility <-- - floor->m_NewSpecial = sec->special & ~SECRET_MASK; + floor->m_NewSpecial = sec->special; //jff 5/23/98 use model subroutine to unify fixes and handling sector_t *modelsec; @@ -462,7 +462,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, if (modelsec != NULL) { floor->m_Texture = modelsec->GetTexture(sector_t::floor); - floor->m_NewSpecial = modelsec->special & ~SECRET_MASK; + floor->m_NewSpecial = modelsec->special; } break; @@ -1091,7 +1091,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (line) { // [RH] if no line, no change sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK); + sec->special = line->frontsector->special; } break; case numChangeOnly: diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 8fa8691b2..53090ef18 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1945,6 +1945,9 @@ FUNC(LS_Sector_ChangeFlags) rtn = false; FSectorTagIterator itr(arg0); + // exclude protected flags + arg1 &= ~SECF_NOMODIFY; + arg2 &= ~SECF_NOMODIFY; while ((secNum = itr.Next()) >= 0) { sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2; diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 9fb4c17b3..cb3f6bf85 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -176,10 +176,12 @@ typedef enum { // [RH] Equivalents for BOOM's generalized sector types +#ifndef SECRET_MASK #define DAMAGE_MASK 0x0300 #define SECRET_MASK 0x0400 #define FRICTION_MASK 0x0800 #define PUSH_MASK 0x1000 +#endif struct line_t; class AActor; diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 7600637b2..eecf521ee 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -281,7 +281,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, if (line) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); if (change == 1) - sec->special &= SECRET_MASK; // Stop damage and other stuff, if any + sec->special = 0; // Stop damage and other stuff, if any } switch (type) @@ -293,7 +293,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, plat->m_Low = sec->floorplane.d; plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); - sec->special &= SECRET_MASK; // NO MORE DAMAGE, IF APPLICABLE + sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE break; case DPlat::platUpByValue: diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index fdf57ddb0..fa1f395cf 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -398,15 +398,25 @@ void P_SerializeWorld (FArchive &arc) } } - arc << sec->SoundTarget + arc << sec->SoundTarget << sec->SecActTarget << sec->sky << sec->MoreFlags << sec->Flags << sec->FloorSkyBox << sec->CeilingSkyBox - << sec->ZoneNumber - << sec->secretsector - << sec->interpolations[0] + << sec->ZoneNumber; + if (SaveVersion < 4529) + { + short secretsector; + arc << secretsector; + if (secretsector) sec->Flags |= SECF_WASSECRET; + if (sec->special & SECRET_MASK) + { + sec->Flags |= SECF_SECRET; + sec->special &= ~SECRET_MASK; + } + } + arc << sec->interpolations[0] << sec->interpolations[1] << sec->interpolations[2] << sec->interpolations[3] diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 50e7f41d6..dbd0954cc 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1512,7 +1512,6 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->special = LittleShort(ms->special); else // [RH] Translate to new sector special ss->special = P_TranslateSectorSpecial (LittleShort(ms->special)); - ss->secretsector = !!(ss->special&SECRET_MASK); tagManager.AddSectorTag(i, LittleShort(ms->tag)); ss->thinglist = NULL; ss->touching_thinglist = NULL; // phares 3/14/98 diff --git a/src/p_spec.cpp b/src/p_spec.cpp index c439ac50e..d94d91ac5 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -437,7 +437,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } } - int special = sector->special & ~SECRET_MASK; + int special = sector->special; // Has hit ground. AInventory *ironfeet; @@ -574,9 +574,9 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } } - if (sector->special & SECRET_MASK) + if (sector->isSecret()) { - sector->special &= ~SECRET_MASK; + sector->ClearSecret(); P_GiveSecret(player->mo, true, true, int(sector - sectors)); } } @@ -1189,7 +1189,11 @@ void P_SpawnSpecials (void) // [RH] All secret sectors are marked with a BOOM-ish bitfield if (sector->special & SECRET_MASK) + { + sector->Flags |= SECF_SECRET | SECF_WASSECRET; + sector->special &= ~SECRET_MASK; level.total_secrets++; + } switch (sector->special & 0xff) { diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 2169da49f..128225e4a 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1567,8 +1567,6 @@ public: if (sc.Number != 0) tagManager.AddSectorTag(index, sc.Number); } } - - sec->secretsector = !!(sec->special&SECRET_MASK); // Reset the planes to their defaults if not all of the plane equation's parameters were found. if (fplaneflags != 15) diff --git a/src/p_user.cpp b/src/p_user.cpp index 8f8a93fdb..922cc2a1c 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2538,10 +2538,8 @@ void P_PlayerThink (player_t *player) if (!(player->cheats & CF_PREDICTING)) { P_PlayerOnSpecial3DFloor (player); - if (player->mo->Sector->special || player->mo->Sector->damageamount != 0) - { - P_PlayerInSpecialSector (player); - } + P_PlayerInSpecialSector (player); + if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint( player->mo->x, player->mo->y) || player->mo->waterlevel) diff --git a/src/r_defs.h b/src/r_defs.h index 89449f446..0c873beeb 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -355,6 +355,12 @@ enum SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. SECF_NORESPAWN = 8, // players can not respawn in this sector + + + SECF_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET // not modifiable by Sector_ChangeFlags }; enum @@ -642,6 +648,20 @@ struct sector_t return pos == floor? floorplane:ceilingplane; } + bool isSecret() const + { + return !!(Flags & SECF_SECRET); + } + + bool wasSecret() const + { + return !!(Flags & SECF_WASSECRET); + } + + void ClearSecret() + { + Flags &= ~SECF_SECRET; + } bool PlaneMoving(int pos); @@ -729,7 +749,6 @@ struct sector_t // regular sky. TObjPtr FloorSkyBox, CeilingSkyBox; - short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap) int sectornum; // for comparing sector copies extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. diff --git a/src/version.h b/src/version.h index d7026786e..b10074f41 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4528 +#define SAVEVER 4529 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 3ffcec3eb3446eda1615d277104b6822fd0af69d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 02:01:59 +0100 Subject: [PATCH 254/335] - moved friction flag from special to Flags as well. --- src/p_map.cpp | 2 +- src/p_saveg.cpp | 6 +++++- src/p_spec.cpp | 12 ++++++++---- src/r_defs.h | 1 + 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 5dd0967b9..f409dafa4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -630,7 +630,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) } } - if (!(sec->special & FRICTION_MASK) && + if (!(sec->Flags & SECF_FRICTION) && Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0) { continue; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index fa1f395cf..16109891b 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -413,8 +413,12 @@ void P_SerializeWorld (FArchive &arc) if (sec->special & SECRET_MASK) { sec->Flags |= SECF_SECRET; - sec->special &= ~SECRET_MASK; } + if (sec->special & FRICTION_MASK) + { + sec->Flags |= SECF_FRICTION; + } + sec->special &= ~(SECRET_MASK|FRICTION_MASK); } arc << sec->interpolations[0] << sec->interpolations[1] diff --git a/src/p_spec.cpp b/src/p_spec.cpp index d94d91ac5..a5bdfffd4 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1191,9 +1191,13 @@ void P_SpawnSpecials (void) if (sector->special & SECRET_MASK) { sector->Flags |= SECF_SECRET | SECF_WASSECRET; - sector->special &= ~SECRET_MASK; level.total_secrets++; } + if (sector->special & FRICTION_MASK) + { + sector->Flags |= SECF_FRICTION; + } + sector->special &= ~(SECRET_MASK|FRICTION_MASK); switch (sector->special & 0xff) { @@ -1262,7 +1266,7 @@ void P_SpawnSpecials (void) sector->friction = FRICTION_LOW; sector->movefactor = 0x269; sector->special &= 0xff00; - sector->special |= FRICTION_MASK; + sector->Flags |= SECF_FRICTION; break; // [RH] Hexen-like phased lighting @@ -2060,11 +2064,11 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag) // can be enabled and disabled at will. if (friction == ORIG_FRICTION) { - sectors[s].special &= ~FRICTION_MASK; + sectors[s].Flags &= ~SECF_FRICTION; } else { - sectors[s].special |= FRICTION_MASK; + sectors[s].Flags |= SECF_FRICTION; } } } diff --git a/src/r_defs.h b/src/r_defs.h index 0c873beeb..014fa1b32 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -355,6 +355,7 @@ enum SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled SECF_WASSECRET = 1 << 30, // a secret that was discovered From d34077a3ba50b0953c02ec67c30257fb6ca664a3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 02:05:39 +0100 Subject: [PATCH 255/335] - ... and finally the push flag. --- src/p_lnspec.h | 2 -- src/p_saveg.cpp | 6 +++++- src/p_spec.cpp | 8 ++++++-- src/r_defs.h | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/p_lnspec.h b/src/p_lnspec.h index cb3f6bf85..9fb4c17b3 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -176,12 +176,10 @@ typedef enum { // [RH] Equivalents for BOOM's generalized sector types -#ifndef SECRET_MASK #define DAMAGE_MASK 0x0300 #define SECRET_MASK 0x0400 #define FRICTION_MASK 0x0800 #define PUSH_MASK 0x1000 -#endif struct line_t; class AActor; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 16109891b..2547933bc 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -418,7 +418,11 @@ void P_SerializeWorld (FArchive &arc) { sec->Flags |= SECF_FRICTION; } - sec->special &= ~(SECRET_MASK|FRICTION_MASK); + if (sec->special & PUSH_MASK) + { + sec->Flags |= SECF_PUSH; + } + sec->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK); } arc << sec->interpolations[0] << sec->interpolations[1] diff --git a/src/p_spec.cpp b/src/p_spec.cpp index a5bdfffd4..493e3e157 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1197,7 +1197,11 @@ void P_SpawnSpecials (void) { sector->Flags |= SECF_FRICTION; } - sector->special &= ~(SECRET_MASK|FRICTION_MASK); + if (sector->special & PUSH_MASK) + { + sector->Flags |= SECF_PUSH; + } + sector->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK); switch (sector->special & 0xff) { @@ -2184,7 +2188,7 @@ void DPusher::Tick () // Be sure the special sector type is still turned on. If so, proceed. // Else, bail out; the sector type has been changed on us. - if (!(sec->special & PUSH_MASK)) + if (!(sec->Flags & SECF_PUSH)) return; // For constant pushers (wind/current) there are 3 situations: diff --git a/src/r_defs.h b/src/r_defs.h index 014fa1b32..d5321a0c3 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -356,6 +356,7 @@ enum SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. SECF_NORESPAWN = 8, // players can not respawn in this sector SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled SECF_WASSECRET = 1 << 30, // a secret that was discovered From b0db5d9b169b858a7b0a5ef265474c36a29afd00 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 02:16:33 +0100 Subject: [PATCH 256/335] - added a SECF_SILENTMOVE flag. Since Eternity got this it's a good candidate for a potential Super-Boom standard, and it's also useful for silencing a sector temporarily without removing the sound sequence. --- src/p_ceiling.cpp | 1 + src/p_doors.cpp | 2 ++ src/p_floor.cpp | 2 ++ src/p_pillar.cpp | 23 +++++++++++++---------- src/p_plats.cpp | 2 ++ src/r_defs.h | 1 + 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 7efef80a5..37cf91b47 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -90,6 +90,7 @@ void DCeiling::Serialize (FArchive &arc) void DCeiling::PlayCeilingSound () { + if (m_Sector->Flags & SECF_SILENTMOVE) return; if (m_Sector->seqType >= 0) { SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false); diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 49ed20f46..f01f2beeb 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -250,6 +250,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const choice = !raise; + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Speed >= FRACUNIT*8) { choice += 2; diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 42372888b..e9febae66 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -55,6 +55,8 @@ inline FArchive &operator<< (FArchive &arc, DFloor::EFloor &type) static void StartFloorSound (sector_t *sec) { + if (sec->Flags & SECF_SILENTMOVE) return; + if (sec->seqType >= 0) { SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0); diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 884218bee..b1cae3af9 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -198,17 +198,20 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed, m_FloorSpeed = Scale (speed, floordist, ceilingdist); } - if (sector->seqType >= 0) + if (!(m_Sector->Flags & SECF_SILENTMOVE)) { - SN_StartSequence (sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); - } - else if (sector->SeqName != NAME_None) - { - SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0); - } - else - { - SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0); + if (sector->seqType >= 0) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); + } + else if (sector->SeqName != NAME_None) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0); + } + else + { + SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0); + } } } diff --git a/src/p_plats.cpp b/src/p_plats.cpp index eecf521ee..280eb415c 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -72,6 +72,8 @@ void DPlat::Serialize (FArchive &arc) void DPlat::PlayPlatSound (const char *sound) { + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Sector->seqType >= 0) { SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0); diff --git a/src/r_defs.h b/src/r_defs.h index d5321a0c3..3a024831c 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -357,6 +357,7 @@ enum SECF_NORESPAWN = 8, // players can not respawn in this sector SECF_FRICTION = 16, // sector has friction enabled SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) SECF_WASSECRET = 1 << 30, // a secret that was discovered From 5474e01de8c1153c25c7d9968e4d435c54933ad9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 12:12:47 +0100 Subject: [PATCH 257/335] - removed FraggleScript's 'sectortype' function. This was GZDoom exclusive and never documented so it got no public exposure. Since this is incompatible with the damage related changes, it has no more use. - major overhaul of the static sector damage system: * consolidated special based damage, Sector_SetDamage and UDMF properties into one set of damage properties. The parallel handling that could lead to double damage infliction was removed. This also means that damage through sector specials can be retroactively changed through Sector_SetDamage. * all special cases were turned into flags. The new system can switch between Strife's delayed damage and regular damage, and it can also set whether terrain splashes are used or not. It also has access to the special properties of the end-level type (i.e. switching off god mode and ending the level.) * the damage related flags are accessible through Sector_ChangeFlags, not the damage functions themselves. --- specs/udmf_zdoom.txt | 7 +- src/b_move.cpp | 18 +- src/fragglescript/t_func.cpp | 34 +-- src/namedef.h | 2 + src/p_doors.cpp | 3 - src/p_interaction.cpp | 3 +- src/p_spec.cpp | 514 +++++++++++++++++------------------ src/p_udmf.cpp | 18 ++ src/r_defs.h | 6 +- 9 files changed, 282 insertions(+), 323 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index f20525d13..74d5fb4f7 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -204,10 +204,15 @@ Note: All fields default to false unless mentioned otherwise. hidden = ; // if true this sector will not be drawn on the textured automap. waterzone = ; // Sector is under water and swimmable moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") - damageamount = ; // Amount of damage inflicted by this sector, default = 0 + damageamount = ; // Amount of damage inflicted by this sector, default = 0. If this is 0, all other damage properties will be ignored. + // Setting damage through these properties will override any damage set through 'special'. + // Setting damageamount to a negative value will create a healing sector. damagetype = ; // Damage type for sector damage, Default = "None". (generic damage) damageinterval = ; // Interval in tics between damage application, default = 32. leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. + damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false. + damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. + * Note about dropactors diff --git a/src/b_move.cpp b/src/b_move.cpp index 2a76f1925..4759f22d9 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -354,21 +354,5 @@ void DBot::Pitch (AActor *target) //Checks if a sector is dangerous. bool FCajunMaster::IsDangerous (sector_t *sec) { - int special; - - return - sec->damageamount - || sec->special & DAMAGE_MASK - || (special = sec->special & 0xff, special == dLight_Strobe_Hurt) - || special == dDamage_Hellslime - || special == dDamage_Nukage - || special == dDamage_End - || special == dDamage_SuperHellslime - || special == dDamage_LavaWimpy - || special == dDamage_LavaHefty - || special == dScroll_EastLavaDamage - || special == hDamage_Sludge - || special == sLight_Strobe_Hurt - || special == Damage_InstantDeath - || special == sDamage_SuperHellslime; + return sec->damageamount > 0; } diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 7e05be8da..fdf904764 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -4323,44 +4323,12 @@ void FParser::SF_KillInSector() //========================================================================== // // new for GZDoom: Sets a sector's type -// (Sure, this is not particularly useful. But having it made it possible -// to fix a few annoying bugs in some old maps ;) ) // //========================================================================== void FParser::SF_SectorType(void) { - int tagnum, secnum; - sector_t *sector; - - if (CheckArgs(1)) - { - tagnum = intvalue(t_argv[0]); - - // argv is sector tag - secnum = T_FindFirstSectorFromTag(tagnum); - - if(secnum < 0) - { script_error("sector not found with tagnum %i\n", tagnum); return;} - - sector = §ors[secnum]; - - if(t_argc > 1) - { - int i = -1; - int spec = intvalue(t_argv[1]); - - // set all sectors with tag - FSSectorTagIterator itr(tagnum); - while ((i = itr.Next()) >= 0) - { - sectors[i].special = spec; - } - } - - t_return.type = svt_int; - t_return.value.i = sector->special; - } + // I don't think this was ever used publicly so I'm not going to bother fixing it. } //========================================================================== diff --git a/src/namedef.h b/src/namedef.h index cad58bfa3..9ca8cb8ed 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -510,6 +510,8 @@ xx(damageamount) xx(damagetype) xx(damageinterval) xx(leakiness) +xx(damageterraineffect) +xx(damagehazard) // USDF keywords xx(Amount) diff --git a/src/p_doors.cpp b/src/p_doors.cpp index f01f2beeb..bce324902 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -513,8 +513,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) fixed_t height; DDoor *door = new DDoor (sec); - sec->special = 0; - door->m_Sector = sec; door->m_Direction = 0; door->m_Type = DDoor::doorRaise; @@ -535,7 +533,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) void P_SpawnDoorRaiseIn5Mins (sector_t *sec) { - sec->special = 0; new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0); } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 203d1688d..b2e27adc8 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1255,8 +1255,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } // end of game hell hack - if ((target->Sector->special & 255) == dDamage_End - && damage >= target->health) + if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health) { damage = target->health - 1; } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 493e3e157..807e6e64b 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -442,135 +442,40 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) // Has hit ground. AInventory *ironfeet; - // Allow subclasses. Better would be to implement it as armor and let that reduce - // the damage as part of the normal damage procedure. Unfortunately, I don't have - // different damage types yet, so that's not happening for now. - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) - { - if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) - break; - } - - // [RH] Normal DOOM special or BOOM specialized? - if (special >= dLight_Flicker && special <= 255) - { - switch (special) - { - case Sector_Heal: - // CoD's healing sector - if (!(level.time & 0x1f)) - P_GiveBody (player->mo, 1); - break; - - case Damage_InstantDeath: - // Strife's instant death sector - P_DamageMobj (player->mo, NULL, NULL, 999, NAME_InstantDeath); - break; - - case dDamage_Hellslime: - // HELLSLIME DAMAGE - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime); - break; - - case dDamage_Nukage: - // NUKAGE DAMAGE - case sLight_Strobe_Hurt: - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); - break; - - case hDamage_Sludge: - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 4, NAME_Slime); - break; - - case dDamage_SuperHellslime: - // SUPER HELLSLIME DAMAGE - case dLight_Strobe_Hurt: - // STROBE HURT - if (ironfeet == NULL || pr_playerinspecialsector() < 5) - { - if (!(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime); - } - break; - - case sDamage_Hellslime: - if (ironfeet == NULL) - player->hazardcount += 2; - break; - - case sDamage_SuperHellslime: - if (ironfeet == NULL) - player->hazardcount += 4; - break; - - case dDamage_End: - // EXIT SUPER DAMAGE! (for E1M8 finale) - player->cheats &= ~CF_GODMODE; - - if (!(level.time & 0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_None); - - if (player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) - G_ExitLevel(0, false); - break; - - case dDamage_LavaWimpy: - case dScroll_EastLavaDamage: - if (!(level.time & 15)) - { - P_DamageMobj(player->mo, NULL, NULL, 5, NAME_Fire); - P_HitFloor(player->mo); - } - break; - - case dDamage_LavaHefty: - if(!(level.time & 15)) - { - P_DamageMobj(player->mo, NULL, NULL, 8, NAME_Fire); - P_HitFloor(player->mo); - } - break; - - default: - // [RH] Ignore unknown specials - break; - } - } - else - { - //jff 3/14/98 handle extended sector types for secrets and damage - switch (special & DAMAGE_MASK) - { - case 0x000: // no damage - break; - case 0x100: // 2/5 damage per 31 ticks - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Fire); - break; - case 0x200: // 5/10 damage per 31 ticks - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime); - break; - case 0x300: // 10/20 damage per 31 ticks - if (ironfeet == NULL - || pr_playerinspecialsector() < 5) // take damage even with suit - { - if (!(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime); - } - break; - } - } - // [RH] Apply any customizable damage - if (sector->damageamount != 0) + if (sector->damageamount > 0) { + // Allow subclasses. Better would be to implement it as armor and let that reduce + // the damage as part of the normal damage procedure. Unfortunately, I don't have + // different damage types yet, so that's not happening for now. + for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) + { + if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) + break; + } + + if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; if (level.time % sector->damageinterval == 0 && (ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) { - P_DamageMobj (player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + if (sector->Flags & SECF_HAZARD) + { + player->hazardcount += sector->damageamount; + } + else + { + P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) + { + G_ExitLevel(0, false); + } + } + } + } + else if (sector->damageamount < 0) + { + if (level.time % sector->damageinterval == 0) + { + P_GiveBody(player->mo, -sector->damageamount, 100); } } @@ -1167,6 +1072,223 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) } +// +// P_SetSectorDamage +// +// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties +// + +static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) +{ + // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. + if (sector->damageamount == 0) + { + sector->damageamount = damage; + sector->damageinterval = MAX(1, interval); + sector->leakydamage = leakchance; + sector->damagetype = type; + sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS); + } +} + +// +// P_InitSectorSpecial +// +// Sets up everything derived from 'sector->special' for one sector +// ('fromload' is necessary to allow conversion upon savegame load.) +// + +void P_InitSectorSpecial(sector_t *sector, int special) +{ + // [RH] All secret sectors are marked with a BOOM-ish bitfield + if (sector->special & SECRET_MASK) + { + sector->Flags |= SECF_SECRET | SECF_WASSECRET; + level.total_secrets++; + } + if (sector->special & FRICTION_MASK) + { + sector->Flags |= SECF_FRICTION; + } + if (sector->special & PUSH_MASK) + { + sector->Flags |= SECF_PUSH; + } + if ((sector->special & DAMAGE_MASK) == 0x100) + { + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + } + sector->special &= 0xff; + + // [RH] Normal DOOM special or BOOM specialized? + bool keepspecial = false; + switch (sector->special) + { + case Light_Phased: + new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); + break; + + // [RH] Hexen-like phased lighting + case LightSequenceStart: + new DPhased (sector); + break; + + case dLight_Flicker: + new DLightFlash (sector); + break; + + case dLight_StrobeFast: + new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case dLight_StrobeSlow: + new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); + break; + + case dLight_Strobe_Hurt: + new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dDamage_Hellslime: + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + break; + + case dDamage_Nukage: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + break; + + case dLight_Glow: + new DGlow (sector); + break; + + case dSector_DoorCloseIn30: + P_SpawnDoorCloseIn30 (sector); + break; + + case dDamage_End: + P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL); + break; + + case dLight_StrobeSlowSync: + new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); + break; + + case dLight_StrobeFastSync: + new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); + break; + + case dSector_DoorRaiseIn5Mins: + P_SpawnDoorRaiseIn5Mins (sector); + break; + + case dFriction_Low: + sector->friction = FRICTION_LOW; + sector->movefactor = 0x269; + sector->Flags |= SECF_FRICTION; + break; + + case dDamage_SuperHellslime: + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dLight_FireFlicker: + new DFireFlicker (sector); + break; + + case dDamage_LavaWimpy: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dDamage_LavaHefty: + P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dScroll_EastLavaDamage: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3, + 0, -1, int(sector-sectors), 0); + break; + + case hDamage_Sludge: + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0); + break; + + case sLight_Strobe_Hurt: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case sDamage_Hellslime: + P_SetupSectorDamage(sector, 2, 1, 0, NAME_None, SECF_HAZARD); + break; + + case Damage_InstantDeath: + // Strife's instant death sector + P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0); + break; + + case sDamage_SuperHellslime: + P_SetupSectorDamage(sector, 4, 1, 0, NAME_None, SECF_HAZARD); + break; + + case Sector_Hidden: + sector->MoreFlags |= SECF_HIDDEN; + break; + + case Sector_Heal: + // CoD's healing sector + P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0); + break; + + case Sky2: + sector->sky = PL_SKYFLAT; + break; + + default: + if (sector->special >= Scroll_North_Slow && + sector->special <= Scroll_SouthWest_Fast) + { // Hexen scroll special + static const char hexenScrollies[24][2] = + { + { 0, 1 }, { 0, 2 }, { 0, 4 }, + { -1, 0 }, { -2, 0 }, { -4, 0 }, + { 0, -1 }, { 0, -2 }, { 0, -4 }, + { 1, 0 }, { 2, 0 }, { 4, 0 }, + { 1, 1 }, { 2, 2 }, { 4, 4 }, + { -1, 1 }, { -2, 2 }, { -4, 4 }, + { -1, -1 }, { -2, -2 }, { -4, -4 }, + { 1, -1 }, { 2, -2 }, { 4, -4 } + }; + + int i = (sector->special & 0xff) - Scroll_North_Slow; + fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); + fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); + new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); + } + else if (sector->special >= Carry_East5 && + sector->special <= Carry_East35) + { // Heretic scroll special + // Only east scrollers also scroll the texture + new DScroller (DScroller::sc_floor, + (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5), + 0, -1, int(sector-sectors), 0); + } + else keepspecial = true; + break; + } + if (!keepspecial) sector->special = 0; +} + // // P_SpawnSpecials // @@ -1187,147 +1309,7 @@ void P_SpawnSpecials (void) if (sector->special == 0) continue; - // [RH] All secret sectors are marked with a BOOM-ish bitfield - if (sector->special & SECRET_MASK) - { - sector->Flags |= SECF_SECRET | SECF_WASSECRET; - level.total_secrets++; - } - if (sector->special & FRICTION_MASK) - { - sector->Flags |= SECF_FRICTION; - } - if (sector->special & PUSH_MASK) - { - sector->Flags |= SECF_PUSH; - } - sector->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK); - - switch (sector->special & 0xff) - { - // [RH] Normal DOOM/Hexen specials. We clear off the special for lights - // here instead of inside the spawners. - - case dLight_Flicker: - // FLICKERING LIGHTS - new DLightFlash (sector); - sector->special &= 0xff00; - break; - - case dLight_StrobeFast: - // STROBE FAST - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - sector->special &= 0xff00; - break; - - case dLight_StrobeSlow: - // STROBE SLOW - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); - sector->special &= 0xff00; - break; - - case dLight_Strobe_Hurt: - case sLight_Strobe_Hurt: - // STROBE FAST/DEATH SLIME - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - break; - - case dLight_Glow: - // GLOWING LIGHT - new DGlow (sector); - sector->special &= 0xff00; - break; - - case dSector_DoorCloseIn30: - // DOOR CLOSE IN 30 SECONDS - P_SpawnDoorCloseIn30 (sector); - break; - - case dLight_StrobeSlowSync: - // SYNC STROBE SLOW - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); - sector->special &= 0xff00; - break; - - case dLight_StrobeFastSync: - // SYNC STROBE FAST - new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); - sector->special &= 0xff00; - break; - - case dSector_DoorRaiseIn5Mins: - // DOOR RAISE IN 5 MINUTES - P_SpawnDoorRaiseIn5Mins (sector); - break; - - case dLight_FireFlicker: - // fire flickering - new DFireFlicker (sector); - sector->special &= 0xff00; - break; - - case dFriction_Low: - sector->friction = FRICTION_LOW; - sector->movefactor = 0x269; - sector->special &= 0xff00; - sector->Flags |= SECF_FRICTION; - break; - - // [RH] Hexen-like phased lighting - case LightSequenceStart: - new DPhased (sector); - break; - - case Light_Phased: - new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); - break; - - case Sky2: - sector->sky = PL_SKYFLAT; - break; - - case dScroll_EastLavaDamage: - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3, - 0, -1, int(sector-sectors), 0); - break; - - case Sector_Hidden: - sector->MoreFlags |= SECF_HIDDEN; - sector->special &= 0xff00; - break; - - default: - if ((sector->special & 0xff) >= Scroll_North_Slow && - (sector->special & 0xff) <= Scroll_SouthWest_Fast) - { // Hexen scroll special - static const char hexenScrollies[24][2] = - { - { 0, 1 }, { 0, 2 }, { 0, 4 }, - { -1, 0 }, { -2, 0 }, { -4, 0 }, - { 0, -1 }, { 0, -2 }, { 0, -4 }, - { 1, 0 }, { 2, 0 }, { 4, 0 }, - { 1, 1 }, { 2, 2 }, { 4, 4 }, - { -1, 1 }, { -2, 2 }, { -4, 4 }, - { -1, -1 }, { -2, -2 }, { -4, -4 }, - { 1, -1 }, { 2, -2 }, { 4, -4 } - }; - - int i = (sector->special & 0xff) - Scroll_North_Slow; - fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); - fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); - new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); - } - else if ((sector->special & 0xff) >= Carry_East5 && - (sector->special & 0xff) <= Carry_East35) - { // Heretic scroll special - // Only east scrollers also scroll the texture - new DScroller (DScroller::sc_floor, - (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5), - 0, -1, int(sector-sectors), 0); - } - break; - } + P_InitSectorSpecial(sector, sector->special); } // Init other misc stuff diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 128225e4a..64536fff4 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1542,6 +1542,14 @@ public: sec->leakydamage = CheckInt(key); break; + case NAME_damageterraineffect: + Flag(sec->Flags, SECF_DMGTERRAINFX, key); + break; + + case NAME_damagehazard: + Flag(sec->Flags, SECF_HAZARD, key); + break; + case NAME_MoreIds: // delay parsing of the tag string until parsing of the sector is complete // This ensures that the ID is always the first tag in the list. @@ -1567,6 +1575,16 @@ public: if (sc.Number != 0) tagManager.AddSectorTag(index, sc.Number); } } + + if (sec->damageamount == 0) + { + // If no damage is set, clear all other related properties so that they do not interfere + // with other means of setting them. + sec->damagetype = NAME_None; + sec->damageinterval = 0; + sec->leakydamage = 0; + sec->Flags &= ~SECF_DAMAGEFLAGS; + } // Reset the planes to their defaults if not all of the plane equation's parameters were found. if (fplaneflags != 15) diff --git a/src/r_defs.h b/src/r_defs.h index 3a024831c..e4b404687 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -358,11 +358,15 @@ enum SECF_FRICTION = 16, // sector has friction enabled SECF_PUSH = 32, // pushers enabled SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) - + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode + SECF_ENDLEVEL = 512, // ends level when health goes below 10 + SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET // not modifiable by Sector_ChangeFlags }; From 73f4e013f18116010a85f7c2c44c62098e9ae123 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 6 Jan 2016 13:26:05 +0200 Subject: [PATCH 258/335] Font kerning is no longer ignored in intermission screen See http://forum.zdoom.org/viewtopic.php?t=50304 --- src/intermission/intermission.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 2a52df58a..a19d0a479 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -329,6 +329,7 @@ void DIntermissionScreenText::Drawer () int c; const FRemapTable *range; const char *ch = mText; + const int kerning = SmallFont->GetDefaultKerning(); // Count number of rows in this text. Since it does not word-wrap, we just count // line feed characters. @@ -380,6 +381,7 @@ void DIntermissionScreenText::Drawer () } pic = SmallFont->GetChar (c, &w); + w += kerning; w *= CleanXfac; if (cx + w > SCREENWIDTH) continue; From 1ee441412a7c8b30d616324a31d490c279e230f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 12:31:27 +0100 Subject: [PATCH 259/335] - add savegame compatibility handling for damage related changes: When loading an old savegame the sector specials must be reinitialized to set the damage properties. --- src/p_lights.cpp | 3 +-- src/p_saveg.cpp | 13 +------------ src/p_spec.cpp | 40 ++++++++++++++++++++++------------------ src/p_spec.h | 1 + 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/p_lights.cpp b/src/p_lights.cpp index 49ef130e8..7d56bce95 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -791,7 +791,7 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev index + 1, l->m_BaseLevel, sector); l->m_Phase = ((numsteps - index - 1) * 64) / numsteps; - sector->special &= 0xff00; + sector->special = 0; return numsteps; } @@ -820,7 +820,6 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase) { m_BaseLevel = baselevel; m_Phase = phase; - sector->special &= 0xff00; } //============================================================================ diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 2547933bc..21e6605b9 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -410,19 +410,8 @@ void P_SerializeWorld (FArchive &arc) short secretsector; arc << secretsector; if (secretsector) sec->Flags |= SECF_WASSECRET; - if (sec->special & SECRET_MASK) - { - sec->Flags |= SECF_SECRET; - } - if (sec->special & FRICTION_MASK) - { - sec->Flags |= SECF_FRICTION; - } - if (sec->special & PUSH_MASK) - { - sec->Flags |= SECF_PUSH; - } sec->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK); + P_InitSectorSpecial(sec, sec->special, true); } arc << sec->interpolations[0] << sec->interpolations[1] diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 807e6e64b..789e44a27 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1098,7 +1098,7 @@ static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int // ('fromload' is necessary to allow conversion upon savegame load.) // -void P_InitSectorSpecial(sector_t *sector, int special) +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) { // [RH] All secret sectors are marked with a BOOM-ish bitfield if (sector->special & SECRET_MASK) @@ -1133,28 +1133,28 @@ void P_InitSectorSpecial(sector_t *sector, int special) switch (sector->special) { case Light_Phased: - new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); + if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); break; // [RH] Hexen-like phased lighting case LightSequenceStart: - new DPhased (sector); + if (!nothinkers) new DPhased (sector); break; case dLight_Flicker: - new DLightFlash (sector); + if (!nothinkers) new DLightFlash (sector); break; case dLight_StrobeFast: - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); break; case dLight_StrobeSlow: - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); break; case dLight_Strobe_Hurt: - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); break; @@ -1167,7 +1167,7 @@ void P_InitSectorSpecial(sector_t *sector, int special) break; case dLight_Glow: - new DGlow (sector); + if (!nothinkers) new DGlow (sector); break; case dSector_DoorCloseIn30: @@ -1179,11 +1179,11 @@ void P_InitSectorSpecial(sector_t *sector, int special) break; case dLight_StrobeSlowSync: - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); break; case dLight_StrobeFastSync: - new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); break; case dSector_DoorRaiseIn5Mins: @@ -1201,7 +1201,7 @@ void P_InitSectorSpecial(sector_t *sector, int special) break; case dLight_FireFlicker: - new DFireFlicker (sector); + if (!nothinkers) new DFireFlicker (sector); break; case dDamage_LavaWimpy: @@ -1214,9 +1214,12 @@ void P_InitSectorSpecial(sector_t *sector, int special) case dScroll_EastLavaDamage: P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3, - 0, -1, int(sector-sectors), 0); + if (!nothinkers) + { + new DStrobe(sector, STROBEBRIGHT, FASTDARK, false); + new DScroller(DScroller::sc_floor, (-FRACUNIT / 2) << 3, + 0, -1, int(sector - sectors), 0); + } break; case hDamage_Sludge: @@ -1225,7 +1228,7 @@ void P_InitSectorSpecial(sector_t *sector, int special) case sLight_Strobe_Hurt: P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); break; case sDamage_Hellslime: @@ -1270,16 +1273,17 @@ void P_InitSectorSpecial(sector_t *sector, int special) { 1, -1 }, { 2, -2 }, { 4, -4 } }; + int i = (sector->special & 0xff) - Scroll_North_Slow; fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); - new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); + if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); } else if (sector->special >= Carry_East5 && sector->special <= Carry_East35) { // Heretic scroll special // Only east scrollers also scroll the texture - new DScroller (DScroller::sc_floor, + if (!nothinkers) new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5), 0, -1, int(sector-sectors), 0); } @@ -1309,7 +1313,7 @@ void P_SpawnSpecials (void) if (sector->special == 0) continue; - P_InitSectorSpecial(sector, sector->special); + P_InitSectorSpecial(sector, sector->special, false); } // Init other misc stuff diff --git a/src/p_spec.h b/src/p_spec.h index 0c3ee8745..da508fda1 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -158,6 +158,7 @@ bool PIT_PushThing (AActor *thing); bool CheckIfExitIsGood (AActor *self, level_info_t *info); // at map load +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers); void P_SpawnSpecials (void); // every tic From bd8513c063e2451e7d075e803efd10aae9ec8f09 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 12:56:35 +0100 Subject: [PATCH 260/335] - made sector_t::damageamount an int so that it can hold TELEFRAG_DAMAGE. - marked all places where sector_t::special needs to be addressed for the damage overhaul. NOTE: This commit will not compile! --- src/g_shared/a_lightning.cpp | 2 +- src/g_strife/a_strifestuff.cpp | 4 ++-- src/p_ceiling.cpp | 8 ++++---- src/p_floor.cpp | 20 ++++++++++---------- src/p_lights.cpp | 2 +- src/p_mobj.cpp | 4 ++-- src/p_plats.cpp | 4 ++-- src/p_saveg.cpp | 13 +++++++++++-- src/p_sectors.cpp | 2 +- src/p_setup.cpp | 2 +- src/p_spec.cpp | 9 ++++----- src/p_udmf.cpp | 8 ++++---- src/r_defs.h | 2 +- 13 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index e7c598d3e..33d51c02d 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -139,7 +139,7 @@ void DLightningThinker::LightningFlash () for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec) { // allow combination of the lightning sector specials with bit masks - int special = tempSec->special & 0xff; + int special = tempSec->special; if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum || special == Light_IndoorLightning1 || special == Light_IndoorLightning2 diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 7e9330990..05f6367dc 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -630,11 +630,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) if (self->z == sec->floorplane.ZatPoint (self->x, self->y)) { - if ((sec->special & 0xFF) == Damage_InstantDeath) + if (sec->special == Damage_InstantDeath) { P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath); } - else if ((sec->special & 0xFF) == Scroll_StrifeCurrent) + else if (sec->special == Scroll_StrifeCurrent) { int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; fixed_t speed = (anglespeed % 10) << (FRACBITS - 4); diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 37cf91b47..b8a3ead7b 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -143,7 +143,7 @@ void DCeiling::Tick () // movers with texture change, change the texture then get removed case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->xspecial = m_NewSpecial; // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -176,7 +176,7 @@ void DCeiling::Tick () // then remove the active ceiling case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->xspecial = m_NewSpecial; // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -440,7 +440,7 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = sec->special; + ceiling->m_NewSpecial = sec->xspecial; ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone @@ -459,7 +459,7 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = line->frontsector->special; + ceiling->m_NewSpecial = line->frontsector->xspecial; ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone diff --git a/src/p_floor.cpp b/src/p_floor.cpp index e9febae66..c570bff4a 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -161,7 +161,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->special = m_Sector->special | m_NewSpecial; + m_Sector->xspecial = m_Sector->xspecial | m_NewSpecial; //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -177,7 +177,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->special = m_Sector->special | m_NewSpecial; + m_Sector->xspecial = m_Sector->xspecial | m_NewSpecial; //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -242,7 +242,7 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change) m_Type = DFloor::genFloorChg; break; case 3: - m_NewSpecial = sec->special; + m_NewSpecial = sec->xspecial; m_Type = DFloor::genFloorChgT; break; } @@ -440,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, { FTextureID oldpic = sec->GetTexture(sector_t::floor); sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = line->frontsector->special; + sec->xspecial = line->frontsector->xspecial; } else { - sec->special = 0; + sec->xspecial = 0; } break; @@ -456,7 +456,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, // jff 1/24/98 make sure floor->m_NewSpecial gets initialized // in case no surrounding sector is at floordestheight // --> should not affect compatibility <-- - floor->m_NewSpecial = sec->special; + floor->m_NewSpecial = sec->xspecial; //jff 5/23/98 use model subroutine to unify fixes and handling sector_t *modelsec; @@ -464,7 +464,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, if (modelsec != NULL) { floor->m_Texture = modelsec->GetTexture(sector_t::floor); - floor->m_NewSpecial = modelsec->special; + floor->m_NewSpecial = modelsec->xspecial; } break; @@ -637,7 +637,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, { // [RH] Find the next sector by scanning for Stairs_Special? tsec = sec->NextSpecialSector ( - (sec->special & 0xff) == Stairs_Special1 ? + sec->special == Stairs_Special1 ? Stairs_Special2 : Stairs_Special1, prev); if ( (ok = (tsec != NULL)) ) @@ -1093,7 +1093,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (line) { // [RH] if no line, no change sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = line->frontsector->special; + sec->xspecial = line->frontsector->xspecial; } break; case numChangeOnly: @@ -1101,7 +1101,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (secm) { // if no model, no change sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor)); - sec->special = secm->special; + sec->xspecial = secm->xspecial; } break; default: diff --git a/src/p_lights.cpp b/src/p_lights.cpp index 7d56bce95..656b86112 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -786,7 +786,7 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev l = new DPhased (sector, baselevel); int numsteps = PhaseHelper (sector->NextSpecialSector ( - (sector->special & 0x00ff) == LightSequenceSpecial1 ? + sector->special == LightSequenceSpecial1 ? LightSequenceSpecial2 : LightSequenceSpecial1, prev), index + 1, l->m_BaseLevel, sector); l->m_Phase = ((numsteps - index - 1) * 64) / numsteps; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bc314dc0e..2ded3daf2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3452,7 +3452,7 @@ void AActor::Tick () if (player != NULL) { - int scrolltype = sec->special & 0xff; + int scrolltype = sec->special; if (scrolltype >= Scroll_North_Slow && scrolltype <= Scroll_SouthWest_Fast) @@ -4424,7 +4424,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) ( gameaction != ga_worlddone ) && ( p->mo != NULL ) && ( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && - ( (p->mo->Sector->special & 255) != Damage_InstantDeath )) + ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) { spawn_x = p->mo->x; spawn_y = p->mo->y; diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 280eb415c..467559e63 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -283,7 +283,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, if (line) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); if (change == 1) - sec->special = 0; // Stop damage and other stuff, if any + sec->xspecial = 0; // Stop damage and other stuff, if any } switch (type) @@ -295,7 +295,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, plat->m_Low = sec->floorplane.d; plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); - sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE + sec->xspecial = 0; // NO MORE DAMAGE, IF APPLICABLE break; case DPlat::platUpByValue: diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 21e6605b9..8e2f7e9d9 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -368,8 +368,17 @@ void P_SerializeWorld (FArchive &arc) << sec->planes[sector_t::ceiling] << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap - << sec->gravity - << sec->damageamount; + << sec->gravity; + if (SaveVersion >= 4529) + { + arc << sec->damageamount; + } + else + { + short dmg; + arc << dmg; + sec->damageamount = dmg; + } if (SaveVersion >= 4528) { arc << sec->damageinterval diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 361b220a7..0b6f032e5 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -49,7 +49,7 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const if (NULL != (tsec = getNextSector (ln, this)) && tsec != nogood && - (tsec->special & 0x00ff) == type) + tsec->special == type) { return tsec; } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index dbd0954cc..772679269 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4048,7 +4048,7 @@ void P_SetupLevel (const char *lumpname, int position) { if (mo->flags & MF_COUNTKILL) { - if (mo->Sector->special == dDamage_End) + if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL)) { mo->ClearCounters(); } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 789e44a27..58679e3e6 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -437,8 +437,6 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } } - int special = sector->special; - // Has hit ground. AInventory *ironfeet; @@ -1220,6 +1218,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) new DScroller(DScroller::sc_floor, (-FRACUNIT / 2) << 3, 0, -1, int(sector - sectors), 0); } + keepspecial = true; break; case hDamage_Sludge: @@ -1274,7 +1273,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) }; - int i = (sector->special & 0xff) - Scroll_North_Slow; + int i = sector->special - Scroll_North_Slow; fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); @@ -1284,10 +1283,10 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) { // Heretic scroll special // Only east scrollers also scroll the texture if (!nothinkers) new DScroller (DScroller::sc_floor, - (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5), + (-FRACUNIT/2)<<(sector->special - Carry_East5), 0, -1, int(sector-sectors), 0); } - else keepspecial = true; + keepspecial = true; break; } if (!keepspecial) sector->special = 0; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 64536fff4..e95193860 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1628,10 +1628,10 @@ public: { // [RH] Sectors default to white light with the default fade. // If they are outside (have a sky ceiling), they use the outside fog. - if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside)) + if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside)) { if (fogMap == NULL) - fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0); + fogMap = GetSpecialLights(PalEntry(255, 255, 255), level.outsidefog, 0); sec->ColorMap = fogMap; } else @@ -1644,9 +1644,9 @@ public: else { if (lightcolor == -1) lightcolor = PalEntry(255,255,255); - if (fadecolor == -1) + if (fadecolor == -1) { - if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside)) + if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside)) fadecolor = level.outsidefog; else fadecolor = level.fadeto; diff --git a/src/r_defs.h b/src/r_defs.h index e4b404687..92b95699f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -738,7 +738,7 @@ struct sector_t float gravity; // [RH] Sector gravity (1.0 is normal) FNameNoInit damagetype; // [RH] Means-of-death for applied damage - short damageamount; // [RH] Damage to do while standing on floor + int damageamount; // [RH] Damage to do while standing on floor short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit From eb6c855a95993fd031ef2f0160b40d7b0b915a23 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 13:30:28 +0100 Subject: [PATCH 261/335] - handle intermediate special values in thinkers. They also need to take care of the related damage variables and flags. --- src/p_ceiling.cpp | 12 +++++------ src/p_floor.cpp | 23 ++++++++++---------- src/p_mobj.cpp | 2 +- src/p_plats.cpp | 5 ++--- src/p_sectors.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++ src/p_spec.h | 4 ++-- src/r_defs.h | 34 ++++++++++++++++++++++++++++- 7 files changed, 109 insertions(+), 25 deletions(-) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index b8a3ead7b..3203cf777 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -143,7 +143,7 @@ void DCeiling::Tick () // movers with texture change, change the texture then get removed case genCeilingChgT: case genCeilingChg0: - m_Sector->xspecial = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -176,7 +176,7 @@ void DCeiling::Tick () // then remove the active ceiling case genCeilingChgT: case genCeilingChg0: - m_Sector->xspecial = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -436,11 +436,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, switch (change & 3) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = sec->xspecial; + sec->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone @@ -455,11 +455,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, switch (change & 3) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = line->frontsector->xspecial; + line->frontsector->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone diff --git a/src/p_floor.cpp b/src/p_floor.cpp index c570bff4a..780bd5d9d 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -161,7 +161,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->xspecial = m_Sector->xspecial | m_NewSpecial; + m_Sector->GetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -177,7 +177,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->xspecial = m_Sector->xspecial | m_NewSpecial; + m_Sector->GetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -235,14 +235,14 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change) switch (change & 3) { case 1: - m_NewSpecial = 0; + m_NewSpecial.Clear(); m_Type = DFloor::genFloorChg0; break; case 2: m_Type = DFloor::genFloorChg; break; case 3: - m_NewSpecial = sec->xspecial; + sec->GetSpecial(&m_NewSpecial); m_Type = DFloor::genFloorChgT; break; } @@ -440,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, { FTextureID oldpic = sec->GetTexture(sector_t::floor); sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->xspecial = line->frontsector->xspecial; + sec->TransferSpecial(line->frontsector); } else { - sec->xspecial = 0; + sec->ClearSpecial(); } break; @@ -455,8 +455,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, floor->m_Texture = sec->GetTexture(sector_t::floor); // jff 1/24/98 make sure floor->m_NewSpecial gets initialized // in case no surrounding sector is at floordestheight - // --> should not affect compatibility <-- - floor->m_NewSpecial = sec->xspecial; + sec->GetSpecial(&floor->m_NewSpecial); //jff 5/23/98 use model subroutine to unify fixes and handling sector_t *modelsec; @@ -464,7 +463,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, if (modelsec != NULL) { floor->m_Texture = modelsec->GetTexture(sector_t::floor); - floor->m_NewSpecial = modelsec->xspecial; + modelsec->GetSpecial(&floor->m_NewSpecial); } break; @@ -794,7 +793,7 @@ bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed) floor->m_Sector = s2; floor->m_Speed = slimespeed; floor->m_Texture = s3->GetTexture(sector_t::floor); - floor->m_NewSpecial = 0; + floor->m_NewSpecial.Clear(); height = s3->FindHighestFloorPoint (&spot); floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height); floor->StartFloorSound (); @@ -1093,7 +1092,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (line) { // [RH] if no line, no change sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->xspecial = line->frontsector->xspecial; + sec->TransferSpecial(line->frontsector); } break; case numChangeOnly: @@ -1101,7 +1100,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (secm) { // if no model, no change sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor)); - sec->xspecial = secm->xspecial; + sec->TransferSpecial(secm); } break; default: diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2ded3daf2..e78307949 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4424,7 +4424,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) ( gameaction != ga_worlddone ) && ( p->mo != NULL ) && ( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && - ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) + ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter... { spawn_x = p->mo->x; spawn_y = p->mo->y; diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 467559e63..b0697fc34 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -282,8 +282,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, { if (line) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); - if (change == 1) - sec->xspecial = 0; // Stop damage and other stuff, if any + if (change == 1) sec->ClearSpecial(); } switch (type) @@ -295,7 +294,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, plat->m_Low = sec->floorplane.d; plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); - sec->xspecial = 0; // NO MORE DAMAGE, IF APPLICABLE + sec->ClearSpecial(); break; case DPlat::platUpByValue: diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 0b6f032e5..321ecdd37 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -843,6 +843,60 @@ sector_t *sector_t::GetHeightSec() const } +void sector_t::GetSpecial(secspecial_t *spec) +{ + spec->special = special; + spec->damageamount = damageamount; + spec->damagetype = damagetype; + spec->damageinterval = damageinterval; + spec->leakydamage = leakydamage; + spec->Flags = Flags & SECF_SPECIALFLAGS; +} + +void sector_t::SetSpecial(const secspecial_t *spec) +{ + special = spec->special; + damageamount = spec->damageamount; + damagetype = spec->damagetype; + damageinterval = spec->damageinterval; + leakydamage = spec->leakydamage; + Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS); +} + +void sector_t::TransferSpecial(sector_t *model) +{ + special = model->special; + damageamount = model->damageamount; + damagetype = model->damagetype; + damageinterval = model->damageinterval; + leakydamage = model->leakydamage; + Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS); +} + +FArchive &operator<< (FArchive &arc, secspecial_t &p) +{ + if (SaveVersion < 4529) + { + short special; + arc << special; + sector_t sec; + P_InitSectorSpecial(&sec, special, true); + sec.GetSpecial(&p); + } + else + { + arc << p.special + << p.damageamount + << p.damagetype + << p.damageinterval + << p.leakydamage + << p.Flags; + } + return arc; +} + + + bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const { bool copy = false; diff --git a/src/p_spec.h b/src/p_spec.h index da508fda1..a95e07ce8 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -674,7 +674,7 @@ protected: // [RH] Need these for BOOM-ish transferring ceilings FTextureID m_Texture; - int m_NewSpecial; + secspecial_t m_NewSpecial; // ID int m_Tag; @@ -761,7 +761,7 @@ protected: int m_Crush; bool m_Hexencrush; int m_Direction; - int m_NewSpecial; + secspecial_t m_NewSpecial; FTextureID m_Texture; fixed_t m_FloorDestDist; fixed_t m_Speed; diff --git a/src/r_defs.h b/src/r_defs.h index 92b95699f..536376b63 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -367,7 +367,8 @@ enum SECF_SECRET = 1 << 31, // a secret sector SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, - SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET // not modifiable by Sector_ChangeFlags + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers }; enum @@ -440,6 +441,23 @@ struct FTransform fixed_t base_angle, base_yoffs; }; +struct secspecial_t +{ + FNameNoInit damagetype; // [RH] Means-of-death for applied damage + int damageamount; // [RH] Damage to do while standing on floor + short special; + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit + int Flags; + + void Clear() + { + memset(this, 0, sizeof(*this)); + } +}; + +FArchive &operator<< (FArchive &arc, secspecial_t &p); + struct sector_t { // Member functions @@ -670,6 +688,20 @@ struct sector_t Flags &= ~SECF_SECRET; } + void ClearSpecial() + { + // clears all variables that originate from 'special'. Used for sector type transferring thinkers + special = 0; + damageamount = 0; + damageinterval = 0; + damagetype = NAME_None; + leakydamage = 0; + Flags &= ~SECF_SPECIALFLAGS; + } + + void TransferSpecial(sector_t *model); + void GetSpecial(secspecial_t *spec); + void SetSpecial(const secspecial_t *spec); bool PlaneMoving(int pos); From 6afd76e5dbeaaf1caba244de6d735a6b5710334c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 13:36:22 +0100 Subject: [PATCH 262/335] - enable damage types for Strife's delayed damage. It will always use the type of damage that was last encountered. --- src/d_player.h | 1 + src/p_spec.cpp | 5 +++-- src/p_user.cpp | 9 +++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 11611cded..dc5b27a2b 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -422,6 +422,7 @@ public: int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing int hazardcount; // for delayed Strife damage + FName hazardtype; // Damage type of last hazardous damage encounter. int poisoncount; // screen flash for poison damage FName poisontype; // type of poison damage to apply FName poisonpaintype; // type of Pain state to enter for poison damage diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 58679e3e6..aa6e0235b 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -458,6 +458,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) if (sector->Flags & SECF_HAZARD) { player->hazardcount += sector->damageamount; + player->hazardtype = sector->damagetype; } else { @@ -1231,7 +1232,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) break; case sDamage_Hellslime: - P_SetupSectorDamage(sector, 2, 1, 0, NAME_None, SECF_HAZARD); + P_SetupSectorDamage(sector, 2, 1, 0, NAME_Slime, SECF_HAZARD); break; case Damage_InstantDeath: @@ -1240,7 +1241,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) break; case sDamage_SuperHellslime: - P_SetupSectorDamage(sector, 4, 1, 0, NAME_None, SECF_HAZARD); + P_SetupSectorDamage(sector, 4, 1, 0, NAME_Slime, SECF_HAZARD); break; case Sector_Hidden: diff --git a/src/p_user.cpp b/src/p_user.cpp index 922cc2a1c..e60b82039 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -362,6 +362,7 @@ player_t &player_t::operator=(const player_t &p) damagecount = p.damagecount; bonuscount = p.bonuscount; hazardcount = p.hazardcount; + hazardtype = p.hazardtype; poisoncount = p.poisoncount; poisontype = p.poisontype; poisonpaintype = p.poisonpaintype; @@ -2599,7 +2600,7 @@ void P_PlayerThink (player_t *player) { player->hazardcount--; if (!(level.time & 31) && player->hazardcount > 16*TICRATE) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); + P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype); } if (player->poisoncount && !(level.time & 15)) @@ -3012,7 +3013,11 @@ void player_t::Serialize (FArchive &arc) << air_finished << turnticks << oldbuttons; - bool IsBot; + if (SaveVersion >= 4929) + { + arc << hazardtype; + } + bool IsBot = false; if (SaveVersion >= 4514) { arc << Bot; From 154e1063150be76ab337436b568cffabf774c0a6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 14:16:42 +0100 Subject: [PATCH 263/335] - make better use of the damageinterval value for Strife's delayed damage. --- src/d_player.h | 1 + src/p_spec.cpp | 9 +++++---- src/p_user.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index dc5b27a2b..38879a63a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -422,6 +422,7 @@ public: int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing int hazardcount; // for delayed Strife damage + int hazardinterval; // Frequency of damage infliction FName hazardtype; // Damage type of last hazardous damage encounter. int poisoncount; // screen flash for poison damage FName poisontype; // type of poison damage to apply diff --git a/src/p_spec.cpp b/src/p_spec.cpp index aa6e0235b..101309651 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -453,14 +453,15 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; - if (level.time % sector->damageinterval == 0 && (ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) + if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) { if (sector->Flags & SECF_HAZARD) { player->hazardcount += sector->damageamount; player->hazardtype = sector->damagetype; + player->hazardinterval = sector->damageinterval; } - else + else if (level.time % sector->damageinterval == 0) { P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) @@ -1232,7 +1233,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) break; case sDamage_Hellslime: - P_SetupSectorDamage(sector, 2, 1, 0, NAME_Slime, SECF_HAZARD); + P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD); break; case Damage_InstantDeath: @@ -1241,7 +1242,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) break; case sDamage_SuperHellslime: - P_SetupSectorDamage(sector, 4, 1, 0, NAME_Slime, SECF_HAZARD); + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD); break; case Sector_Hidden: diff --git a/src/p_user.cpp b/src/p_user.cpp index e60b82039..ba987d393 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -363,6 +363,7 @@ player_t &player_t::operator=(const player_t &p) bonuscount = p.bonuscount; hazardcount = p.hazardcount; hazardtype = p.hazardtype; + hazardinterval = p.hazardinterval; poisoncount = p.poisoncount; poisontype = p.poisontype; poisonpaintype = p.poisonpaintype; @@ -2599,7 +2600,7 @@ void P_PlayerThink (player_t *player) if (player->hazardcount) { player->hazardcount--; - if (!(level.time & 31) && player->hazardcount > 16*TICRATE) + if (!(level.time % player->hazardinterval) && player->hazardcount > 16*TICRATE) P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype); } @@ -3015,7 +3016,8 @@ void player_t::Serialize (FArchive &arc) << oldbuttons; if (SaveVersion >= 4929) { - arc << hazardtype; + arc << hazardtype + << hazardinterval; } bool IsBot = false; if (SaveVersion >= 4514) From f8b2b4558f8ccd3cdd49a309a1218308d770fa2b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 15:47:56 +0100 Subject: [PATCH 264/335] - fixed a few typos (Get instead of Set...) --- src/p_floor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 780bd5d9d..e3763e677 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -161,7 +161,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->GetSpecial(&m_NewSpecial); + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -177,7 +177,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->GetSpecial(&m_NewSpecial); + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); From eafa394af4abeffb86e4cb2f582d8c4873f55bd0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 16:42:21 +0100 Subject: [PATCH 265/335] - re-added and fixed terrain splashes for damaging sectors. Turned out that P_HitWater wasn't even able to spawn the splashes, even after the call was re-added. --- src/p_local.h | 1288 ++++++++++++++++++++++++------------------------ src/p_mobj.cpp | 31 +- src/p_spec.cpp | 4 + 3 files changed, 665 insertions(+), 658 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 11e6678c1..63ee4c1b1 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -1,647 +1,647 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Play functions, animation, global header. -// -//----------------------------------------------------------------------------- - - -#ifndef __P_LOCAL__ -#define __P_LOCAL__ - -#include "doomtype.h" -#include "doomdef.h" -#include "tables.h" -#include "r_state.h" -#include "r_utility.h" -#include "d_player.h" - -#include "a_morph.h" - -#include - -#define STEEPSLOPE 46342 // [RH] Minimum floorplane.c value for walking - -#define BONUSADD 6 - -// mapblocks are used to check movement -// against lines and things -#define MAPBLOCKUNITS 128 -#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) -#define MAPBLOCKSHIFT (FRACBITS+7) -#define MAPBMASK (MAPBLOCKSIZE-1) -#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) - -// Inspired by Maes -extern int bmapnegx; -extern int bmapnegy; - -inline int GetSafeBlockX(int blockx) -{ - blockx >>= MAPBLOCKSHIFT; - return (blockx <= bmapnegx) ? blockx & 0x1FF : blockx; -} -inline int GetSafeBlockX(long long blockx) -{ - blockx >>= MAPBLOCKSHIFT; - return int((blockx <= bmapnegx) ? blockx & 0x1FF : blockx); -} - -inline int GetSafeBlockY(int blocky) -{ - blocky >>= MAPBLOCKSHIFT; - return (blocky <= bmapnegy) ? blocky & 0x1FF: blocky; -} -inline int GetSafeBlockY(long long blocky) -{ - blocky >>= MAPBLOCKSHIFT; - return int((blocky <= bmapnegy) ? blocky & 0x1FF: blocky); -} - -// MAXRADIUS is for precalculated sector block boxes -// the spider demon is larger, -// but we do not have any moving sectors nearby -#define MAXRADIUS 0/*32*FRACUNIT*/ - -//#define GRAVITY FRACUNIT -#define MAXMOVE (30*FRACUNIT) - -#define TALKRANGE (128*FRACUNIT) -#define USERANGE (64*FRACUNIT) -#define MELEERANGE (64*FRACUNIT) -#define MISSILERANGE (32*64*FRACUNIT) -#define PLAYERMISSILERANGE (8192*FRACUNIT) // [RH] New MISSILERANGE for players - -// follow a player exlusively for 3 seconds -#define BASETHRESHOLD 100 - - -// -// P_PSPR -// -void P_SetupPsprites (player_t* curplayer, bool startweaponup); -void P_MovePsprites (player_t* curplayer); -void P_DropWeapon (player_t* player); - - -// -// P_USER -// -void P_FallingDamage (AActor *ent); -void P_PlayerThink (player_t *player); -void P_PredictPlayer (player_t *player); -void P_UnPredictPlayer (); -void P_PredictionLerpReset(); - -// -// P_MOBJ -// - -#define ONFLOORZ FIXED_MIN -#define ONCEILINGZ FIXED_MAX -#define FLOATRANDZ (FIXED_MAX-1) - -#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player -#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised - -APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, int flags=0); - -void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); -int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); -bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false, bool usecurspeed=false); - -enum EPuffFlags -{ - PF_HITTHING = 1, - PF_MELEERANGE = 2, - PF_TEMPORARY = 4, - PF_HITTHINGBLEED = 8, - PF_NORANDOMZ = 16 -}; - -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); -void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); -void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); -void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); -void P_RipperBlood (AActor *mo, AActor *bleeder); -int P_GetThingFloorType (AActor *thing); -void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); - -AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); -AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); -AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); -AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); - -AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); -AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, - AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); - -void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); - -// -// [RH] P_THINGS -// -extern FClassMap SpawnableThings; -extern FClassMap StrifeTypes; - -bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); -bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, - fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, - bool leadTarget); -bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog); -bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); -int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); -void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); -void P_RemoveThing(AActor * actor); -bool P_Thing_Raise(AActor *thing, AActor *raiser); -bool P_Thing_CanRaise(AActor *thing); -const PClass *P_GetSpawnableType(int spawnnum); -void InitSpawnablesFromMapinfo(); -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); - -enum WARPF +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// DESCRIPTION: +// Play functions, animation, global header. +// +//----------------------------------------------------------------------------- + + +#ifndef __P_LOCAL__ +#define __P_LOCAL__ + +#include "doomtype.h" +#include "doomdef.h" +#include "tables.h" +#include "r_state.h" +#include "r_utility.h" +#include "d_player.h" + +#include "a_morph.h" + +#include + +#define STEEPSLOPE 46342 // [RH] Minimum floorplane.c value for walking + +#define BONUSADD 6 + +// mapblocks are used to check movement +// against lines and things +#define MAPBLOCKUNITS 128 +#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) +#define MAPBLOCKSHIFT (FRACBITS+7) +#define MAPBMASK (MAPBLOCKSIZE-1) +#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) + +// Inspired by Maes +extern int bmapnegx; +extern int bmapnegy; + +inline int GetSafeBlockX(int blockx) { - WARPF_ABSOLUTEOFFSET = 0x1, - WARPF_ABSOLUTEANGLE = 0x2, - WARPF_USECALLERANGLE = 0x4, - - WARPF_NOCHECKPOSITION = 0x8, - - WARPF_INTERPOLATE = 0x10, - WARPF_WARPINTERPOLATION = 0x20, - WARPF_COPYINTERPOLATION = 0x40, - - WARPF_STOP = 0x80, - WARPF_TOFLOOR = 0x100, - WARPF_TESTONLY = 0x200, - WARPF_ABSOLUTEPOSITION = 0x400, - WARPF_BOB = 0x800, - WARPF_MOVEPTR = 0x1000, - WARPF_USEPTR = 0x2000, - WARPF_USETID = 0x2000, - WARPF_COPYVELOCITY = 0x4000, - WARPF_COPYPITCH = 0x8000, + blockx >>= MAPBLOCKSHIFT; + return (blockx <= bmapnegx) ? blockx & 0x1FF : blockx; +} +inline int GetSafeBlockX(long long blockx) +{ + blockx >>= MAPBLOCKSHIFT; + return int((blockx <= bmapnegx) ? blockx & 0x1FF : blockx); +} + +inline int GetSafeBlockY(int blocky) +{ + blocky >>= MAPBLOCKSHIFT; + return (blocky <= bmapnegy) ? blocky & 0x1FF: blocky; +} +inline int GetSafeBlockY(long long blocky) +{ + blocky >>= MAPBLOCKSHIFT; + return int((blocky <= bmapnegy) ? blocky & 0x1FF: blocky); +} + +// MAXRADIUS is for precalculated sector block boxes +// the spider demon is larger, +// but we do not have any moving sectors nearby +#define MAXRADIUS 0/*32*FRACUNIT*/ + +//#define GRAVITY FRACUNIT +#define MAXMOVE (30*FRACUNIT) + +#define TALKRANGE (128*FRACUNIT) +#define USERANGE (64*FRACUNIT) +#define MELEERANGE (64*FRACUNIT) +#define MISSILERANGE (32*64*FRACUNIT) +#define PLAYERMISSILERANGE (8192*FRACUNIT) // [RH] New MISSILERANGE for players + +// follow a player exlusively for 3 seconds +#define BASETHRESHOLD 100 + + +// +// P_PSPR +// +void P_SetupPsprites (player_t* curplayer, bool startweaponup); +void P_MovePsprites (player_t* curplayer); +void P_DropWeapon (player_t* player); + + +// +// P_USER +// +void P_FallingDamage (AActor *ent); +void P_PlayerThink (player_t *player); +void P_PredictPlayer (player_t *player); +void P_UnPredictPlayer (); +void P_PredictionLerpReset(); + +// +// P_MOBJ +// + +#define ONFLOORZ FIXED_MIN +#define ONCEILINGZ FIXED_MAX +#define FLOATRANDZ (FIXED_MAX-1) + +#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player +#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised + +APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, int flags=0); + +void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); +int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); +bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false, bool usecurspeed=false); + +enum EPuffFlags +{ + PF_HITTHING = 1, + PF_MELEERANGE = 2, + PF_TEMPORARY = 4, + PF_HITTHINGBLEED = 8, + PF_NORANDOMZ = 16 }; - - -// -// P_MAPUTL -// -struct divline_t -{ - fixed_t x; - fixed_t y; - fixed_t dx; - fixed_t dy; - -}; - -struct intercept_t -{ - fixed_t frac; // along trace line - bool isaline; - bool done; - union { - AActor *thing; - line_t *line; - } d; -}; - -typedef bool (*traverser_t) (intercept_t *in); - -fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); - -//========================================================================== -// -// P_PointOnLineSide -// -// Returns 0 (front/on) or 1 (back) -// [RH] inlined, stripped down, and made more precise -// -//========================================================================== - -inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) -{ - extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); - - return i_compatflags2 & COMPATF2_POINTONLINE - ? P_VanillaPointOnLineSide(x, y, line) - : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; -} - -//========================================================================== -// -// P_PointOnDivlineSide -// -// Same as P_PointOnLineSide except it uses divlines -// [RH] inlined, stripped down, and made more precise -// -//========================================================================== - -inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) -{ - extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); - - return (i_compatflags2 & COMPATF2_POINTONLINE) - ? P_VanillaPointOnDivlineSide(x, y, line) - : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); -} - -//========================================================================== -// -// P_MakeDivline -// -//========================================================================== - -inline void P_MakeDivline (const line_t *li, divline_t *dl) -{ - dl->x = li->v1->x; - dl->y = li->v1->y; - dl->dx = li->dx; - dl->dy = li->dy; -} - -fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); - -struct FLineOpening -{ - fixed_t top; - fixed_t bottom; - fixed_t range; - fixed_t lowfloor; - sector_t *bottomsec; - sector_t *topsec; - FTextureID ceilingpic; - FTextureID floorpic; - bool touchmidtex; - bool abovemidtex; -}; - -void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx=FIXED_MIN, fixed_t refy=0, int flags=0); - -class FBoundingBox; -struct polyblock_t; - -class FBlockLinesIterator -{ - int minx, maxx; - int miny, maxy; - - int curx, cury; - polyblock_t *polyLink; - int polyIndex; - int *list; - - void StartBlock(int x, int y); - -public: - FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false); - FBlockLinesIterator(const FBoundingBox &box); - line_t *Next(); - void Reset() { StartBlock(minx, miny); } -}; - -class FBlockThingsIterator -{ - int minx, maxx; - int miny, maxy; - - int curx, cury; - - FBlockNode *block; - - int Buckets[32]; - - struct HashEntry - { - AActor *Actor; - int Next; - }; - HashEntry FixedHash[10]; - int NumFixedHash; - TArray DynHash; - - HashEntry *GetHashEntry(int i) { return i < (int)countof(FixedHash) ? &FixedHash[i] : &DynHash[i - countof(FixedHash)]; } - - void StartBlock(int x, int y); - void SwitchBlock(int x, int y); - void ClearHash(); - - // The following is only for use in the path traverser - // and therefore declared private. - FBlockThingsIterator(); - - friend class FPathTraverse; - -public: - FBlockThingsIterator(int minx, int miny, int maxx, int maxy); - FBlockThingsIterator(const FBoundingBox &box); - AActor *Next(bool centeronly = false); - void Reset() { StartBlock(minx, miny); } -}; - -class FPathTraverse -{ - static TArray 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, FBlockThingsIterator &it, bool compatible); -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_ADDTHINGS 2 -#define PT_COMPATIBLE 4 -#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint - -AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); - -// -// P_MAP -// - -struct FCheckPosition -{ - // in - AActor *thing; - fixed_t x; - fixed_t y; - fixed_t z; - - // out - sector_t *sector; - fixed_t floorz; - fixed_t ceilingz; - fixed_t dropoffz; - FTextureID floorpic; - sector_t *floorsector; - FTextureID ceilingpic; - sector_t *ceilingsector; - bool touchmidtex; - bool abovemidtex; - bool floatok; - bool FromPMove; - line_t *ceilingline; - AActor *stepthing; - // [RH] These are used by PIT_CheckThing and P_XYMovement to apply - // ripping damage once per tic instead of once per move. - bool DoRipping; - AActor *LastRipped; - int PushTime; - - FCheckPosition(bool rip=false) - { - DoRipping = rip; - LastRipped = NULL; - PushTime = 0; - FromPMove = false; - } -}; - - - -// If "floatok" true, move would be ok -// if within "tmfloorz - tmceilingz". -extern msecnode_t *sector_list; // phares 3/16/98 - -extern TArray spechit; - - -bool P_TestMobjLocation (AActor *mobj); -bool P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); -bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool actorsonly=false); -bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, bool actorsonly=false); -AActor *P_CheckOnmobj (AActor *thing); -void P_FakeZMovement (AActor *mo); -bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); -bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); -bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); -void P_ApplyTorque(AActor *mo); -bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters -void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player -void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); -bool P_BounceWall (AActor *mo); -bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); - -enum ESightFlags -{ - SF_IGNOREVISIBILITY=1, - SF_SEEPASTSHOOTABLELINES=2, - SF_SEEPASTBLOCKEVERYTHING=4, - SF_IGNOREWATERBOUNDARY=8 -}; - -void P_ResetSightCounters (bool full); -bool P_TalkFacing (AActor *player); -void P_UseLines (player_t* player); -bool P_UsePuzzleItem (AActor *actor, int itemType); - -enum -{ - FFCF_ONLYSPAWNPOS = 1, - FFCF_SAMESECTOR = 2, - FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes - FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z -}; -void P_FindFloorCeiling (AActor *actor, int flags=0); - -bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); - -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); - -enum // P_AimLineAttack flags -{ - ALF_FORCENOSMART = 1, - ALF_CHECK3D = 2, - ALF_CHECKNONSHOOTABLE = 4, - ALF_CHECKCONVERSATION = 8, - ALF_NOFRIENDS = 16, -}; - -enum // P_LineAttack flags -{ - LAF_ISMELEEATTACK = 1, - LAF_NORANDOMPUFFZ = 2, - LAF_NOIMPACTDECAL = 4 -}; - -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); -void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); -void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); -void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version -void P_TraceBleed (int damage, AActor *target); // random direction version -bool P_HitFloor (AActor *thing); -bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); -void P_CheckSplash(AActor *self, fixed_t distance); -void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun - -enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags -{ - RAF_SILENT = 1, - RAF_NOPIERCE = 2, - RAF_EXPLICITANGLE = 4, - RAF_FULLBRIGHT = 8, - RAF_CENTERZ = 16, -}; - - -bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); -void P_PlaySpawnSound(AActor *missile, AActor *spawner); - -// [RH] Position the chasecam -void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); - -// [RH] Means of death -enum -{ - RADF_HURTSOURCE = 1, - RADF_NOIMPACTDAMAGE = 2, - RADF_SOURCEISSPOT = 4, - RADF_NODAMAGE = 8, -}; -void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, - FName damageType, int flags, int fulldamagedistance=0); - -void P_DelSector_List(); -void P_DelSeclist(msecnode_t *); // phares 3/16/98 -msecnode_t* P_DelSecnode(msecnode_t *); -void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98 -int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98 -int P_GetFriction(const AActor *mo, int *frictionfactor); -bool Check_Sides(AActor *, int, int); // phares - -// [RH] -const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove); - -//---------------------------------------------------------------------------------- -// -// Added so that in the source there's a clear distinction between -// game engine and renderer specific calls. -// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.) -// -//---------------------------------------------------------------------------------- -subsector_t *P_PointInSubsector (fixed_t x, fixed_t y); -inline sector_t *P_PointInSector(fixed_t x, fixed_t y) -{ - return P_PointInSubsector(x,y)->sector; -} - -// -// P_SETUP -// -extern BYTE* rejectmatrix; // for fast sight rejection -extern int* blockmaplump; // offsets in blockmap are from here - -extern int* blockmap; -extern int bmapwidth; -extern int bmapheight; // in mapblocks -extern fixed_t bmaporgx; -extern fixed_t bmaporgy; // origin of block map -extern FBlockNode** blocklinks; // for thing chains - - - -// -// P_INTER -// -void P_TouchSpecialThing (AActor *special, AActor *toucher); -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); -void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); -bool P_GiveBody (AActor *actor, int num, int max=0); -bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); -void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); - -enum EDmgFlags -{ - DMG_NO_ARMOR = 1, - DMG_INFLICTOR_IS_PUFF = 2, - DMG_THRUSTLESS = 4, - DMG_FORCED = 8, - DMG_NO_FACTOR = 16, - DMG_PLAYERATTACK = 32, - DMG_FOILINVUL = 64, - DMG_FOILBUDDHA = 128, - DMG_NO_PROTECT = 256, -}; - - -// ===== PO_MAN ===== - -typedef enum -{ - PODOOR_NONE, - PODOOR_SLIDE, - PODOOR_SWING, -} podoortype_t; - -bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); -bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); -bool EV_MovePolyTo (line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); -bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); -bool EV_StopPoly (int polyNum); - - -// [RH] Data structure for P_SpawnMapThing() to keep track -// of polyobject-related things. -struct polyspawns_t -{ - polyspawns_t *next; - fixed_t x; - fixed_t y; - short angle; - short type; -}; - -extern int po_NumPolyobjs; -extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn - - -void PO_Init (); -bool PO_Busy (int polyobj); -FPolyObj *PO_GetPolyobj(int polyNum); - -// -// P_SPEC -// -#include "p_spec.h" - -bool P_AlignFlat (int linenum, int side, int fc); - -#endif // __P_LOCAL__ +AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); +void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); +void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); +void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); +void P_RipperBlood (AActor *mo, AActor *bleeder); +int P_GetThingFloorType (AActor *thing); +void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); + +AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); +AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); +AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); +AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); +AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); + +AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); +AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); +AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, + AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); + +void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); + +// +// [RH] P_THINGS +// +extern FClassMap SpawnableThings; +extern FClassMap StrifeTypes; + +bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); +bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, + fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, + bool leadTarget); +bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog); +bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); +int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); +void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); +void P_RemoveThing(AActor * actor); +bool P_Thing_Raise(AActor *thing, AActor *raiser); +bool P_Thing_CanRaise(AActor *thing); +const PClass *P_GetSpawnableType(int spawnnum); +void InitSpawnablesFromMapinfo(); +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); + +enum WARPF +{ + WARPF_ABSOLUTEOFFSET = 0x1, + WARPF_ABSOLUTEANGLE = 0x2, + WARPF_USECALLERANGLE = 0x4, + + WARPF_NOCHECKPOSITION = 0x8, + + WARPF_INTERPOLATE = 0x10, + WARPF_WARPINTERPOLATION = 0x20, + WARPF_COPYINTERPOLATION = 0x40, + + WARPF_STOP = 0x80, + WARPF_TOFLOOR = 0x100, + WARPF_TESTONLY = 0x200, + WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, + WARPF_USEPTR = 0x2000, + WARPF_USETID = 0x2000, + WARPF_COPYVELOCITY = 0x4000, + WARPF_COPYPITCH = 0x8000, +}; + + + +// +// P_MAPUTL +// +struct divline_t +{ + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; + +}; + +struct intercept_t +{ + fixed_t frac; // along trace line + bool isaline; + bool done; + union { + AActor *thing; + line_t *line; + } d; +}; + +typedef bool (*traverser_t) (intercept_t *in); + +fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); + +//========================================================================== +// +// P_PointOnLineSide +// +// Returns 0 (front/on) or 1 (back) +// [RH] inlined, stripped down, and made more precise +// +//========================================================================== + +inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) +{ + extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); + + return i_compatflags2 & COMPATF2_POINTONLINE + ? P_VanillaPointOnLineSide(x, y, line) + : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; +} + +//========================================================================== +// +// P_PointOnDivlineSide +// +// Same as P_PointOnLineSide except it uses divlines +// [RH] inlined, stripped down, and made more precise +// +//========================================================================== + +inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) +{ + extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); + + return (i_compatflags2 & COMPATF2_POINTONLINE) + ? P_VanillaPointOnDivlineSide(x, y, line) + : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); +} + +//========================================================================== +// +// P_MakeDivline +// +//========================================================================== + +inline void P_MakeDivline (const line_t *li, divline_t *dl) +{ + dl->x = li->v1->x; + dl->y = li->v1->y; + dl->dx = li->dx; + dl->dy = li->dy; +} + +fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); + +struct FLineOpening +{ + fixed_t top; + fixed_t bottom; + fixed_t range; + fixed_t lowfloor; + sector_t *bottomsec; + sector_t *topsec; + FTextureID ceilingpic; + FTextureID floorpic; + bool touchmidtex; + bool abovemidtex; +}; + +void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx=FIXED_MIN, fixed_t refy=0, int flags=0); + +class FBoundingBox; +struct polyblock_t; + +class FBlockLinesIterator +{ + int minx, maxx; + int miny, maxy; + + int curx, cury; + polyblock_t *polyLink; + int polyIndex; + int *list; + + void StartBlock(int x, int y); + +public: + FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false); + FBlockLinesIterator(const FBoundingBox &box); + line_t *Next(); + void Reset() { StartBlock(minx, miny); } +}; + +class FBlockThingsIterator +{ + int minx, maxx; + int miny, maxy; + + int curx, cury; + + FBlockNode *block; + + int Buckets[32]; + + struct HashEntry + { + AActor *Actor; + int Next; + }; + HashEntry FixedHash[10]; + int NumFixedHash; + TArray DynHash; + + HashEntry *GetHashEntry(int i) { return i < (int)countof(FixedHash) ? &FixedHash[i] : &DynHash[i - countof(FixedHash)]; } + + void StartBlock(int x, int y); + void SwitchBlock(int x, int y); + void ClearHash(); + + // The following is only for use in the path traverser + // and therefore declared private. + FBlockThingsIterator(); + + friend class FPathTraverse; + +public: + FBlockThingsIterator(int minx, int miny, int maxx, int maxy); + FBlockThingsIterator(const FBoundingBox &box); + AActor *Next(bool centeronly = false); + void Reset() { StartBlock(minx, miny); } +}; + +class FPathTraverse +{ + static TArray 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, FBlockThingsIterator &it, bool compatible); +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_ADDTHINGS 2 +#define PT_COMPATIBLE 4 +#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint + +AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); + +// +// P_MAP +// + +struct FCheckPosition +{ + // in + AActor *thing; + fixed_t x; + fixed_t y; + fixed_t z; + + // out + sector_t *sector; + fixed_t floorz; + fixed_t ceilingz; + fixed_t dropoffz; + FTextureID floorpic; + sector_t *floorsector; + FTextureID ceilingpic; + sector_t *ceilingsector; + bool touchmidtex; + bool abovemidtex; + bool floatok; + bool FromPMove; + line_t *ceilingline; + AActor *stepthing; + // [RH] These are used by PIT_CheckThing and P_XYMovement to apply + // ripping damage once per tic instead of once per move. + bool DoRipping; + AActor *LastRipped; + int PushTime; + + FCheckPosition(bool rip=false) + { + DoRipping = rip; + LastRipped = NULL; + PushTime = 0; + FromPMove = false; + } +}; + + + +// If "floatok" true, move would be ok +// if within "tmfloorz - tmceilingz". +extern msecnode_t *sector_list; // phares 3/16/98 + +extern TArray spechit; + + +bool P_TestMobjLocation (AActor *mobj); +bool P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); +bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool actorsonly=false); +bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, bool actorsonly=false); +AActor *P_CheckOnmobj (AActor *thing); +void P_FakeZMovement (AActor *mo); +bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); +bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); +bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); +void P_ApplyTorque(AActor *mo); +bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters +void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player +void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); +bool P_BounceWall (AActor *mo); +bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); +bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); + +enum ESightFlags +{ + SF_IGNOREVISIBILITY=1, + SF_SEEPASTSHOOTABLELINES=2, + SF_SEEPASTBLOCKEVERYTHING=4, + SF_IGNOREWATERBOUNDARY=8 +}; + +void P_ResetSightCounters (bool full); +bool P_TalkFacing (AActor *player); +void P_UseLines (player_t* player); +bool P_UsePuzzleItem (AActor *actor, int itemType); + +enum +{ + FFCF_ONLYSPAWNPOS = 1, + FFCF_SAMESECTOR = 2, + FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes + FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z +}; +void P_FindFloorCeiling (AActor *actor, int flags=0); + +bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); + +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); + +enum // P_AimLineAttack flags +{ + ALF_FORCENOSMART = 1, + ALF_CHECK3D = 2, + ALF_CHECKNONSHOOTABLE = 4, + ALF_CHECKCONVERSATION = 8, + ALF_NOFRIENDS = 16, +}; + +enum // P_LineAttack flags +{ + LAF_ISMELEEATTACK = 1, + LAF_NORANDOMPUFFZ = 2, + LAF_NOIMPACTDECAL = 4 +}; + +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); +void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); +void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); +void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version +void P_TraceBleed (int damage, AActor *target); // random direction version +bool P_HitFloor (AActor *thing); +bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); +void P_CheckSplash(AActor *self, fixed_t distance); +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun + +enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags +{ + RAF_SILENT = 1, + RAF_NOPIERCE = 2, + RAF_EXPLICITANGLE = 4, + RAF_FULLBRIGHT = 8, + RAF_CENTERZ = 16, +}; + + +bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); +void P_PlaySpawnSound(AActor *missile, AActor *spawner); + +// [RH] Position the chasecam +void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); + +// [RH] Means of death +enum +{ + RADF_HURTSOURCE = 1, + RADF_NOIMPACTDAMAGE = 2, + RADF_SOURCEISSPOT = 4, + RADF_NODAMAGE = 8, +}; +void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, + FName damageType, int flags, int fulldamagedistance=0); + +void P_DelSector_List(); +void P_DelSeclist(msecnode_t *); // phares 3/16/98 +msecnode_t* P_DelSecnode(msecnode_t *); +void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98 +int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98 +int P_GetFriction(const AActor *mo, int *frictionfactor); +bool Check_Sides(AActor *, int, int); // phares + +// [RH] +const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove); + +//---------------------------------------------------------------------------------- +// +// Added so that in the source there's a clear distinction between +// game engine and renderer specific calls. +// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.) +// +//---------------------------------------------------------------------------------- +subsector_t *P_PointInSubsector (fixed_t x, fixed_t y); +inline sector_t *P_PointInSector(fixed_t x, fixed_t y) +{ + return P_PointInSubsector(x,y)->sector; +} + +// +// P_SETUP +// +extern BYTE* rejectmatrix; // for fast sight rejection +extern int* blockmaplump; // offsets in blockmap are from here + +extern int* blockmap; +extern int bmapwidth; +extern int bmapheight; // in mapblocks +extern fixed_t bmaporgx; +extern fixed_t bmaporgy; // origin of block map +extern FBlockNode** blocklinks; // for thing chains + + + +// +// P_INTER +// +void P_TouchSpecialThing (AActor *special, AActor *toucher); +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); +void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); +bool P_GiveBody (AActor *actor, int num, int max=0); +bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); +void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); + +enum EDmgFlags +{ + DMG_NO_ARMOR = 1, + DMG_INFLICTOR_IS_PUFF = 2, + DMG_THRUSTLESS = 4, + DMG_FORCED = 8, + DMG_NO_FACTOR = 16, + DMG_PLAYERATTACK = 32, + DMG_FOILINVUL = 64, + DMG_FOILBUDDHA = 128, + DMG_NO_PROTECT = 256, +}; + + +// ===== PO_MAN ===== + +typedef enum +{ + PODOOR_NONE, + PODOOR_SLIDE, + PODOOR_SWING, +} podoortype_t; + +bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); +bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); +bool EV_MovePolyTo (line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); +bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); +bool EV_StopPoly (int polyNum); + + +// [RH] Data structure for P_SpawnMapThing() to keep track +// of polyobject-related things. +struct polyspawns_t +{ + polyspawns_t *next; + fixed_t x; + fixed_t y; + short angle; + short type; +}; + +extern int po_NumPolyobjs; +extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn + + +void PO_Init (); +bool PO_Busy (int polyobj); +FPolyObj *PO_GetPolyobj(int polyNum); + +// +// P_SPEC +// +#include "p_spec.h" + +bool P_AlignFlat (int linenum, int side, int fc); + +#endif // __P_LOCAL__ diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e78307949..48f16ba0e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5320,7 +5320,7 @@ int P_GetThingFloorType (AActor *thing) // Returns true if hit liquid and splashed, false if not. //--------------------------------------------------------------------------- -bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert) +bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert, bool force) { if (thing->flags3 & MF3_DONTSPLASH) return false; @@ -5362,24 +5362,27 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z } #endif - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - F3DFloor * rover = sec->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_EXISTS)) continue; - fixed_t planez = rover->top.plane->ZatPoint(x, y); - if (z > planez - FRACUNIT/2 && z < planez + FRACUNIT/2) // allow minor imprecisions + if (!force) + { + for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { - if (rover->flags & (FF_SOLID|FF_SWIMMABLE) ) + F3DFloor * rover = sec->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + fixed_t planez = rover->top.plane->ZatPoint(x, y); + if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions { - terrainnum = TerrainTypes[*rover->top.texture]; - goto foundone; + if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) + { + terrainnum = TerrainTypes[*rover->top.texture]; + goto foundone; + } } + planez = rover->bottom.plane->ZatPoint(x, y); + if (planez < z && !(planez < thing->floorz)) return false; } - planez = rover->bottom.plane->ZatPoint(x, y); - if (planez < z && !(planez < thing->floorz)) return false; } hsec = sec->GetHeightSec(); - if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) + if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) { terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)]; } @@ -5403,7 +5406,7 @@ foundone: // Don't splash for living things with small vertical velocities. // There are levels where the constant splashing from the monsters gets extremely annoying - if ((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) + if (((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) && !force) return Terrains[terrainnum].IsLiquid; splash = &Splashes[splashnum]; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 101309651..918d07ed2 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -468,6 +468,10 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { G_ExitLevel(0, false); } + if (sector->Flags & SECF_DMGTERRAINFX) + { + P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); + } } } } From cd4076dc1bba6779038a8a2eabdf63ba95af0476 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Jan 2016 12:49:38 -0600 Subject: [PATCH 266/335] Added $ check for language support for StaticTextSwitchable --- src/menu/optionmenuitems.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index c63359f4b..3054847c1 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -32,6 +32,7 @@ ** */ #include "v_text.h" +#include "gstrings.h" void M_DrawConText (int color, int x, int y, const char *str); @@ -503,6 +504,7 @@ public: int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected) { const char *txt = mCurrent? (const char*)mAltText : mLabel; + if (*txt == '$') txt = GStrings(txt + 1); int w = SmallFont->StringWidth(txt) * CleanXfac_1; int x = (screen->GetWidth() - w) / 2; screen->DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true, TAG_DONE); From efaaccc0306de2362a29c3b68db3f8f5b0c92cfc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Jan 2016 12:58:36 -0600 Subject: [PATCH 267/335] Added $ check for language support for drawing Option Values --- src/menu/optionmenuitems.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 3054847c1..0b0b57759 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -200,6 +200,7 @@ public: { text = (*opt)->mValues[Selection].Text; } + if (*text == '$') text = GStrings(text + 1); screen->DrawText (SmallFont, OptionSettings.mFontColorValue, indent + CURSORSPACE, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE); return indent; From d20f18a4bb5efad73a7c782d96b39f4a1e58f5ed Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 7 Jan 2016 22:48:25 -0600 Subject: [PATCH 268/335] I missed one last spot where a FreeBSD compilation should follow the path of OS X -- needs to be pulled in for signal functions --- src/posix/sdl/crashcatcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/sdl/crashcatcher.c b/src/posix/sdl/crashcatcher.c index f85713e31..70c9e7b0c 100644 --- a/src/posix/sdl/crashcatcher.c +++ b/src/posix/sdl/crashcatcher.c @@ -15,7 +15,7 @@ #ifndef PR_SET_PTRACER #define PR_SET_PTRACER 0x59616d61 #endif -#elif defined (__APPLE__) +#elif defined (__APPLE__) || defined (__FreeBSD__) #include #endif From cf564c60c214751bbc3b8511f688104ac9f618b2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 01:23:00 +0100 Subject: [PATCH 269/335] - simplified setup of polyobjects defined from explicit lines The old method had a problem with missing order numbers and aborted the level load and made many assumptions that no longer apply with BSP based polyobject rendering. --- src/po_man.cpp | 64 ++++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index 60627e4f3..fac9a660b 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1533,6 +1533,11 @@ static void IterFindPolySides (FPolyObj *po, side_t *side) // //========================================================================== +static int STACK_ARGS posicmp(const void *a, const void *b) +{ + return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1]; +} + static void SpawnPolyobj (int index, int tag, int type) { unsigned int ii; @@ -1577,59 +1582,24 @@ static void SpawnPolyobj (int index, int tag, int type) // didn't find a polyobj through PO_LINE_START TArray polySideList; unsigned int psIndexOld; - for (j = 1; j < PO_MAXPOLYSEGS; j++) - { - psIndexOld = po->Sidedefs.Size(); - for (ii = 0; ii < KnownPolySides.Size(); ++ii) - { - i = KnownPolySides[ii]; + psIndexOld = po->Sidedefs.Size(); - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag) - { - if (!sides[i].linedef->args[1]) - { - I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", - j+1, tag); - } - if (sides[i].linedef->args[1] == j) - { - po->Sidedefs.Push (&sides[i]); - } - } - } - // Clear out any specials for these segs...we cannot clear them out - // in the above loop, since we aren't guaranteed one seg per linedef. - for (ii = 0; ii < KnownPolySides.Size(); ++ii) + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + + if (i >= 0 && + sides[i].linedef->special == Polyobj_ExplicitLine && + sides[i].linedef->args[0] == tag) { - i = KnownPolySides[ii]; - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag && sides[i].linedef->args[1] == j) + if (!sides[i].linedef->args[1]) { - sides[i].linedef->special = 0; - sides[i].linedef->args[0] = 0; - KnownPolySides[ii] = -1; - } - } - if (po->Sidedefs.Size() == psIndexOld) - { // Check if an explicit line order has been skipped. - // A line has been skipped if there are any more explicit - // lines with the current tag value. [RH] Can this actually happen? - for (ii = 0; ii < KnownPolySides.Size(); ++ii) - { - i = KnownPolySides[ii]; - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag) - { - I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", - j, tag); - } + I_Error("SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, int(sides[i].linedef - lines)); } + po->Sidedefs.Push (&sides[i]); } } + qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp); if (po->Sidedefs.Size() > 0) { po->crush = (type != SMT_PolySpawn) ? 3 : 0; From a43f5a8ecac4323309954a58ba940efdc956e06c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Jan 2016 20:08:06 -0600 Subject: [PATCH 270/335] Remove now unused variable from SpawnPolyobj --- src/po_man.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index fac9a660b..727591bd5 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1542,7 +1542,6 @@ static void SpawnPolyobj (int index, int tag, int type) { unsigned int ii; int i; - int j; FPolyObj *po = &polyobjs[index]; for (ii = 0; ii < KnownPolySides.Size(); ++ii) From f330a819092c58d6d3d305d99a6ca8ef7dcb38df Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Jan 2016 20:08:10 -0600 Subject: [PATCH 271/335] Rename packing textures to texture atlases for the D3D code - I figure since I now know the "proper" name for these things, I should call them by it. --- src/win32/fb_d3d9.cpp | 89 ++++++++++++++++++++++-------------------- src/win32/win32iface.h | 6 +-- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index e23275734..273fcde44 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -90,7 +90,7 @@ IMPLEMENT_CLASS(D3DFB) struct D3DFB::PackedTexture { - D3DFB::PackingTexture *Owner; + D3DFB::Atlas *Owner; PackedTexture *Next, **Prev; @@ -104,10 +104,10 @@ struct D3DFB::PackedTexture bool Padded; }; -struct D3DFB::PackingTexture +struct D3DFB::Atlas { - PackingTexture(D3DFB *fb, int width, int height, D3DFORMAT format); - ~PackingTexture(); + Atlas(D3DFB *fb, int width, int height, D3DFORMAT format); + ~Atlas(); PackedTexture *GetBestFit(int width, int height, int &area); void AllocateImage(PackedTexture *box, int width, int height); @@ -115,7 +115,7 @@ struct D3DFB::PackingTexture void AddEmptyBox(int left, int top, int right, int bottom); void FreeBox(PackedTexture *box); - PackingTexture *Next; + Atlas *Next; IDirect3DTexture9 *Tex; D3DFORMAT Format; PackedTexture *UsedList; // Boxes that contain images @@ -283,7 +283,7 @@ D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen) ScreenWipe = NULL; InScene = false; QuadExtra = new BufferedTris[MAX_QUAD_BATCH]; - Packs = NULL; + Atlases = NULL; PixelDoubling = 0; SkipAt = -1; CurrRenderTexture = 0; @@ -496,7 +496,7 @@ void D3DFB::FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, b bool D3DFB::CreateResources() { - Packs = NULL; + Atlases = NULL; if (!Windowed) { // Remove the window border in fullscreen mode @@ -624,8 +624,8 @@ void D3DFB::ReleaseResources () delete ScreenWipe; ScreenWipe = NULL; } - PackingTexture *pack, *next; - for (pack = Packs; pack != NULL; pack = next) + Atlas *pack, *next; + for (pack = Atlases; pack != NULL; pack = next) { next = pack->Next; delete pack; @@ -1826,8 +1826,9 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) // // D3DFB :: DrawPackedTextures // -// DEBUG: Draws the packing textures to the screen, starting with the -// 1-based packnum. +// DEBUG: Draws the texture atlases to the screen, starting with the +// 1-based packnum. Ignores atlases that are flagged for use by one +// texture only. // //========================================================================== @@ -1838,30 +1839,34 @@ void D3DFB::DrawPackedTextures(int packnum) 0xFFFF9999, 0xFF99FF99, 0xFF9999FF, 0xFFFFFF99, 0xFFFF99FF, 0xFF99FFFF, 0xFFFFCC99, 0xFF99CCFF }; - PackingTexture *pack; + Atlas *pack; int x = 8, y = 8; if (packnum <= 0) { return; } - pack = Packs; + pack = Atlases; + // Find the first texture atlas that is an actual atlas. while (pack != NULL && pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases pack = pack->Next; } + // Skip however many atlases we would have otherwise drawn + // until we've skipped of them. while (pack != NULL && packnum != 1) { if (!pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases packnum--; } pack = pack->Next; } + // Draw atlases until we run out of room on the screen. while (pack != NULL) { if (pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases pack = pack->Next; continue; } @@ -1969,34 +1974,34 @@ void D3DFB::DrawPackedTextures(int packnum) // // D3DFB :: AllocPackedTexture // -// Finds space to pack an image inside a packing texture and returns it. +// Finds space to pack an image inside a texture atlas and returns it. // Large images and those that need to wrap always get their own textures. // //========================================================================== D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3DFORMAT format) { - PackingTexture *bestpack; + Atlas *bestpack; PackedTexture *bestbox; int area; // check for 254 to account for padding if (w > 254 || h > 254 || wrapping) - { // Create a new packing texture. - bestpack = new PackingTexture(this, w, h, format); + { // Create a new texture atlas. + bestpack = new Atlas(this, w, h, format); bestpack->OneUse = true; bestbox = bestpack->GetBestFit(w, h, area); bestbox->Padded = false; } else - { // Try to find space in an existing packing texture. + { // Try to find space in an existing texture atlas. w += 2; // Add padding h += 2; int bestarea = INT_MAX; int bestareaever = w * h; bestpack = NULL; bestbox = NULL; - for (PackingTexture *pack = Packs; pack != NULL; pack = pack->Next) + for (Atlas *pack = Atlases; pack != NULL; pack = pack->Next) { if (pack->Format == format) { @@ -2016,8 +2021,8 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D } } if (bestpack == NULL) - { // Create a new packing texture. - bestpack = new PackingTexture(this, 256, 256, format); + { // Create a new texture atlas. + bestpack = new Atlas(this, 256, 256, format); bestbox = bestpack->GetBestFit(w, h, bestarea); } bestbox->Padded = true; @@ -2028,11 +2033,11 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D //========================================================================== // -// PackingTexture Constructor +// Atlas Constructor // //========================================================================== -D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format) +D3DFB::Atlas::Atlas(D3DFB *fb, int w, int h, D3DFORMAT format) { Tex = NULL; Format = format; @@ -2043,8 +2048,8 @@ D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format) Width = 0; Height = 0; - Next = fb->Packs; - fb->Packs = this; + Next = fb->Atlases; + fb->Atlases = this; #if 1 if (FAILED(fb->D3DDevice->CreateTexture(w, h, 1, 0, format, D3DPOOL_MANAGED, &Tex, NULL))) @@ -2068,11 +2073,11 @@ D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format) //========================================================================== // -// PackingTexture Destructor +// Atlas Destructor // //========================================================================== -D3DFB::PackingTexture::~PackingTexture() +D3DFB::Atlas::~Atlas() { PackedTexture *box, *next; @@ -2096,14 +2101,14 @@ D3DFB::PackingTexture::~PackingTexture() //========================================================================== // -// PackingTexture :: GetBestFit +// Atlas :: GetBestFit // // Returns the empty box that provides the best fit for the requested // dimensions, or NULL if none of them are large enough. // //========================================================================== -D3DFB::PackedTexture *D3DFB::PackingTexture::GetBestFit(int w, int h, int &area) +D3DFB::PackedTexture *D3DFB::Atlas::GetBestFit(int w, int h, int &area) { PackedTexture *box; int smallestarea = INT_MAX; @@ -2133,17 +2138,17 @@ D3DFB::PackedTexture *D3DFB::PackingTexture::GetBestFit(int w, int h, int &area) //========================================================================== // -// PackingTexture :: AllocateImage +// Atlas :: AllocateImage // // Moves the box from the empty list to the used list, sizing it to the // requested dimensions and adding additional boxes to the empty list if // needed. // -// The passed box *MUST* be in this packing texture's empty list. +// The passed box *MUST* be in this texture atlas's empty list. // //========================================================================== -void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int h) +void D3DFB::Atlas::AllocateImage(D3DFB::PackedTexture *box, int w, int h) { RECT start = box->Area; @@ -2212,13 +2217,13 @@ void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int //========================================================================== // -// PackingTexture :: AddEmptyBox +// Atlas :: AddEmptyBox // // Adds a box with the specified dimensions to the empty list. // //========================================================================== -void D3DFB::PackingTexture::AddEmptyBox(int left, int top, int right, int bottom) +void D3DFB::Atlas::AddEmptyBox(int left, int top, int right, int bottom) { PackedTexture *box = AllocateBox(); box->Area.left = left; @@ -2236,14 +2241,14 @@ void D3DFB::PackingTexture::AddEmptyBox(int left, int top, int right, int bottom //========================================================================== // -// PackingTexture :: AllocateBox +// Atlas :: AllocateBox // // Returns a new PackedTexture box, either by retrieving one off the free // list or by creating a new one. The box is not linked into a list. // //========================================================================== -D3DFB::PackedTexture *D3DFB::PackingTexture::AllocateBox() +D3DFB::PackedTexture *D3DFB::Atlas::AllocateBox() { PackedTexture *box; @@ -2266,7 +2271,7 @@ D3DFB::PackedTexture *D3DFB::PackingTexture::AllocateBox() //========================================================================== // -// PackingTexture :: FreeBox +// Atlas :: FreeBox // // Removes a box from its current list and adds it to the empty list, // updating EmptyArea. If there are no boxes left in the used list, then @@ -2275,7 +2280,7 @@ D3DFB::PackedTexture *D3DFB::PackingTexture::AllocateBox() // //========================================================================== -void D3DFB::PackingTexture::FreeBox(D3DFB::PackedTexture *box) +void D3DFB::Atlas::FreeBox(D3DFB::PackedTexture *box) { *(box->Prev) = box->Next; if (box->Next != NULL) @@ -4004,7 +4009,7 @@ void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR bo SetTexture(1, texture); } -void D3DFB::SetPalTexBilinearConstants(PackingTexture *tex) +void D3DFB::SetPalTexBilinearConstants(Atlas *tex) { #if 0 float con[8]; diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 934931ea0..a64b1dd82 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -279,7 +279,7 @@ private: friend class D3DPal; struct PackedTexture; - struct PackingTexture; + struct Atlas; struct FBVERTEX { @@ -392,7 +392,7 @@ private: void SetPixelShader(IDirect3DPixelShader9 *shader); void SetTexture(int tnum, IDirect3DTexture9 *texture); void SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color); - void SetPalTexBilinearConstants(PackingTexture *texture); + void SetPalTexBilinearConstants(Atlas *texture); BOOL AlphaTestEnabled; BOOL AlphaBlendEnabled; @@ -431,7 +431,7 @@ private: BYTE BlockNum; D3DPal *Palettes; D3DTex *Textures; - PackingTexture *Packs; + Atlas *Atlases; HRESULT LastHR; UINT Adapter; From bf31d66d312bbf3b557bab0662f654a1015c0af5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Jan 2016 22:07:16 -0600 Subject: [PATCH 272/335] Use a better packing algorithm for the texture atlases - The old algorithm is something I threw together that produced decent, but not spectacular results since it had a tendency to waste space by forcing everything onto "shelves". The new packer is the Skyline-MinWaste-WasteMap-BestFirstFit algorithm described by Jukka Jylanki in his paper *A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing*, which can currently be read at http://clb.demon.fi/files/RectangleBinPack.pdf This is minus the optimization to rotate rectangles to make better fits. --- src/CMakeLists.txt | 2 + src/GuillotineBinPack.cpp | 633 ++++++++++++++++++++++++++++++++++++++ src/GuillotineBinPack.h | 135 ++++++++ src/Rect.h | 94 ++++++ src/SkylineBinPack.cpp | 329 ++++++++++++++++++++ src/SkylineBinPack.h | 88 ++++++ src/win32/fb_d3d9.cpp | 327 +++++--------------- src/win32/win32iface.h | 1 + zdoom.vcproj | 20 ++ 9 files changed, 1378 insertions(+), 251 deletions(-) create mode 100644 src/GuillotineBinPack.cpp create mode 100644 src/GuillotineBinPack.h create mode 100644 src/Rect.h create mode 100644 src/SkylineBinPack.cpp create mode 100644 src/SkylineBinPack.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8503fabcf..90748f257 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -995,6 +995,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE wi_stuff.cpp zstrformat.cpp zstring.cpp + GuillotineBinPack.cpp + SkylineBinPack.cpp g_doom/a_doommisc.cpp g_heretic/a_hereticmisc.cpp g_hexen/a_hexenmisc.cpp diff --git a/src/GuillotineBinPack.cpp b/src/GuillotineBinPack.cpp new file mode 100644 index 000000000..61ac7a4ce --- /dev/null +++ b/src/GuillotineBinPack.cpp @@ -0,0 +1,633 @@ +/** @file GuillotineBinPack.cpp + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ + +#include + +#include "GuillotineBinPack.h" + +using namespace std; + +GuillotineBinPack::GuillotineBinPack() +:binWidth(0), +binHeight(0) +{ +} + +GuillotineBinPack::GuillotineBinPack(int width, int height) +{ + Init(width, height); +} + +void GuillotineBinPack::Init(int width, int height) +{ + binWidth = width; + binHeight = height; + +#ifdef _DEBUG + disjointRects.Clear(); +#endif + + // Clear any memory of previously packed rectangles. + usedRectangles.Clear(); + + // We start with a single big free rectangle that spans the whole bin. + Rect n; + n.x = 0; + n.y = 0; + n.width = width; + n.height = height; + + freeRectangles.Clear(); + freeRectangles.Push(n); +} + +void GuillotineBinPack::Insert(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + dst.Clear(); + + // Remember variables about the best packing choice we have made so far during the iteration process. + int bestFreeRect = 0; + int bestRect = 0; + bool bestFlipped = false; + + // Pack rectangles one at a time until we have cleared the rects array of all rectangles. + // rects will get destroyed in the process. + while(rects.Size() > 0) + { + // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. + int bestScore = INT_MAX; + + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + { + for(unsigned j = 0; j < rects.Size(); ++j) + { + // If this rectangle is a perfect match, we pick it instantly. + if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = INT_MIN; + i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // If flipping this rectangle is a perfect match, pick that then. + else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = INT_MIN; + i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // Try if we can fit the rectangle upright. + else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(rects[j].width, rects[j].height, freeRectangles[i], rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = score; + } + } + // If not, then perhaps flipping sideways will make it fit? + else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(rects[j].height, rects[j].width, freeRectangles[i], rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = score; + } + } + } + } + + // If we didn't manage to find any rectangle to pack, abort. + if (bestScore == INT_MAX) + return; + + // Otherwise, we're good to go and do the actual packing. + Rect newNode; + newNode.x = freeRectangles[bestFreeRect].x; + newNode.y = freeRectangles[bestFreeRect].y; + newNode.width = rects[bestRect].width; + newNode.height = rects[bestRect].height; + + if (bestFlipped) + std::swap(newNode.width, newNode.height); + + // Remove the free space we lost in the bin. + SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod); + freeRectangles.Delete(bestFreeRect); + + // Remove the rectangle we just packed from the input list. + rects.Delete(bestRect); + + // Perform a Rectangle Merge step if desired. + if (merge) + MergeFreeList(); + + // Remember the new used rectangle. + usedRectangles.Push(newNode); + + // Check that we're really producing correct packings here. + assert(disjointRects.Add(newNode) == true); + } +} + +/// @return True if r fits inside freeRect (possibly rotated). +bool Fits(const RectSize &r, const Rect &freeRect) +{ + return (r.width <= freeRect.width && r.height <= freeRect.height) || + (r.height <= freeRect.width && r.width <= freeRect.height); +} + +/// @return True if r fits perfectly inside freeRect, i.e. the leftover area is 0. +bool FitsPerfectly(const RectSize &r, const Rect &freeRect) +{ + return (r.width == freeRect.width && r.height == freeRect.height) || + (r.height == freeRect.width && r.width == freeRect.height); +} + +/* +// A helper function for GUILLOTINE-MAXFITTING. Counts how many rectangles fit into the given rectangle +// after it has been split. +void CountNumFitting(const Rect &freeRect, int width, int height, const TArray &rects, + int usedRectIndex, bool splitHorizontal, int &score1, int &score2) +{ + const int w = freeRect.width - width; + const int h = freeRect.height - height; + + Rect bottom; + bottom.x = freeRect.x; + bottom.y = freeRect.y + height; + bottom.height = h; + + Rect right; + right.x = freeRect.x + width; + right.y = freeRect.y; + right.width = w; + + if (splitHorizontal) + { + bottom.width = freeRect.width; + right.height = height; + } + else // Split vertically + { + bottom.width = width; + right.height = freeRect.height; + } + + int fitBottom = 0; + int fitRight = 0; + for(size_t i = 0; i < rects.size(); ++i) + if (i != usedRectIndex) + { + if (FitsPerfectly(rects[i], bottom)) + fitBottom |= 0x10000000; + if (FitsPerfectly(rects[i], right)) + fitRight |= 0x10000000; + + if (Fits(rects[i], bottom)) + ++fitBottom; + if (Fits(rects[i], right)) + ++fitRight; + } + + score1 = min(fitBottom, fitRight); + score2 = max(fitBottom, fitRight); +} +*/ +/* +// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice. +void GuillotineBinPack::InsertMaxFitting(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + dst.clear(); + int bestRect = 0; + bool bestFlipped = false; + bool bestSplitHorizontal = false; + + // Pick rectangles one at a time and pack the one that leaves the most choices still open. + while(rects.size() > 0 && freeRectangles.size() > 0) + { + int bestScore1 = -1; + int bestScore2 = -1; + + ///\todo Different sort predicates. + clb::sort::QuickSort(&freeRectangles[0], freeRectangles.size(), CompareRectShortSide); + + Rect &freeRect = freeRectangles[0]; + + for(size_t j = 0; j < rects.size(); ++j) + { + int score1; + int score2; + + if (rects[j].width == freeRect.width && rects[j].height == freeRect.height) + { + bestRect = j; + bestFlipped = false; + bestScore1 = bestScore2 = std::numeric_limits::max(); + break; + } + else if (rects[j].width <= freeRect.width && rects[j].height <= freeRect.height) + { + CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, false, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = false; + bestSplitHorizontal = false; + } + + CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, true, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = false; + bestSplitHorizontal = true; + } + } + + if (rects[j].height == freeRect.width && rects[j].width == freeRect.height) + { + bestRect = j; + bestFlipped = true; + bestScore1 = bestScore2 = std::numeric_limits::max(); + break; + } + else if (rects[j].height <= freeRect.width && rects[j].width <= freeRect.height) + { + CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, false, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = true; + bestSplitHorizontal = false; + } + + CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, true, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = true; + bestSplitHorizontal = true; + } + } + } + + if (bestScore1 >= 0) + { + Rect newNode; + newNode.x = freeRect.x; + newNode.y = freeRect.y; + newNode.width = rects[bestRect].width; + newNode.height = rects[bestRect].height; + if (bestFlipped) + std::swap(newNode.width, newNode.height); + + assert(disjointRects.Disjoint(newNode)); + SplitFreeRectAlongAxis(freeRect, newNode, bestSplitHorizontal); + + rects.erase(rects.begin() + bestRect); + + if (merge) + MergeFreeList(); + + usedRectangles.push_back(newNode); +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + + freeRectangles.erase(freeRectangles.begin()); + } +} +*/ + +Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, + GuillotineSplitHeuristic splitMethod) +{ + // Find where to put the new rectangle. + int freeNodeIndex = 0; + Rect newRect = FindPositionForNewNode(width, height, rectChoice, &freeNodeIndex); + + // Abort if we didn't have enough space in the bin. + if (newRect.height == 0) + return newRect; + + // Remove the space that was just consumed by the new rectangle. + SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, splitMethod); + freeRectangles.Delete(freeNodeIndex); + + // Perform a Rectangle Merge step if desired. + if (merge) + MergeFreeList(); + + // Remember the new used rectangle. + usedRectangles.Push(newRect); + + // Check that we're really producing correct packings here. + assert(disjointRects.Add(newRect) == true); + + return newRect; +} + +/// Computes the ratio of used surface area to the total bin area. +float GuillotineBinPack::Occupancy() const +{ + ///\todo The occupancy rate could be cached/tracked incrementally instead + /// of looping through the list of packed rectangles here. + unsigned long usedSurfaceArea = 0; + for(unsigned i = 0; i < usedRectangles.Size(); ++i) + usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height; + + return (float)usedSurfaceArea / (binWidth * binHeight); +} + +/// Returns the heuristic score value for placing a rectangle of size width*height into freeRect. Does not try to rotate. +int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice) +{ + switch(rectChoice) + { + case RectBestAreaFit: return ScoreBestAreaFit(width, height, freeRect); + case RectBestShortSideFit: return ScoreBestShortSideFit(width, height, freeRect); + case RectBestLongSideFit: return ScoreBestLongSideFit(width, height, freeRect); + case RectWorstAreaFit: return ScoreWorstAreaFit(width, height, freeRect); + case RectWorstShortSideFit: return ScoreWorstShortSideFit(width, height, freeRect); + case RectWorstLongSideFit: return ScoreWorstLongSideFit(width, height, freeRect); + default: assert(false); return INT_MAX; + } +} + +int GuillotineBinPack::ScoreBestAreaFit(int width, int height, const Rect &freeRect) +{ + return freeRect.width * freeRect.height - width * height; +} + +int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect &freeRect) +{ + int leftoverHoriz = abs(freeRect.width - width); + int leftoverVert = abs(freeRect.height - height); + int leftover = min(leftoverHoriz, leftoverVert); + return leftover; +} + +int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &freeRect) +{ + int leftoverHoriz = abs(freeRect.width - width); + int leftoverVert = abs(freeRect.height - height); + int leftover = max(leftoverHoriz, leftoverVert); + return leftover; +} + +int GuillotineBinPack::ScoreWorstAreaFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestAreaFit(width, height, freeRect); +} + +int GuillotineBinPack::ScoreWorstShortSideFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestShortSideFit(width, height, freeRect); +} + +int GuillotineBinPack::ScoreWorstLongSideFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestLongSideFit(width, height, freeRect); +} + +Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex) +{ + Rect bestNode; + memset(&bestNode, 0, sizeof(Rect)); + + int bestScore = INT_MAX; + + /// Try each free rectangle to find the best one for placement. + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + { + // If this is a perfect fit upright, choose it immediately. + if (width == freeRectangles[i].width && height == freeRectangles[i].height) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = width; + bestNode.height = height; + bestScore = INT_MIN; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + break; + } + // If this is a perfect fit sideways, choose it. +/* else if (height == freeRectangles[i].width && width == freeRectangles[i].height) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = height; + bestNode.height = width; + bestScore = INT_MIN; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + break; + } +*/ // Does the rectangle fit upright? + else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice); + + if (score < bestScore) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = width; + bestNode.height = height; + bestScore = score; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + } + } + // Does the rectangle fit sideways? +/* else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice); + + if (score < bestScore) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = height; + bestNode.height = width; + bestScore = score; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + } + } +*/ } + return bestNode; +} + +void GuillotineBinPack::SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method) +{ + // Compute the lengths of the leftover area. + const int w = freeRect.width - placedRect.width; + const int h = freeRect.height - placedRect.height; + + // Placing placedRect into freeRect results in an L-shaped free area, which must be split into + // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line. + // We have two choices: horizontal or vertical. + + // Use the given heuristic to decide which choice to make. + + bool splitHorizontal; + switch(method) + { + case SplitShorterLeftoverAxis: + // Split along the shorter leftover axis. + splitHorizontal = (w <= h); + break; + case SplitLongerLeftoverAxis: + // Split along the longer leftover axis. + splitHorizontal = (w > h); + break; + case SplitMinimizeArea: + // Maximize the larger area == minimize the smaller area. + // Tries to make the single bigger rectangle. + splitHorizontal = (placedRect.width * h > w * placedRect.height); + break; + case SplitMaximizeArea: + // Maximize the smaller area == minimize the larger area. + // Tries to make the rectangles more even-sized. + splitHorizontal = (placedRect.width * h <= w * placedRect.height); + break; + case SplitShorterAxis: + // Split along the shorter total axis. + splitHorizontal = (freeRect.width <= freeRect.height); + break; + case SplitLongerAxis: + // Split along the longer total axis. + splitHorizontal = (freeRect.width > freeRect.height); + break; + default: + splitHorizontal = true; + assert(false); + } + + // Perform the actual split. + SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal); +} + +/// This function will add the two generated rectangles into the freeRectangles array. The caller is expected to +/// remove the original rectangle from the freeRectangles array after that. +void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal) +{ + // Form the two new rectangles. + Rect bottom; + bottom.x = freeRect.x; + bottom.y = freeRect.y + placedRect.height; + bottom.height = freeRect.height - placedRect.height; + + Rect right; + right.x = freeRect.x + placedRect.width; + right.y = freeRect.y; + right.width = freeRect.width - placedRect.width; + + if (splitHorizontal) + { + bottom.width = freeRect.width; + right.height = placedRect.height; + } + else // Split vertically + { + bottom.width = placedRect.width; + right.height = freeRect.height; + } + + // Add the new rectangles into the free rectangle pool if they weren't degenerate. + if (bottom.width > 0 && bottom.height > 0) + freeRectangles.Push(bottom); + if (right.width > 0 && right.height > 0) + freeRectangles.Push(right); + + assert(disjointRects.Disjoint(bottom)); + assert(disjointRects.Disjoint(right)); +} + +void GuillotineBinPack::MergeFreeList() +{ +#ifdef _DEBUG + DisjointRectCollection test; + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + assert(test.Add(freeRectangles[i]) == true); +#endif + + // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one. + // Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that) + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + for(unsigned j = i+1; j < freeRectangles.Size(); ++j) + { + if (freeRectangles[i].width == freeRectangles[j].width && freeRectangles[i].x == freeRectangles[j].x) + { + if (freeRectangles[i].y == freeRectangles[j].y + freeRectangles[j].height) + { + freeRectangles[i].y -= freeRectangles[j].height; + freeRectangles[i].height += freeRectangles[j].height; + freeRectangles.Delete(j); + --j; + } + else if (freeRectangles[i].y + freeRectangles[i].height == freeRectangles[j].y) + { + freeRectangles[i].height += freeRectangles[j].height; + freeRectangles.Delete(j); + --j; + } + } + else if (freeRectangles[i].height == freeRectangles[j].height && freeRectangles[i].y == freeRectangles[j].y) + { + if (freeRectangles[i].x == freeRectangles[j].x + freeRectangles[j].width) + { + freeRectangles[i].x -= freeRectangles[j].width; + freeRectangles[i].width += freeRectangles[j].width; + freeRectangles.Delete(j); + --j; + } + else if (freeRectangles[i].x + freeRectangles[i].width == freeRectangles[j].x) + { + freeRectangles[i].width += freeRectangles[j].width; + freeRectangles.Delete(j); + --j; + } + } + } + +#ifdef _DEBUG + test.Clear(); + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + assert(test.Add(freeRectangles[i]) == true); +#endif +} diff --git a/src/GuillotineBinPack.h b/src/GuillotineBinPack.h new file mode 100644 index 000000000..54cd77a9e --- /dev/null +++ b/src/GuillotineBinPack.h @@ -0,0 +1,135 @@ +/** @file GuillotineBinPack.h + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include "tarray.h" + +#include "Rect.h" + +/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure + to keep track of the free space of the bin where rectangles may be placed. */ +class GuillotineBinPack +{ +public: + /// The initial bin size will be (0,0). Call Init to set the bin size. + GuillotineBinPack(); + + /// Initializes a new bin of the given size. + GuillotineBinPack(int width, int height); + + /// (Re)initializes the packer to an empty bin of width x height units. Call whenever + /// you need to restart with a new bin. + void Init(int width, int height); + + /// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles + /// to place the to-be-packed rectangle into. + enum FreeRectChoiceHeuristic + { + RectBestAreaFit, ///< -BAF + RectBestShortSideFit, ///< -BSSF + RectBestLongSideFit, ///< -BLSF + RectWorstAreaFit, ///< -WAF + RectWorstShortSideFit, ///< -WSSF + RectWorstLongSideFit ///< -WLSF + }; + + /// Specifies the different choice heuristics that can be used when the packer needs to decide whether to + /// subdivide the remaining free space in horizontal or vertical direction. + enum GuillotineSplitHeuristic + { + SplitShorterLeftoverAxis, ///< -SLAS + SplitLongerLeftoverAxis, ///< -LLAS + SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small. + SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible. + SplitShorterAxis, ///< -SAS + SplitLongerAxis ///< -LAS + }; + + /// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned + /// struct will have the width and height values swapped. + /// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure + /// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up + /// some extra time. + /// @param rectChoice The free rectangle choice heuristic rule to use. + /// @param splitMethod The free rectangle split heuristic rule to use. + Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + + /// Inserts a list of rectangles into the bin. + /// @param rects The list of rectangles to add. This list will be destroyed in the packing process. + /// @param dst The outputted list of rectangles. Note that the indices will not correspond to the input indices. + /// @param merge If true, performs Rectangle Merge operations during the packing process. + /// @param rectChoice The free rectangle choice heuristic rule to use. + /// @param splitMethod The free rectangle split heuristic rule to use. + void Insert(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + +// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice. +// void InsertMaxFitting(TArray &rects, TArray &dst, bool merge, +// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + + /// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used. + float Occupancy() const; + + /// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector + /// any way desired, as long as the end result still is a list of disjoint rectangles. + TArray &GetFreeRectangles() { return freeRectangles; } + + /// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from + /// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation. + TArray &GetUsedRectangles() { return usedRectangles; } + + /// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they + /// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time. + void MergeFreeList(); + +#ifdef _DEBUG + void DelDisjoint(const Rect &r) { disjointRects.Del(r); } +#endif + +private: + int binWidth; + int binHeight; + + /// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio, + /// so if you want to have the packer consume less memory, this can be removed. + TArray usedRectangles; + + /// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint. + TArray freeRectangles; + +#ifdef _DEBUG + /// Used to track that the packer produces proper packings. + DisjointRectCollection disjointRects; +#endif + + /// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into. + /// Running time is Theta(|freeRectangles|). + /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new + /// rect was placed. + /// @return A Rect structure that represents the placement of the new rect into the best free rectangle. + Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex); + + static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice); + // The following functions compute (penalty) score values if a rect of the given size was placed into the + // given free rectangle. In these score values, smaller is better. + + static int ScoreBestAreaFit(int width, int height, const Rect &freeRect); + static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect); + static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect); + + static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect); + static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect); + static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect); + + /// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it. + /// Determines the split axis by using the given heuristic. + void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method); + + /// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis. + void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal); +}; diff --git a/src/Rect.h b/src/Rect.h new file mode 100644 index 000000000..8b7ba1e2a --- /dev/null +++ b/src/Rect.h @@ -0,0 +1,94 @@ +/** @file Rect.h + @author Jukka Jylänki + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include + +struct RectSize +{ + int width; + int height; +}; + +struct Rect +{ + int x; + int y; + int width; + int height; +}; + +/// Performs a lexicographic compare on (rect short side, rect long side). +/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around. +/// If they are equal, the larger side length is used as a tie-breaker. +/// If the rectangles are of same size, returns 0. +int CompareRectShortSide(const Rect &a, const Rect &b); + +/// Performs a lexicographic compare on (x, y, width, height). +int NodeSortCmp(const Rect &a, const Rect &b); + +/// Returns true if a is contained in b. +bool IsContainedIn(const Rect &a, const Rect &b); + +#ifdef _DEBUG +class DisjointRectCollection +{ +public: + TArray rects; + + bool Add(const Rect &r) + { + // Degenerate rectangles are ignored. + if (r.width == 0 || r.height == 0) + return true; + + if (!Disjoint(r)) + return false; + rects.Push(r); + return true; + } + + bool Del(const Rect &r) + { + for(unsigned i = 0; i < rects.Size(); ++i) + { + if(r.x == rects[i].x && r.y == rects[i].y && r.width == rects[i].width && r.height == rects[i].height) + { + rects.Delete(i); + return true; + } + } + return false; + } + + void Clear() + { + rects.Clear(); + } + + bool Disjoint(const Rect &r) const + { + // Degenerate rectangles are ignored. + if (r.width == 0 || r.height == 0) + return true; + + for(unsigned i = 0; i < rects.Size(); ++i) + if (!Disjoint(rects[i], r)) + return false; + return true; + } + + static bool Disjoint(const Rect &a, const Rect &b) + { + if (a.x + a.width <= b.x || + b.x + b.width <= a.x || + a.y + a.height <= b.y || + b.y + b.height <= a.y) + return true; + return false; + } +}; +#endif diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp new file mode 100644 index 000000000..578a248a5 --- /dev/null +++ b/src/SkylineBinPack.cpp @@ -0,0 +1,329 @@ +/** @file SkylineBinPack.cpp + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the SKYLINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ + +#include + +#include "SkylineBinPack.h" + +using namespace std; + +SkylineBinPack::SkylineBinPack() +:binWidth(0), +binHeight(0) +{ +} + +SkylineBinPack::SkylineBinPack(int width, int height, bool useWasteMap) +{ + Init(width, height, useWasteMap); +} + +void SkylineBinPack::Init(int width, int height, bool useWasteMap_) +{ + binWidth = width; + binHeight = height; + + useWasteMap = useWasteMap_; + +#ifdef _DEBUG + disjointRects.Clear(); +#endif + + usedSurfaceArea = 0; + skyLine.Clear(); + SkylineNode node; + node.x = 0; + node.y = 0; + node.width = binWidth; + skyLine.Push(node); + + if (useWasteMap) + { + wasteMap.Init(width, height); + wasteMap.GetFreeRectangles().Clear(); + } +} + +void SkylineBinPack::Insert(TArray &rects, TArray &dst) +{ + dst.Clear(); + + while(rects.Size() > 0) + { + Rect bestNode; + int bestScore1 = INT_MAX; + int bestScore2 = INT_MAX; + int bestSkylineIndex = -1; + int bestRectIndex = -1; + for(unsigned i = 0; i < rects.Size(); ++i) + { + Rect newNode; + int score1; + int score2; + int index; + newNode = FindPositionForNewNodeMinWaste(rects[i].width, rects[i].height, score2, score1, index); + assert(disjointRects.Disjoint(newNode)); + if (newNode.height != 0) + { + if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) + { + bestNode = newNode; + bestScore1 = score1; + bestScore2 = score2; + bestSkylineIndex = index; + bestRectIndex = i; + } + } + } + + if (bestRectIndex == -1) + return; + + // Perform the actual packing. + assert(disjointRects.Disjoint(bestNode)); +#ifdef _DEBUG + disjointRects.Add(bestNode); +#endif + AddSkylineLevel(bestSkylineIndex, bestNode); + usedSurfaceArea += rects[bestRectIndex].width * rects[bestRectIndex].height; + rects.Delete(bestRectIndex); + dst.Push(bestNode); + } +} + +Rect SkylineBinPack::Insert(int width, int height) +{ + // First try to pack this rectangle into the waste map, if it fits. + Rect node = wasteMap.Insert(width, height, true, GuillotineBinPack::RectBestShortSideFit, + GuillotineBinPack::SplitMaximizeArea); + assert(disjointRects.Disjoint(node)); + + if (node.height != 0) + { + Rect newNode; + newNode.x = node.x; + newNode.y = node.y; + newNode.width = node.width; + newNode.height = node.height; + usedSurfaceArea += width * height; + assert(disjointRects.Disjoint(newNode)); +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + return newNode; + } + + return InsertMinWaste(width, height); +} + +bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const +{ + int x = skyLine[skylineNodeIndex].x; + if (x + width > binWidth) + return false; + int widthLeft = width; + int i = skylineNodeIndex; + y = skyLine[skylineNodeIndex].y; + while(widthLeft > 0) + { + y = max(y, skyLine[i].y); + if (y + height > binHeight) + return false; + widthLeft -= skyLine[i].width; + ++i; + assert(i < (int)skyLine.Size() || widthLeft <= 0); + } + return true; +} + +int SkylineBinPack::ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const +{ + int wastedArea = 0; + const int rectLeft = skyLine[skylineNodeIndex].x; + const int rectRight = rectLeft + width; + for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex) + { + if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft) + break; + + int leftSide = skyLine[skylineNodeIndex].x; + int rightSide = min(rectRight, leftSide + skyLine[skylineNodeIndex].width); + assert(y >= skyLine[skylineNodeIndex].y); + wastedArea += (rightSide - leftSide) * (y - skyLine[skylineNodeIndex].y); + } + return wastedArea; +} + +bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const +{ + bool fits = RectangleFits(skylineNodeIndex, width, height, y); + if (fits) + wastedArea = ComputeWastedArea(skylineNodeIndex, width, height, y); + + return fits; +} + +void SkylineBinPack::AddWasteMapArea(int skylineNodeIndex, int width, int height, int y) +{ + int wastedArea = 0; + const int rectLeft = skyLine[skylineNodeIndex].x; + const int rectRight = rectLeft + width; + for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex) + { + if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft) + break; + + int leftSide = skyLine[skylineNodeIndex].x; + int rightSide = min(rectRight, leftSide + skyLine[skylineNodeIndex].width); + assert(y >= skyLine[skylineNodeIndex].y); + + Rect waste; + waste.x = leftSide; + waste.y = skyLine[skylineNodeIndex].y; + waste.width = rightSide - leftSide; + waste.height = y - skyLine[skylineNodeIndex].y; + + assert(disjointRects.Disjoint(waste)); + wasteMap.GetFreeRectangles().Push(waste); + } +} + +void SkylineBinPack::AddWaste(const Rect &waste) +{ + wasteMap.GetFreeRectangles().Push(waste); +#ifdef _DEBUG + disjointRects.Del(waste); + wasteMap.DelDisjoint(waste); +#endif +} + +void SkylineBinPack::AddSkylineLevel(int skylineNodeIndex, const Rect &rect) +{ + // First track all wasted areas and mark them into the waste map if we're using one. + if (useWasteMap) + AddWasteMapArea(skylineNodeIndex, rect.width, rect.height, rect.y); + + SkylineNode newNode; + newNode.x = rect.x; + newNode.y = rect.y + rect.height; + newNode.width = rect.width; + skyLine.Insert(skylineNodeIndex, newNode); + + assert(newNode.x + newNode.width <= binWidth); + assert(newNode.y <= binHeight); + + for(unsigned i = skylineNodeIndex+1; i < skyLine.Size(); ++i) + { + assert(skyLine[i-1].x <= skyLine[i].x); + + if (skyLine[i].x < skyLine[i-1].x + skyLine[i-1].width) + { + int shrink = skyLine[i-1].x + skyLine[i-1].width - skyLine[i].x; + + skyLine[i].x += shrink; + skyLine[i].width -= shrink; + + if (skyLine[i].width <= 0) + { + skyLine.Delete(i); + --i; + } + else + break; + } + else + break; + } + MergeSkylines(); +} + +void SkylineBinPack::MergeSkylines() +{ + for(unsigned i = 0; i < skyLine.Size()-1; ++i) + if (skyLine[i].y == skyLine[i+1].y) + { + skyLine[i].width += skyLine[i+1].width; + skyLine.Delete(i+1); + --i; + } +} + +Rect SkylineBinPack::InsertMinWaste(int width, int height) +{ + int bestHeight; + int bestWastedArea; + int bestIndex; + Rect newNode = FindPositionForNewNodeMinWaste(width, height, bestHeight, bestWastedArea, bestIndex); + + if (bestIndex != -1) + { + assert(disjointRects.Disjoint(newNode)); + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(newNode)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestWastedArea = INT_MAX; + bestIndex = -1; + Rect newNode; + memset(&newNode, 0, sizeof(newNode)); + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + int wastedArea; + + if (RectangleFits(i, width, height, y, wastedArea)) + { + if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + height < bestHeight)) + { + bestHeight = y + height; + bestWastedArea = wastedArea; + bestIndex = i; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; + assert(disjointRects.Disjoint(newNode)); + } + } +/* if (RectangleFits(i, height, width, y, wastedArea)) + { + if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + width < bestHeight)) + { + bestHeight = y + width; + bestWastedArea = wastedArea; + bestIndex = i; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + }*/ + } + + return newNode; +} + +/// Computes the ratio of used surface area. +float SkylineBinPack::Occupancy() const +{ + return (float)usedSurfaceArea / (binWidth * binHeight); +} diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h new file mode 100644 index 000000000..f93ddd29d --- /dev/null +++ b/src/SkylineBinPack.h @@ -0,0 +1,88 @@ +/** @file SkylineBinPack.h + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the SKYLINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include "tarray.h" + +#include "Rect.h" +#include "GuillotineBinPack.h" + +/** Implements bin packing algorithms that use the SKYLINE data structure to store the bin contents. Uses + GuillotineBinPack as the waste map. */ +class SkylineBinPack +{ +public: + /// Instantiates a bin of size (0,0). Call Init to create a new bin. + SkylineBinPack(); + + /// Instantiates a bin of the given size. + SkylineBinPack(int binWidth, int binHeight, bool useWasteMap); + + /// (Re)initializes the packer to an empty bin of width x height units. Call whenever + /// you need to restart with a new bin. + void Init(int binWidth, int binHeight, bool useWasteMap); + + /// Inserts the given list of rectangles in an offline/batch mode, possibly rotated. + /// @param rects The list of rectangles to insert. This vector will be destroyed in the process. + /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects. + /// @param method The rectangle placement rule to use when packing. + void Insert(TArray &rects, TArray &dst); + + /// Inserts a single rectangle into the bin, possibly rotated. + Rect Insert(int width, int height); + + /// Adds a rectangle to the waste list. It must have been previously returned by + /// Insert or the results are undefined. + void AddWaste(const Rect &rect); + + /// Computes the ratio of used surface area to the total bin area. + float Occupancy() const; + +private: + int binWidth; + int binHeight; + +#ifdef _DEBUG + DisjointRectCollection disjointRects; +#endif + + /// Represents a single level (a horizontal line) of the skyline/horizon/envelope. + struct SkylineNode + { + /// The starting x-coordinate (leftmost). + int x; + + /// The y-coordinate of the skyline level line. + int y; + + /// The line width. The ending coordinate (inclusive) will be x+width-1. + int width; + }; + + TArray skyLine; + + unsigned long usedSurfaceArea; + + /// If true, we use the GuillotineBinPack structure to recover wasted areas into a waste map. + bool useWasteMap; + GuillotineBinPack wasteMap; + + Rect InsertMinWaste(int width, int height); + Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const; + + bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const; + bool RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const; + int ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const; + + void AddWasteMapArea(int skylineNodeIndex, int width, int height, int y); + + void AddSkylineLevel(int skylineNodeIndex, const Rect &rect); + + /// Merges all skyline nodes that are at the same level. + void MergeSkylines(); +}; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 273fcde44..1641df365 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -72,6 +72,7 @@ #include "v_palette.h" #include "w_wad.h" #include "r_data/colormaps.h" +#include "SkylineBinPack.h" // MACROS ------------------------------------------------------------------ @@ -92,7 +93,7 @@ struct D3DFB::PackedTexture { D3DFB::Atlas *Owner; - PackedTexture *Next, **Prev; + PackedTexture **Prev, *Next; // Pixels this image covers RECT Area; @@ -109,18 +110,14 @@ struct D3DFB::Atlas Atlas(D3DFB *fb, int width, int height, D3DFORMAT format); ~Atlas(); - PackedTexture *GetBestFit(int width, int height, int &area); - void AllocateImage(PackedTexture *box, int width, int height); - PackedTexture *AllocateBox(); - void AddEmptyBox(int left, int top, int right, int bottom); + PackedTexture *AllocateImage(const Rect &rect, bool padded); void FreeBox(PackedTexture *box); + SkylineBinPack Packer; Atlas *Next; IDirect3DTexture9 *Tex; D3DFORMAT Format; PackedTexture *UsedList; // Boxes that contain images - PackedTexture *EmptyList; // Boxes that contain empty space - PackedTexture *FreeList; // Boxes that are just waiting to be used int Width, Height; bool OneUse; }; @@ -1871,7 +1868,8 @@ void D3DFB::DrawPackedTextures(int packnum) continue; } - AddColorOnlyQuad(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); + AddColorOnlyRect(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); + AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); CheckQuadBatch(); @@ -1881,12 +1879,12 @@ void D3DFB::DrawPackedTextures(int packnum) quad->Group1 = 0; if (pack->Format == D3DFMT_L8/* && !tex->IsGray*/) { - quad->Flags = BQF_WrapUV | BQF_GamePalette | BQF_DisableAlphaTest; + quad->Flags = BQF_WrapUV | BQF_GamePalette/* | BQF_DisableAlphaTest*/; quad->ShaderNum = BQS_PalTex; } else { - quad->Flags = BQF_WrapUV | BQF_DisableAlphaTest; + quad->Flags = BQF_WrapUV/* | BQF_DisableAlphaTest*/; quad->ShaderNum = BQS_Plain; } quad->Palette = NULL; @@ -1946,16 +1944,6 @@ void D3DFB::DrawPackedTextures(int packnum) VertexPos += 4; IndexPos += 6; - // Draw entries in the empty list. - PackedTexture *box; - int emptynum; - for (box = pack->EmptyList, emptynum = 0; box != NULL; box = box->Next, emptynum++) - { - AddColorOnlyQuad(x + box->Area.left, y + box->Area.top - LBOffsetI, - box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, - empty_colors[emptynum & 7]); - } - x += 256 + 8; if (x > Width - 256) { @@ -1981,54 +1969,43 @@ void D3DFB::DrawPackedTextures(int packnum) D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3DFORMAT format) { - Atlas *bestpack; - PackedTexture *bestbox; - int area; + Atlas *pack; + Rect box; + bool padded; // check for 254 to account for padding if (w > 254 || h > 254 || wrapping) { // Create a new texture atlas. - bestpack = new Atlas(this, w, h, format); - bestpack->OneUse = true; - bestbox = bestpack->GetBestFit(w, h, area); - bestbox->Padded = false; + pack = new Atlas(this, w, h, format); + pack->OneUse = true; + box = pack->Packer.Insert(w, h); + padded = false; } else { // Try to find space in an existing texture atlas. w += 2; // Add padding h += 2; - int bestarea = INT_MAX; - int bestareaever = w * h; - bestpack = NULL; - bestbox = NULL; - for (Atlas *pack = Atlases; pack != NULL; pack = pack->Next) + for (pack = Atlases; pack != NULL; pack = pack->Next) { + // Use the first atlas it fits in. if (pack->Format == format) { - PackedTexture *box = pack->GetBestFit(w, h, area); - if (area == bestareaever) - { // An exact fit! Use it! - bestpack = pack; - bestbox = box; - break; - } - if (area < bestarea) + box = pack->Packer.Insert(w, h); + if (box.width != 0) { - bestarea = area; - bestpack = pack; - bestbox = box; + break; } } } - if (bestpack == NULL) + if (pack == NULL) { // Create a new texture atlas. - bestpack = new Atlas(this, 256, 256, format); - bestbox = bestpack->GetBestFit(w, h, bestarea); + pack = new Atlas(this, 256, 256, format); + box = pack->Packer.Insert(w, h); } - bestbox->Padded = true; + padded = true; } - bestpack->AllocateImage(bestbox, w, h); - return bestbox; + assert(box.width != 0 && box.height != 0); + return pack->AllocateImage(box, padded); } //========================================================================== @@ -2038,18 +2015,23 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D //========================================================================== D3DFB::Atlas::Atlas(D3DFB *fb, int w, int h, D3DFORMAT format) + : Packer(w, h, true) { Tex = NULL; Format = format; UsedList = NULL; - EmptyList = NULL; - FreeList = NULL; OneUse = false; Width = 0; Height = 0; + Next = NULL; - Next = fb->Atlases; - fb->Atlases = this; + // Attach to the end of the atlas list + Atlas **prev = &fb->Atlases; + while (*prev != NULL) + { + prev = &((*prev)->Next); + } + *prev = this; #if 1 if (FAILED(fb->D3DDevice->CreateTexture(w, h, 1, 0, format, D3DPOOL_MANAGED, &Tex, NULL))) @@ -2066,9 +2048,6 @@ D3DFB::Atlas::Atlas(D3DFB *fb, int w, int h, D3DFORMAT format) } Width = w; Height = h; - - // The whole texture is initially empty. - AddEmptyBox(0, 0, w, h); } //========================================================================== @@ -2087,53 +2066,6 @@ D3DFB::Atlas::~Atlas() next = box->Next; delete box; } - for (box = EmptyList; box != NULL; box = next) - { - next = box->Next; - delete box; - } - for (box = FreeList; box != NULL; box = next) - { - next = box->Next; - delete box; - } -} - -//========================================================================== -// -// Atlas :: GetBestFit -// -// Returns the empty box that provides the best fit for the requested -// dimensions, or NULL if none of them are large enough. -// -//========================================================================== - -D3DFB::PackedTexture *D3DFB::Atlas::GetBestFit(int w, int h, int &area) -{ - PackedTexture *box; - int smallestarea = INT_MAX; - PackedTexture *smallestbox = NULL; - - for (box = EmptyList; box != NULL; box = box->Next) - { - int boxw = box->Area.right - box->Area.left; - int boxh = box->Area.bottom - box->Area.top; - if (boxw >= w && boxh >= h) - { - int boxarea = boxw * boxh; - if (boxarea < smallestarea) - { - smallestarea = boxarea; - smallestbox = box; - if (boxw == w && boxh == h) - { // An exact fit! Use it! - break; - } - } - } - } - area = smallestarea; - return smallestbox; } //========================================================================== @@ -2148,24 +2080,22 @@ D3DFB::PackedTexture *D3DFB::Atlas::GetBestFit(int w, int h, int &area) // //========================================================================== -void D3DFB::Atlas::AllocateImage(D3DFB::PackedTexture *box, int w, int h) +D3DFB::PackedTexture *D3DFB::Atlas::AllocateImage(const Rect &rect, bool padded) { - RECT start = box->Area; + PackedTexture *box = new PackedTexture; - box->Area.right = box->Area.left + w; - box->Area.bottom = box->Area.top + h; + box->Owner = this; + box->Area.left = rect.x; + box->Area.top = rect.y; + box->Area.right = rect.x + rect.width; + box->Area.bottom = rect.y + rect.height; - box->Left = float(box->Area.left + box->Padded) / Width; - box->Right = float(box->Area.right - box->Padded) / Width; - box->Top = float(box->Area.top + box->Padded) / Height; - box->Bottom = float(box->Area.bottom - box->Padded) / Height; + box->Left = float(box->Area.left + padded) / Width; + box->Right = float(box->Area.right - padded) / Width; + box->Top = float(box->Area.top + padded) / Height; + box->Bottom = float(box->Area.bottom - padded) / Height; - // Remove it from the empty list. - *(box->Prev) = box->Next; - if (box->Next != NULL) - { - box->Next->Prev = box->Prev; - } + box->Padded = padded; // Add it to the used list. box->Next = UsedList; @@ -2176,96 +2106,6 @@ void D3DFB::Atlas::AllocateImage(D3DFB::PackedTexture *box, int w, int h) UsedList = box; box->Prev = &UsedList; - // If we didn't use the whole box, split the remainder into the empty list. - if (box->Area.bottom + 7 < start.bottom && box->Area.right + 7 < start.right) - { - // Split like this: - // +---+------+ - // |###| | - // +---+------+ - // | | - // | | - // +----------+ - if (box->Area.bottom < start.bottom) - { - AddEmptyBox(start.left, box->Area.bottom, start.right, start.bottom); - } - if (box->Area.right < start.right) - { - AddEmptyBox(box->Area.right, start.top, start.right, box->Area.bottom); - } - } - else - { - // Split like this: - // +---+------+ - // |###| | - // +---+ | - // | | | - // | | | - // +---+------+ - if (box->Area.bottom < start.bottom) - { - AddEmptyBox(start.left, box->Area.bottom, box->Area.right, start.bottom); - } - if (box->Area.right < start.right) - { - AddEmptyBox(box->Area.right, start.top, start.right, start.bottom); - } - } -} - -//========================================================================== -// -// Atlas :: AddEmptyBox -// -// Adds a box with the specified dimensions to the empty list. -// -//========================================================================== - -void D3DFB::Atlas::AddEmptyBox(int left, int top, int right, int bottom) -{ - PackedTexture *box = AllocateBox(); - box->Area.left = left; - box->Area.top = top; - box->Area.right = right; - box->Area.bottom = bottom; - box->Next = EmptyList; - if (box->Next != NULL) - { - box->Next->Prev = &box->Next; - } - box->Prev = &EmptyList; - EmptyList = box; -} - -//========================================================================== -// -// Atlas :: AllocateBox -// -// Returns a new PackedTexture box, either by retrieving one off the free -// list or by creating a new one. The box is not linked into a list. -// -//========================================================================== - -D3DFB::PackedTexture *D3DFB::Atlas::AllocateBox() -{ - PackedTexture *box; - - if (FreeList != NULL) - { - box = FreeList; - FreeList = box->Next; - if (box->Next != NULL) - { - box->Next->Prev = &FreeList; - } - } - else - { - box = new PackedTexture; - box->Owner = this; - } return box; } @@ -2273,10 +2113,9 @@ D3DFB::PackedTexture *D3DFB::Atlas::AllocateBox() // // Atlas :: FreeBox // -// Removes a box from its current list and adds it to the empty list, -// updating EmptyArea. If there are no boxes left in the used list, then -// the empty list is replaced with a single box, so the texture can be -// subdivided again. +// Removes a box from the used list and deletes it. Space is returned to the +// waste list. Once all boxes for this atlas are freed, the entire bin +// packer is reinitialized for maximum efficiency. // //========================================================================== @@ -2287,47 +2126,16 @@ void D3DFB::Atlas::FreeBox(D3DFB::PackedTexture *box) { box->Next->Prev = box->Prev; } - box->Next = EmptyList; - box->Prev = &EmptyList; - if (EmptyList != NULL) - { - EmptyList->Prev = &box->Next; - } - EmptyList = box; + Rect waste; + waste.x = box->Area.left; + waste.y = box->Area.top; + waste.width = box->Area.right - box->Area.left; + waste.height = box->Area.bottom - box->Area.top; + box->Owner->Packer.AddWaste(waste); + delete box; if (UsedList == NULL) - { // No more space in use! Move all but this into the free list. - if (box->Next != NULL) - { - D3DFB::PackedTexture *lastbox; - - // Find the last box in the free list. - lastbox = FreeList; - if (lastbox != NULL) - { - while (lastbox->Next != NULL) - { - lastbox = lastbox->Next; - } - } - // Chain the empty list to the end of the free list. - if (lastbox != NULL) - { - lastbox->Next = box->Next; - box->Next->Prev = &lastbox->Next; - } - else - { - FreeList = box->Next; - box->Next->Prev = &FreeList; - } - box->Next = NULL; - } - // Now this is the only box in the empty list, so it should - // contain the whole texture. - box->Area.left = 0; - box->Area.top = 0; - box->Area.right = Width; - box->Area.bottom = Height; + { + Packer.Init(Width, Height, true); } } @@ -2412,6 +2220,7 @@ bool D3DTex::CheckWrapping(bool wrapping) bool D3DTex::Create(D3DFB *fb, bool wrapping) { + assert(Box == NULL); if (Box != NULL) { Box->Owner->FreeBox(Box); @@ -3441,6 +3250,22 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR IndexPos += 6; } +//========================================================================== +// +// D3DFB :: AddColorOnlyRect +// +// Like AddColorOnlyQuad, except it's hollow. +// +//========================================================================== + +void D3DFB::AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color) +{ + AddColorOnlyQuad(left, top, width - 1, 1, color); // top + AddColorOnlyQuad(left + width - 1, top, 1, height - 1, color); // right + AddColorOnlyQuad(left + 1, top + height - 1, width - 1, 1, color); // bottom + AddColorOnlyQuad(left, top + 1, 1, height - 1, color); // left +} + //========================================================================== // // D3DFB :: CheckQuadBatch diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index a64b1dd82..8b0c88f45 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -375,6 +375,7 @@ private: static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1); void DoWindowedGamma(); void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color); + void AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color); void CheckQuadBatch(int numtris=2, int numverts=4); void BeginQuadBatch(); void EndQuadBatch(); diff --git a/zdoom.vcproj b/zdoom.vcproj index a2587840f..597b56f2f 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -666,6 +666,10 @@ RelativePath=".\src\gitinfo.cpp" > + + @@ -1026,6 +1030,10 @@ RelativePath=".\src\skins.cpp" > + + @@ -1311,6 +1319,10 @@ RelativePath=".\src\gstrings.h" > + + @@ -1491,6 +1503,10 @@ RelativePath=".\src\po_man.h" > + + @@ -1515,6 +1531,10 @@ RelativePath=".\src\skins.h" > + + From 786caaf36b31d27d717a292ca6ef27fc1bde615d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Jan 2016 22:41:23 -0600 Subject: [PATCH 273/335] Execute disconnect scripts immediately before the player is destroyed. - Disconnect scripts were previously run at some point after the player left. Now they are run immediately before destroying the player. Since the player hasn't actually been destroyed yet, the player also gets to be the script's activator. This gives you a chance to scrape whatever data you want from the player before they're history. Note that if you do anything to make the script wait, the script's activator will become the world, as it was before. --- src/b_game.cpp | 2 +- src/g_game.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/b_game.cpp b/src/b_game.cpp index e136f3f29..5f852d043 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -423,8 +423,8 @@ void FCajunMaster::RemoveAllBots (bool fromlist) } } } + FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true); ClearPlayer (i, !fromlist); - FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, i); } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 8101ca23d..64e746cef 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1713,6 +1713,8 @@ void G_DoPlayerPop(int playernum) // [RH] Make the player disappear FBehavior::StaticStopMyScripts(players[playernum].mo); + // [RH] Let the scripts know the player left + FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true); if (players[playernum].mo != NULL) { P_DisconnectEffect(players[playernum].mo); @@ -1726,8 +1728,6 @@ void G_DoPlayerPop(int playernum) players[playernum].mo = NULL; players[playernum].camera = NULL; } - // [RH] Let the scripts know the player left - FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum); } void G_ScreenShot (char *filename) From 0b5e4195936776364a247bfcef323bf9290cbdfc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 10:11:20 +0100 Subject: [PATCH 274/335] - fixed friction logic for sectors. Issues with the old code: * when calculating friction for a 3D-floor - swimmable or not - the 3D floor's top texture must be used. The previous version always checked the sector's floor texture, even though the top might as well come from the sector's ceiling. * 3D floors never checked for the SECF_FRICTION flag at all. According to Boom specs, sector-based friction must be ignored if this is the case. * Terrain based friction had a higher priority than the sector's own value. Changed the rules as follows: * if the sector's SECF_FRICTION flag is set (i.e. something explicitly changed the sector's friction), this value is used regardless of terrain settings. * if this flag is not set, the terrain's friction is used, if defined, using the proper plane for 3D-floors. * otherwise the default is used. --- src/p_map.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index f409dafa4..fe5959df9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -529,16 +529,18 @@ void P_PlayerStartStomp(AActor *actor) // //========================================================================== -inline fixed_t secfriction(const sector_t *sec) +inline fixed_t secfriction(const sector_t *sec, int plane = sector_t::floor) { - fixed_t friction = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction; - return friction != 0 ? friction : sec->friction; + if (sec->Flags & SECF_FRICTION) return sec->friction; + fixed_t friction = Terrains[TerrainTypes[sec->GetTexture(plane)]].Friction; + return friction != 0 ? friction : ORIG_FRICTION; } -inline fixed_t secmovefac(const sector_t *sec) +inline fixed_t secmovefac(const sector_t *sec, int plane = sector_t::floor) { - fixed_t movefactor = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].MoveFactor; - return movefactor != 0 ? movefactor : sec->movefactor; + if (sec->Flags & SECF_FRICTION) return sec->friction; + fixed_t movefactor = Terrains[TerrainTypes[sec->GetTexture(plane)]].MoveFactor; + return movefactor != 0 ? movefactor : ORIG_FRICTION_FACTOR; } //========================================================================== @@ -584,11 +586,11 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) mo->z < rover->bottom.plane->ZatPoint(mo->x, mo->y)) continue; - newfriction = secfriction(rover->model); + newfriction = secfriction(rover->model, rover->top.isceiling); if (newfriction < friction || friction == ORIG_FRICTION) { friction = newfriction; - movefactor = secmovefac(rover->model) >> 1; + movefactor = secmovefac(rover->model, rover->top.isceiling) >> 1; } } } @@ -622,11 +624,11 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) else continue; - newfriction = secfriction(rover->model); + newfriction = secfriction(rover->model, rover->top.isceiling); if (newfriction < friction || friction == ORIG_FRICTION) { friction = newfriction; - movefactor = secmovefac(rover->model); + movefactor = secmovefac(rover->model, rover->top.isceiling); } } From 4b3adf548ac1ea6cdb12515563655f86ff7cb4a8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 11:44:05 +0100 Subject: [PATCH 275/335] - fixed compile errors. --- src/GuillotineBinPack.cpp | 6 +++--- src/SkylineBinPack.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/GuillotineBinPack.cpp b/src/GuillotineBinPack.cpp index 61ac7a4ce..2131ed5db 100644 --- a/src/GuillotineBinPack.cpp +++ b/src/GuillotineBinPack.cpp @@ -7,7 +7,7 @@ */ #include - +#include "templates.h" #include "GuillotineBinPack.h" using namespace std; @@ -395,7 +395,7 @@ int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect & { int leftoverHoriz = abs(freeRect.width - width); int leftoverVert = abs(freeRect.height - height); - int leftover = min(leftoverHoriz, leftoverVert); + int leftover = MIN(leftoverHoriz, leftoverVert); return leftover; } @@ -403,7 +403,7 @@ int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &f { int leftoverHoriz = abs(freeRect.width - width); int leftoverVert = abs(freeRect.height - height); - int leftover = max(leftoverHoriz, leftoverVert); + int leftover = MAX(leftoverHoriz, leftoverVert); return leftover; } diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp index 578a248a5..33f862043 100644 --- a/src/SkylineBinPack.cpp +++ b/src/SkylineBinPack.cpp @@ -7,6 +7,7 @@ */ #include +#include "templates.h" #include "SkylineBinPack.h" @@ -131,7 +132,7 @@ bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, y = skyLine[skylineNodeIndex].y; while(widthLeft > 0) { - y = max(y, skyLine[i].y); + y = MAX(y, skyLine[i].y); if (y + height > binHeight) return false; widthLeft -= skyLine[i].width; @@ -152,7 +153,7 @@ int SkylineBinPack::ComputeWastedArea(int skylineNodeIndex, int width, int heigh break; int leftSide = skyLine[skylineNodeIndex].x; - int rightSide = min(rectRight, leftSide + skyLine[skylineNodeIndex].width); + int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width); assert(y >= skyLine[skylineNodeIndex].y); wastedArea += (rightSide - leftSide) * (y - skyLine[skylineNodeIndex].y); } @@ -179,7 +180,7 @@ void SkylineBinPack::AddWasteMapArea(int skylineNodeIndex, int width, int height break; int leftSide = skyLine[skylineNodeIndex].x; - int rightSide = min(rectRight, leftSide + skyLine[skylineNodeIndex].width); + int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width); assert(y >= skyLine[skylineNodeIndex].y); Rect waste; From 71c7f2b42c115c9f9a0f47e7eeaf0d536573dea1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 12:10:36 +0100 Subject: [PATCH 276/335] - added 'floorterrain' and 'ceilingterrain' sector properties for UDMF. These will take precedence over texture based terrain if used. 'ceilingterrain' is needed because the top of 3D-floors refers to the model sector's ceiling, so in order to give a 3D floor a terrain it must be assignable to the sector's ceiling. Note that although it is basically the same property, its actual function bears no relevance to its use in Eternity. --- specs/udmf_zdoom.txt | 2 ++ src/actor.h | 1 + src/g_level.cpp | 1 + src/namedef.h | 2 ++ src/p_3dfloors.cpp | 5 ++++- src/p_3dmidtex.cpp | 3 +++ src/p_buildmap.cpp | 1 + src/p_local.h | 2 ++ src/p_map.cpp | 18 +++++++++++++++--- src/p_maputl.cpp | 3 +++ src/p_mobj.cpp | 21 ++++++++++++++------- src/p_saveg.cpp | 4 ++++ src/p_sectors.cpp | 6 ++++++ src/p_setup.cpp | 1 + src/p_terrain.cpp | 9 ++++----- src/p_terrain.h | 2 ++ src/p_udmf.cpp | 10 ++++++++++ src/r_defs.h | 4 ++++ src/version.h | 2 +- 19 files changed, 80 insertions(+), 17 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 74d5fb4f7..611a667af 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -212,6 +212,8 @@ Note: All fields default to false unless mentioned otherwise. leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false. damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. + floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.' + ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.' * Note about dropactors diff --git a/src/actor.h b/src/actor.h index 468dcc0c6..cb0524587 100644 --- a/src/actor.h +++ b/src/actor.h @@ -896,6 +896,7 @@ public: struct sector_t *floorsector; FTextureID floorpic; // contacted sec floorpic + int floorterrain; struct sector_t *ceilingsector; FTextureID ceilingpic; // contacted sec ceilingpic fixed_t radius, height; // for movement checking diff --git a/src/g_level.cpp b/src/g_level.cpp index aba58e810..03474a5b7 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1232,6 +1232,7 @@ void G_FinishTravel () pawn->dropoffz = pawndup->dropoffz; pawn->floorsector = pawndup->floorsector; pawn->floorpic = pawndup->floorpic; + pawn->floorterrain = pawndup->floorterrain; pawn->ceilingsector = pawndup->ceilingsector; pawn->ceilingpic = pawndup->ceilingpic; pawn->floorclip = pawndup->floorclip; diff --git a/src/namedef.h b/src/namedef.h index 9ca8cb8ed..ae456883c 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -512,6 +512,8 @@ xx(damageinterval) xx(leakiness) xx(damageterraineffect) xx(damagehazard) +xx(floorterrain) +xx(ceilingterrain) // USDF keywords xx(Amount) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 3fbbfeab7..496809fac 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -346,7 +346,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) // Apply flat specials (using the ceiling!) P_PlayerOnSpecialFlat( - player, TerrainTypes[rover->model->GetTexture(rover->flags & FF_INVERTSECTOR? sector_t::floor : sector_t::ceiling)]); + player, rover->model->GetTerrain(rover->top.isceiling)); break; } @@ -762,6 +762,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li linedef->frontsector->floorplane.ZatPoint(x, y), linedef->backsector->floorplane.ZatPoint(x, y) }; FTextureID highestfloorpic; + int highestfloorterrain = -1; FTextureID lowestceilingpic; highestfloorpic.SetInvalid(); @@ -792,6 +793,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { highestfloor = ff_top; highestfloorpic = *rover->top.texture; + highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); } if(ff_top > lowestfloor[j] && ff_top <= thing->z + thing->MaxStepHeight) lowestfloor[j] = ff_top; } @@ -801,6 +803,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { open.bottom = highestfloor; open.floorpic = highestfloorpic; + open.floorterrain = highestfloorterrain; } if(lowestceiling < open.top) diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 9a9492e08..dbca50d10 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -37,6 +37,7 @@ #include "templates.h" #include "p_local.h" +#include "p_terrain.h" //============================================================================ @@ -290,6 +291,8 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & open.bottom = tt; open.abovemidtex = true; open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid); + open.floorterrain = TerrainTypes[open.floorpic]; + } // returns true if it touches the midtexture return (abs(thing->z - tt) <= thing->MaxStepHeight); diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 670f53751..d9074310d 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -443,6 +443,7 @@ static void LoadSectors (sectortype *bsec) sec->movefactor = ORIG_FRICTION_FACTOR; sec->ColorMap = map; sec->ZoneNumber = 0xFFFF; + sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; if (bsec->floorstat & 4) { diff --git a/src/p_local.h b/src/p_local.h index 63ee4c1b1..fd5064f3c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -293,6 +293,7 @@ struct FLineOpening sector_t *topsec; FTextureID ceilingpic; FTextureID floorpic; + int floorterrain; bool touchmidtex; bool abovemidtex; }; @@ -408,6 +409,7 @@ struct FCheckPosition fixed_t ceilingz; fixed_t dropoffz; FTextureID floorpic; + int floorterrain; sector_t *floorsector; FTextureID ceilingpic; sector_t *ceilingsector; diff --git a/src/p_map.cpp b/src/p_map.cpp index fe5959df9..7aeb9d115 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -242,6 +242,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) tmf.floorz = tmf.dropoffz = sec->floorplane.ZatPoint(tmf.x, tmf.y); tmf.ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y); tmf.floorpic = sec->GetTexture(sector_t::floor); + tmf.floorterrain = sec->GetTerrain(sector_t::floor); tmf.ceilingpic = sec->GetTexture(sector_t::ceiling); } else @@ -264,6 +265,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { tmf.dropoffz = tmf.floorz = ff_top; tmf.floorpic = *rover->top.texture; + tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling); } } if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height) @@ -304,6 +306,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) tmf.floorz = tmf.dropoffz = actor->floorz; tmf.ceilingz = actor->ceilingz; tmf.floorpic = actor->floorpic; + tmf.floorterrain = actor->floorterrain; tmf.ceilingpic = actor->ceilingpic; P_GetFloorCeilingZ(tmf, flags); } @@ -311,6 +314,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) actor->dropoffz = tmf.dropoffz; actor->ceilingz = tmf.ceilingz; actor->floorpic = tmf.floorpic; + actor->floorterrain = tmf.floorterrain; actor->floorsector = tmf.floorsector; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; @@ -337,6 +341,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) actor->dropoffz = tmf.dropoffz; actor->ceilingz = tmf.ceilingz; actor->floorpic = tmf.floorpic; + actor->floorterrain = tmf.floorterrain; actor->floorsector = tmf.floorsector; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; @@ -348,6 +353,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) if (actor->Sector != NULL) { actor->floorpic = actor->Sector->GetTexture(sector_t::floor); + actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor); actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling); } } @@ -455,6 +461,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra thing->ceilingz = tmf.ceilingz; thing->floorsector = tmf.floorsector; thing->floorpic = tmf.floorpic; + thing->floorterrain = tmf.floorterrain; thing->ceilingsector = tmf.ceilingsector; thing->ceilingpic = tmf.ceilingpic; thing->dropoffz = tmf.dropoffz; // killough 11/98 @@ -532,14 +539,14 @@ void P_PlayerStartStomp(AActor *actor) inline fixed_t secfriction(const sector_t *sec, int plane = sector_t::floor) { if (sec->Flags & SECF_FRICTION) return sec->friction; - fixed_t friction = Terrains[TerrainTypes[sec->GetTexture(plane)]].Friction; + fixed_t friction = Terrains[sec->GetTerrain(plane)].Friction; return friction != 0 ? friction : ORIG_FRICTION; } inline fixed_t secmovefac(const sector_t *sec, int plane = sector_t::floor) { if (sec->Flags & SECF_FRICTION) return sec->friction; - fixed_t movefactor = Terrains[TerrainTypes[sec->GetTexture(plane)]].MoveFactor; + fixed_t movefactor = Terrains[sec->GetTerrain(plane)].MoveFactor; return movefactor != 0 ? movefactor : ORIG_FRICTION_FACTOR; } @@ -633,7 +640,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) } if (!(sec->Flags & SECF_FRICTION) && - Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0) + Terrains[sec->GetTerrain(sector_t::floor)].Friction == 0) { continue; } @@ -891,6 +898,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) tm.floorz = open.bottom; tm.floorsector = open.bottomsec; tm.floorpic = open.floorpic; + tm.floorterrain = open.floorterrain; tm.touchmidtex = open.touchmidtex; tm.abovemidtex = open.abovemidtex; tm.thing->BlockingLine = ld; @@ -1436,6 +1444,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(x, y); tm.ceilingz = newsec->ceilingplane.ZatPoint(x, y); tm.floorpic = newsec->GetTexture(sector_t::floor); + tm.floorterrain = newsec->GetTerrain(sector_t::floor); tm.floorsector = newsec; tm.ceilingpic = newsec->GetTexture(sector_t::ceiling); tm.ceilingsector = newsec; @@ -1468,6 +1477,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo { tm.floorz = tm.dropoffz = ff_top; tm.floorpic = *rover->top.texture; + tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); } if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2)) { @@ -2091,6 +2101,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, thing->ceilingz = tm.ceilingz; thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs thing->floorpic = tm.floorpic; + thing->floorterrain = tm.floorterrain; thing->floorsector = tm.floorsector; thing->ceilingpic = tm.ceilingpic; thing->ceilingsector = tm.ceilingsector; @@ -4951,6 +4962,7 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos) thing->ceilingz = tm.ceilingz; thing->dropoffz = tm.dropoffz; // killough 11/98: remember dropoffs thing->floorpic = tm.floorpic; + thing->floorterrain = tm.floorterrain; thing->floorsector = tm.floorsector; thing->ceilingpic = tm.ceilingpic; thing->ceilingsector = tm.ceilingsector; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 0a39460e7..e6d5a99e6 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -194,6 +194,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottom = ff; open.bottomsec = front; open.floorpic = front->GetTexture(sector_t::floor); + open.floorterrain = front->GetTerrain(sector_t::floor); open.lowfloor = bf; } else @@ -201,6 +202,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottom = bf; open.bottomsec = back; open.floorpic = back->GetTexture(sector_t::floor); + open.floorterrain = back->GetTerrain(sector_t::floor); open.lowfloor = ff; } } @@ -211,6 +213,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.top = FIXED_MAX; open.bottomsec = NULL; open.floorpic.SetInvalid(); + open.floorterrain = -1; open.bottom = FIXED_MIN; open.lowfloor = FIXED_MAX; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 48f16ba0e..8c814738e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -191,6 +191,10 @@ void AActor::Serialize (FArchive &arc) << tics << state << Damage; + if (SaveVersion >= 4530) + { + arc << floorterrain; + } if (SaveVersion >= 3227) { arc << projectileKickback; @@ -4035,6 +4039,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t { actor->floorsector = actor->Sector; actor->floorpic = actor->floorsector->GetTexture(sector_t::floor); + actor->floorterrain = actor->floorsector->GetTerrain(sector_t::floor); actor->ceilingsector = actor->Sector; actor->ceilingpic = actor->ceilingsector->GetTexture(sector_t::ceiling); } @@ -4046,6 +4051,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t else { actor->floorpic = actor->Sector->GetTexture(sector_t::floor); + actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor); actor->floorsector = actor->Sector; actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling); actor->ceilingsector = actor->Sector; @@ -4339,7 +4345,7 @@ void AActor::AdjustFloorClip () sector_t *hsec = m->m_sector->GetHeightSec(); if (hsec == NULL && m->m_sector->floorplane.ZatPoint (x, y) == z) { - fixed_t clip = Terrains[TerrainTypes[m->m_sector->GetTexture(sector_t::floor)]].FootClip; + fixed_t clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip; if (clip < shallowestclip) { shallowestclip = clip; @@ -5303,13 +5309,13 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) int P_GetThingFloorType (AActor *thing) { - if (thing->floorpic.isValid()) + if (thing->floorterrain >= 0) { - return TerrainTypes[thing->floorpic]; + return thing->floorterrain; } else { - return TerrainTypes[thing->Sector->GetTexture(sector_t::floor)]; + return thing->Sector->GetTerrain(sector_t::floor); } } @@ -5362,6 +5368,7 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z } #endif + // 'force' means, we want this sector's terrain, no matter what. if (!force) { for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) @@ -5373,7 +5380,7 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z { if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) { - terrainnum = TerrainTypes[*rover->top.texture]; + terrainnum = rover->model->GetTerrain(rover->top.isceiling); goto foundone; } } @@ -5384,11 +5391,11 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z hsec = sec->GetHeightSec(); if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) { - terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)]; + terrainnum = sec->GetTerrain(sector_t::floor); } else { - terrainnum = TerrainTypes[hsec->GetTexture(sector_t::floor)]; + terrainnum = hsec->GetTerrain(sector_t::floor); } foundone: diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 8e2f7e9d9..918eb7a89 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -369,6 +369,10 @@ void P_SerializeWorld (FArchive &arc) << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap << sec->gravity; + if (SaveVersion >= 4530) + { + arc << sec->terrainnum[0] << sec->terrainnum[1]; + } if (SaveVersion >= 4529) { arc << sec->damageamount; diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 321ecdd37..5a60933ba 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -26,6 +26,7 @@ #include "doomstat.h" #include "g_level.h" #include "nodebuild.h" +#include "p_terrain.h" #include "po_man.h" #include "farchive.h" #include "r_utility.h" @@ -873,6 +874,11 @@ void sector_t::TransferSpecial(sector_t *model) Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS); } +int sector_t::GetTerrain(int pos) const +{ + return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)]; +} + FArchive &operator<< (FArchive &arc, secspecial_t &p) { if (SaveVersion < 4529) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 772679269..3749e97aa 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1532,6 +1532,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->gravity = 1.f; // [RH] Default sector gravity of 1.0 ss->ZoneNumber = 0xFFFF; + ss->terrainnum[sector_t::ceiling] = ss->terrainnum[sector_t::floor] = -1; // [RH] Sectors default to white light with the default fade. // If they are outside (have a sky ceiling), they use the outside fog. diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index a1a9ea25b..006835ea6 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -121,7 +121,6 @@ static void ParseSplash (FScanner &sc); static void ParseTerrain (FScanner &sc); static void ParseFloor (FScanner &sc); static int FindSplash (FName name); -static int FindTerrain (FName name); static void GenericParse (FScanner &sc, FGenericParse *parser, const char **keywords, void *fields, const char *type, FName name); static void ParseDamage (FScanner &sc, int keyword, void *fields); @@ -427,7 +426,7 @@ void ParseTerrain (FScanner &sc) sc.MustGetString (); name = sc.String; - terrainnum = (int)FindTerrain (name); + terrainnum = (int)P_FindTerrain (name); if (terrainnum < 0) { FTerrainDef def; @@ -637,7 +636,7 @@ static void ParseFloor (FScanner &sc) return; } sc.MustGetString (); - terrain = FindTerrain (sc.String); + terrain = P_FindTerrain (sc.String); if (terrain == -1) { Printf ("Unknown terrain %s\n", sc.String); @@ -657,7 +656,7 @@ static void ParseDefault (FScanner &sc) int terrain; sc.MustGetString (); - terrain = FindTerrain (sc.String); + terrain = P_FindTerrain (sc.String); if (terrain == -1) { Printf ("Unknown terrain %s\n", sc.String); @@ -692,7 +691,7 @@ int FindSplash (FName name) // //========================================================================== -int FindTerrain (FName name) +int P_FindTerrain (FName name) { unsigned int i; diff --git a/src/p_terrain.h b/src/p_terrain.h index 482c66b00..85059a945 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -122,4 +122,6 @@ struct FTerrainDef extern TArray Splashes; extern TArray Terrains; +int P_FindTerrain(FName name); + #endif //__P_TERRAIN_H__ diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e95193860..9cfcbc0c2 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -47,6 +47,7 @@ #include "r_data/colormaps.h" #include "w_wad.h" #include "p_tags.h" +#include "p_terrain.h" //=========================================================================== // @@ -1300,6 +1301,7 @@ public: sec->heightsec = NULL; // sector used to get floor and ceiling height sec->sectornum = index; sec->damageinterval = 32; + sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes @@ -1550,6 +1552,14 @@ public: Flag(sec->Flags, SECF_HAZARD, key); break; + case NAME_floorterrain: + sec->terrainnum[sector_t::floor] = P_FindTerrain(CheckString(key)); + break; + + case NAME_ceilingterrain: + sec->terrainnum[sector_t::ceiling] = P_FindTerrain(CheckString(key)); + break; + case NAME_MoreIds: // delay parsing of the tag string until parsing of the sector is complete // This ensures that the ID is always the first tag in the list. diff --git a/src/r_defs.h b/src/r_defs.h index 536376b63..a7e37f369 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -699,6 +699,8 @@ struct sector_t Flags &= ~SECF_SPECIALFLAGS; } + int GetTerrain(int pos) const; + void TransferSpecial(sector_t *model); void GetSpecial(secspecial_t *spec); void SetSpecial(const secspecial_t *spec); @@ -734,6 +736,8 @@ struct sector_t // when processed as mobj properties. Fix is to make them sector properties. fixed_t friction, movefactor; + int terrainnum[2]; + // thinker_t for reversable actions TObjPtr floordata; // jff 2/22/98 make thinkers on TObjPtr ceilingdata; // floors, ceilings, lighting, diff --git a/src/version.h b/src/version.h index b10074f41..6a0eb9c4b 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4529 +#define SAVEVER 4530 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 7f454358b9f99ae3ff565c313bb8f8dc4f02aa8b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 12:16:41 +0100 Subject: [PATCH 277/335] - added ACS SetSectorTerrain function. --- src/p_acs.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index aacd5cc4a..c40ba6b94 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -75,6 +75,7 @@ #include "actorptrselect.h" #include "farchive.h" #include "decallib.h" +#include "p_terrain.h" #include "version.h" #include "g_shared/a_pickups.h" @@ -4459,6 +4460,7 @@ enum EACSFunctions ACSF_Warp, // 92 ACSF_GetMaxInventory, ACSF_SetSectorDamage, + ACSF_SetSectorTerrain, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5968,6 +5970,18 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } break; + case ACSF_SetSectorTerrain: + if (argCount >= 3) + { + int terrain = P_FindTerrain(FBehavior::StaticLookupString(args[2])); + FSectorTagIterator it(args[0]); + int s; + while ((s = it.Next()) >= 0) + { + sectors[s].terrainnum[args[1]] = terrain; + } + } + default: break; } From 23cfd29dbb5a837ae04d4522b623ac21836dc396 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 12:28:42 +0100 Subject: [PATCH 278/335] - let's save the terrain properties as names so that they survive a change in the definition files. --- src/p_mobj.cpp | 2 +- src/p_saveg.cpp | 4 +++- src/p_terrain.cpp | 24 ++++++++++++++++++++++++ src/p_terrain.h | 2 ++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8c814738e..3d0d8e072 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -193,7 +193,7 @@ void AActor::Serialize (FArchive &arc) << Damage; if (SaveVersion >= 4530) { - arc << floorterrain; + P_SerializeTerrain(arc, floorterrain); } if (SaveVersion >= 3227) { diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 918eb7a89..db14aeb90 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -52,6 +52,7 @@ #include "farchive.h" #include "p_lnspec.h" #include "p_acs.h" +#include "p_terrain.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); @@ -371,7 +372,8 @@ void P_SerializeWorld (FArchive &arc) << sec->gravity; if (SaveVersion >= 4530) { - arc << sec->terrainnum[0] << sec->terrainnum[1]; + P_SerializeTerrain(arc, sec->terrainnum[0]); + P_SerializeTerrain(arc, sec->terrainnum[1]); } if (SaveVersion >= 4529) { diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 006835ea6..af8de5cab 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -46,6 +46,7 @@ #include "s_sound.h" #include "p_local.h" #include "templates.h" +#include "farchive.h" // MACROS ------------------------------------------------------------------ @@ -704,3 +705,26 @@ int P_FindTerrain (FName name) } return -1; } + +void P_SerializeTerrain(FArchive &arc, int &terrainnum) +{ + FName val; + if (arc.IsStoring()) + { + if (terrainnum < 0 || terrainnum >= (int)Terrains.Size()) + { + val = NAME_Null; + } + else + { + val = Terrains[terrainnum].Name; + } + arc << val; + } + else + { + arc << val; + terrainnum = P_FindTerrain(val); + + } +} diff --git a/src/p_terrain.h b/src/p_terrain.h index 85059a945..dab4904b6 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -122,6 +122,8 @@ struct FTerrainDef extern TArray Splashes; extern TArray Terrains; +class FArchive; int P_FindTerrain(FName name); +void P_SerializeTerrain(FArchive &arc, int &terrainnum); #endif //__P_TERRAIN_H__ From b27fdcffb53bb889b9f41045ff0f6d71559b4be0 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 9 Jan 2016 16:59:13 +0200 Subject: [PATCH 279/335] Added shortcut to toggle fullscreen on OS X Press Command+F to toggle fullscreen mode in native OS X backend Set k_allowfullscreentoggle CVAR to false to disable the shortcut --- src/posix/cocoa/i_common.h | 1 + src/posix/cocoa/i_input.mm | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 545540b2f..7d7f82ac5 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -79,6 +79,7 @@ typedef float CGFloat; // From HIToolbox/Events.h enum { + kVK_ANSI_F = 0x03, kVK_Return = 0x24, kVK_Tab = 0x30, kVK_Space = 0x31, diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 5e0c5f1c8..3bbf42a9a 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -57,6 +57,8 @@ CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) { if (self < 0) @@ -542,6 +544,16 @@ void ProcessKeyboardEvent(NSEvent* theEvent) return; } + if (k_allowfullscreentoggle + && (kVK_ANSI_F == keyCode) + && (NSCommandKeyMask & [theEvent modifierFlags]) + && (NSKeyDown == [theEvent type]) + && ![theEvent isARepeat]) + { + ToggleFullscreen = !ToggleFullscreen; + return; + } + if (GUICapture) { ProcessKeyboardEventInMenu(theEvent); From 53d385a596d60b542a51b3fdfbd0b21bbfff2b15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 21:10:12 +0100 Subject: [PATCH 280/335] - need to validate SetSectorTerrain's 'plane' parameter, --- src/p_acs.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c40ba6b94..87641efe2 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5973,15 +5973,19 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_SetSectorTerrain: if (argCount >= 3) { - int terrain = P_FindTerrain(FBehavior::StaticLookupString(args[2])); - FSectorTagIterator it(args[0]); - int s; - while ((s = it.Next()) >= 0) + if (args[1] == sector_t::floor || args[1] == sector_t::ceiling) { - sectors[s].terrainnum[args[1]] = terrain; + int terrain = P_FindTerrain(FBehavior::StaticLookupString(args[2])); + FSectorTagIterator it(args[0]); + int s; + while ((s = it.Next()) >= 0) + { + sectors[s].terrainnum[args[1]] = terrain; + } } } - + break; + default: break; } From 1f34372abcac269539f7f0617b77788b8a16447e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 9 Jan 2016 17:53:47 -0600 Subject: [PATCH 281/335] Remove the upper limit on midi_voices. - Black MIDIs can be brutal, and there's really no reason that this needs to be artificially limited to a paltry 256 voices. --- src/timidity/timidity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 807bc07b7..440db9211 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -698,7 +698,7 @@ Renderer::Renderer(float sample_rate, const char *args) if (def_instr_name.IsNotEmpty()) set_default_instrument(def_instr_name); - voices = clamp(midi_voices, 16, 256); + voices = MAX(*midi_voices, 16); voice = new Voice[voices]; drumchannels = DEFAULT_DRUMCHANNELS; } From 1e2ce9a6220f6cfcb6d137bb0d7faa68644f268c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 17:52:41 +0100 Subject: [PATCH 282/335] - some refactoring of P_AproxDistance calls into newly defined AActor method AproxDistance. The main reason here is to reduce the number of instances where AActor::x and AActor::y are being referenced. --- src/actor.h | 2414 +++++++++++++++-------------- src/b_func.cpp | 16 +- src/b_move.cpp | 2 +- src/b_think.cpp | 12 +- src/g_doom/a_lostsoul.cpp | 2 +- src/g_doom/a_revenant.cpp | 5 +- src/g_game.cpp | 3 +- src/g_heretic/a_ironlich.cpp | 3 +- src/g_hexen/a_blastradius.cpp | 2 +- src/g_hexen/a_clericholy.cpp | 7 +- src/g_hexen/a_dragon.cpp | 8 +- src/g_hexen/a_firedemon.cpp | 2 +- src/g_hexen/a_healingradius.cpp | 2 +- src/g_hexen/a_heresiarch.cpp | 3 +- src/g_hexen/a_korax.cpp | 6 +- src/g_raven/a_minotaur.cpp | 6 +- src/g_shared/a_quake.cpp | 5 +- src/g_shared/a_specialspot.cpp | 2 +- src/g_strife/a_crusader.cpp | 4 +- src/g_strife/a_inquisitor.cpp | 4 +- src/p_enemy.cpp | 34 +- src/p_map.cpp | 6 +- src/p_mobj.cpp | 11 +- src/p_spec.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 18 +- 25 files changed, 1293 insertions(+), 1286 deletions(-) diff --git a/src/actor.h b/src/actor.h index cb0524587..0cd87ec52 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1,1189 +1,1225 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Map Objects, MObj, definition and handling. -// -//----------------------------------------------------------------------------- - - -#ifndef __P_MOBJ_H__ -#define __P_MOBJ_H__ - -// Basics. -#include "tables.h" - -// We need the thinker_t stuff. -#include "dthinker.h" - - -// States are tied to finite states are tied to animation frames. -#include "info.h" - -#include "doomdef.h" -#include "textures/textures.h" -#include "r_data/renderstyle.h" -#include "s_sound.h" -#include "memarena.h" -#include "g_level.h" -#include "tflags.h" - -struct subsector_t; -// -// NOTES: AActor -// -// Actors are used to tell the refresh where to draw an image, -// tell the world simulation when objects are contacted, -// and tell the sound driver how to position a sound. -// -// The refresh uses the next and prev links to follow -// lists of things in sectors as they are being drawn. -// The sprite, frame, and angle elements determine which patch_t -// is used to draw the sprite if it is visible. -// The sprite and frame values are almost always set -// from state_t structures. -// The statescr.exe utility generates the states.h and states.c -// files that contain the sprite/frame numbers from the -// statescr.txt source file. -// The xyz origin point represents a point at the bottom middle -// of the sprite (between the feet of a biped). -// This is the default origin position for patch_ts grabbed -// with lumpy.exe. -// A walking creature will have its z equal to the floor -// it is standing on. -// -// The sound code uses the x,y, and sometimes z fields -// to do stereo positioning of any sound emitted by the actor. -// -// The play simulation uses the blocklinks, x,y,z, radius, height -// to determine when AActors are touching each other, -// touching lines in the map, or hit by trace lines (gunshots, -// lines of sight, etc). -// The AActor->flags element has various bit flags -// used by the simulation. -// -// Every actor is linked into a single sector -// based on its origin coordinates. -// The subsector_t is found with R_PointInSubsector(x,y), -// and the sector_t can be found with subsector->sector. -// The sector links are only used by the rendering code, -// the play simulation does not care about them at all. -// -// Any actor that needs to be acted upon by something else -// in the play world (block movement, be shot, etc) will also -// need to be linked into the blockmap. -// If the thing has the MF_NOBLOCK flag set, it will not use -// the block links. It can still interact with other things, -// but only as the instigator (missiles will run into other -// things, but nothing can run into a missile). -// Each block in the grid is 128*128 units, and knows about -// every line_t that it contains a piece of, and every -// interactable actor that has its origin contained. -// -// A valid actor is an actor that has the proper subsector_t -// filled in for its xy coordinates and is linked into the -// sector from which the subsector was made, or has the -// MF_NOSECTOR flag set (the subsector_t needs to be valid -// even if MF_NOSECTOR is set), and is linked into a blockmap -// block or has the MF_NOBLOCKMAP flag set. -// Links should only be modified by the P_[Un]SetThingPosition() -// functions. -// Do not change the MF_NO* flags while a thing is valid. -// -// Any questions? -// - -// --- mobj.flags --- -enum ActorFlag -{ - MF_SPECIAL = 0x00000001, // call P_SpecialThing when touched - MF_SOLID = 0x00000002, - MF_SHOOTABLE = 0x00000004, - MF_NOSECTOR = 0x00000008, // don't use the sector links - // (invisible but touchable) - MF_NOBLOCKMAP = 0x00000010, // don't use the blocklinks - // (inert but displayable) - MF_AMBUSH = 0x00000020, // not activated by sound; deaf monster - MF_JUSTHIT = 0x00000040, // try to attack right back - MF_JUSTATTACKED = 0x00000080, // take at least one step before attacking - MF_SPAWNCEILING = 0x00000100, // hang from ceiling instead of floor - MF_NOGRAVITY = 0x00000200, // don't apply gravity every tic - -// movement flags - MF_DROPOFF = 0x00000400, // allow jumps from high places - MF_PICKUP = 0x00000800, // for players to pick up items - MF_NOCLIP = 0x00001000, // player cheat - MF_INCHASE = 0x00002000, // [RH] used by A_Chase and A_Look to avoid recursion - MF_FLOAT = 0x00004000, // allow moves to any height, no gravity - MF_TELEPORT = 0x00008000, // don't cross lines or look at heights - MF_MISSILE = 0x00010000, // don't hit same species, explode on block - - MF_DROPPED = 0x00020000, // dropped by a demon, not level spawned - MF_SHADOW = 0x00040000, // actor is hard for monsters to see - MF_NOBLOOD = 0x00080000, // don't bleed when shot (use puff) - MF_CORPSE = 0x00100000, // don't stop moving halfway off a step - MF_INFLOAT = 0x00200000, // floating to a height for a move, don't - // auto float to target's height - MF_INBOUNCE = 0x00200000, // used by Heretic bouncing missiles - - MF_COUNTKILL = 0x00400000, // count towards intermission kill total - MF_COUNTITEM = 0x00800000, // count towards intermission item total - - MF_SKULLFLY = 0x01000000, // skull in flight - MF_NOTDMATCH = 0x02000000, // don't spawn in death match (key cards) - - MF_SPAWNSOUNDSOURCE = 0x04000000, // Plays missile's see sound at spawning object. - MF_FRIENDLY = 0x08000000, // [RH] Friendly monsters for Strife (and MBF) - MF_UNMORPHED = 0x10000000, // [RH] Actor is the unmorphed version of something else - MF_NOLIFTDROP = 0x20000000, // [RH] Used with MF_NOGRAVITY to avoid dropping with lifts - MF_STEALTH = 0x40000000, // [RH] Andy Baker's stealth monsters - MF_ICECORPSE = 0x80000000, // a frozen corpse (for blasting) [RH] was 0x800000 - - // --- dummies for unknown/unimplemented Strife flags --- - MF_STRIFEx8000000 = 0, // seems related to MF_SHADOW -}; - -// --- mobj.flags2 --- -enum ActorFlag2 -{ - MF2_DONTREFLECT = 0x00000001, // this projectile cannot be reflected - MF2_WINDTHRUST = 0x00000002, // gets pushed around by the wind specials - MF2_DONTSEEKINVISIBLE=0x00000004, // For seeker missiles: Don't home in on invisible/shadow targets - MF2_BLASTED = 0x00000008, // actor will temporarily take damage from impact - MF2_FLY = 0x00000010, // fly mode is active - MF2_FLOORCLIP = 0x00000020, // if feet are allowed to be clipped - MF2_SPAWNFLOAT = 0x00000040, // spawn random float z - MF2_NOTELEPORT = 0x00000080, // does not teleport - MF2_RIP = 0x00000100, // missile rips through solid targets - MF2_PUSHABLE = 0x00000200, // can be pushed by other moving actors - MF2_SLIDE = 0x00000400, // slides against walls - MF2_ONMOBJ = 0x00000800, // actor is resting on top of another actor - MF2_PASSMOBJ = 0x00001000, // Enable z block checking. If on, - // this flag will allow the actor to - // pass over/under other actors. - MF2_CANNOTPUSH = 0x00002000, // cannot push other pushable mobjs - MF2_THRUGHOST = 0x00004000, // missile will pass through ghosts [RH] was 8 - MF2_BOSS = 0x00008000, // mobj is a major boss - - MF2_DONTTRANSLATE = 0x00010000, // Don't apply palette translations - MF2_NODMGTHRUST = 0x00020000, // does not thrust target when damaging - MF2_TELESTOMP = 0x00040000, // mobj can stomp another - MF2_FLOATBOB = 0x00080000, // use float bobbing z movement - MF2_THRUACTORS = 0x00100000, // performs no actor<->actor collision checks - MF2_IMPACT = 0x00200000, // an MF_MISSILE mobj can activate SPAC_IMPACT - MF2_PUSHWALL = 0x00400000, // mobj can push walls - MF2_MCROSS = 0x00800000, // can activate monster cross lines - MF2_PCROSS = 0x01000000, // can activate projectile cross lines - MF2_CANTLEAVEFLOORPIC=0x02000000, // stay within a certain floor type - MF2_NONSHOOTABLE = 0x04000000, // mobj is totally non-shootable, - // but still considered solid - MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable - MF2_DORMANT = 0x10000000, // thing is dormant - MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the - // args should not be taken from the mapthing definition - MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) - MF2_REFLECTIVE = 0x80000000, // reflects missiles -}; - -// --- mobj.flags3 --- -enum ActorFlag3 -{ - MF3_FLOORHUGGER = 0x00000001, // Missile stays on floor - MF3_CEILINGHUGGER = 0x00000002, // Missile stays on ceiling - MF3_NORADIUSDMG = 0x00000004, // Actor does not take radius damage - MF3_GHOST = 0x00000008, // Actor is a ghost - MF3_ALWAYSPUFF = 0x00000010, // Puff always appears, even when hit nothing - MF3_SPECIALFLOORCLIP= 0x00000020, // Actor uses floorclip for special effect (e.g. Wraith) - MF3_DONTSPLASH = 0x00000040, // Thing doesn't make a splash - MF3_NOSIGHTCHECK = 0x00000080, // Go after first acceptable target without checking sight - MF3_DONTOVERLAP = 0x00000100, // Don't pass over/under other things with this bit set - MF3_DONTMORPH = 0x00000200, // Immune to arti_egg - MF3_DONTSQUASH = 0x00000400, // Death ball can't squash this actor - MF3_EXPLOCOUNT = 0x00000800, // Don't explode until special2 counts to special1 - MF3_FULLVOLACTIVE = 0x00001000, // Active sound is played at full volume - MF3_ISMONSTER = 0x00002000, // Actor is a monster - MF3_SKYEXPLODE = 0x00004000, // Explode missile when hitting sky - MF3_STAYMORPHED = 0x00008000, // Monster cannot unmorph - MF3_DONTBLAST = 0x00010000, // Actor cannot be pushed by blasting - MF3_CANBLAST = 0x00020000, // Actor is not a monster but can be blasted - MF3_NOTARGET = 0x00040000, // This actor not targetted when it hurts something else - MF3_DONTGIB = 0x00080000, // Don't gib this corpse - MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines - MF3_CRASHED = 0x00200000, // Actor entered its crash state - MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) - MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) - MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV - MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things - MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact - MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood - MF3_NOEXPLODEFLOOR = 0x10000000, // Missile stops at floor instead of exploding - MF3_WARNBOT = 0x20000000, // Missile warns bot - MF3_PUFFONACTORS = 0x40000000, // Puff appears even when hit bleeding actors - MF3_HUNTPLAYERS = 0x80000000, // Used with TIDtoHate, means to hate players too -}; - -// --- mobj.flags4 --- -enum ActorFlag4 -{ - MF4_NOHATEPLAYERS = 0x00000001, // Ignore player attacks - MF4_QUICKTORETALIATE= 0x00000002, // Always switch targets when hurt - MF4_NOICEDEATH = 0x00000004, // Actor never enters an ice death, not even the generic one - MF4_BOSSDEATH = 0x00000008, // A_FreezeDeathChunks calls A_BossDeath - MF4_RANDOMIZE = 0x00000010, // Missile has random initial tic count - MF4_NOSKIN = 0x00000020, // Player cannot use skins - MF4_FIXMAPTHINGPOS = 0x00000040, // Fix this actor's position when spawned as a map thing - MF4_ACTLIKEBRIDGE = 0x00000080, // Pickups can "stand" on this actor / cannot be moved by any sector action. - MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x - - MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials - MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack - MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack - MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG - MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying. - MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger - MF4_INCOMBAT = 0x00008000, // Don't alert others when attacked by a dagger - MF4_LOOKALLAROUND = 0x00010000, // Monster has eyes in the back of its head - MF4_STANDSTILL = 0x00020000, // Monster should not chase targets unless attacked? - MF4_SPECTRAL = 0x00040000, - MF4_SCROLLMOVE = 0x00080000, // velocity has been applied by a scroller - MF4_NOSPLASHALERT = 0x00100000, // Splashes don't alert this monster - MF4_SYNCHRONIZED = 0x00200000, // For actors spawned at load-time only: Do not randomize tics - MF4_NOTARGETSWITCH = 0x00400000, // monster never switches target until current one is dead - MF4_VFRICTION = 0x00800000, // Internal flag used by A_PainAttack to push a monster down - MF4_DONTHARMCLASS = 0x01000000, // Don't hurt one's own kind with explosions (hitscans, too?) - MF4_SHIELDREFLECT = 0x02000000, - MF4_DEFLECT = 0x04000000, // different projectile reflection styles - MF4_ALLOWPARTICLES = 0x08000000, // this puff type can be replaced by particles - MF4_NOEXTREMEDEATH = 0x10000000, // this projectile or weapon never gibs its victim - MF4_EXTREMEDEATH = 0x20000000, // this projectile or weapon always gibs its victim - MF4_FRIGHTENED = 0x40000000, // Monster runs away from player - MF4_BOSSSPAWNED = 0x80000000, // Spawned by a boss spawn cube -}; - -// --- mobj.flags5 --- - -enum ActorFlag5 -{ - MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. - /* = 0x00000002, reserved for use by scripting branch */ - MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. - MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this - MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret - MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs - MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage - MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set. - MF5_BLOODSPLATTER = 0x00000100, // Blood splatter like in Raven's games. - MF5_OLDRADIUSDMG = 0x00000200, // Use old radius damage code (for barrels and boss brain) - MF5_DEHEXPLOSION = 0x00000400, // Use the DEHACKED explosion options when this projectile explodes - MF5_PIERCEARMOR = 0x00000800, // Armor doesn't protect against damage from this actor - MF5_NOBLOODDECALS = 0x00001000, // Actor bleeds but doesn't spawn blood decals - MF5_USESPECIAL = 0x00002000, // Actor executes its special when being 'used'. - MF5_NOPAIN = 0x00004000, // If set the pain state won't be entered - MF5_ALWAYSFAST = 0x00008000, // always uses 'fast' attacking logic - MF5_NEVERFAST = 0x00010000, // never uses 'fast' attacking logic - MF5_ALWAYSRESPAWN = 0x00020000, // always respawns, regardless of skill setting - MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting - MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hitting this actor - MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt - MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks - MF5_NOTIMEFREEZE = 0x00400000, // Actor is not affected by time freezer - MF5_PUFFGETSOWNER = 0x00800000, // [BB] Sets the owner of the puff to the player who fired it - MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to remove - // dependence of main engine code of specific actor types. - MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later. - MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range - MF5_BRIGHT = 0x08000000, // Actor is always rendered fullbright - MF5_CANTSEEK = 0x10000000, // seeker missiles cannot home in on this actor - MF5_INCONVERSATION = 0x20000000, // Actor is having a conversation - MF5_PAINLESS = 0x40000000, // Actor always inflicts painless damage. - MF5_MOVEWITHSECTOR = 0x80000000, // P_ChangeSector() will still process this actor if it has MF_NOBLOCKMAP -}; - -// --- mobj.flags6 --- -enum ActorFlag6 -{ - MF6_NOBOSSRIP = 0x00000001, // For rippermissiles: Don't rip through bosses. - MF6_THRUSPECIES = 0x00000002, // Actors passes through other of the same species. - MF6_MTHRUSPECIES = 0x00000004, // Missile passes through actors of its shooter's species. - MF6_FORCEPAIN = 0x00000008, // forces target into painstate (unless it has the NOPAIN flag) - MF6_NOFEAR = 0x00000010, // Not scared of frightening players - MF6_BUMPSPECIAL = 0x00000020, // Actor executes its special when being collided (as the ST flag) - MF6_DONTHARMSPECIES = 0x00000040, // Don't hurt one's own species with explosions (hitscans, too?) - MF6_STEPMISSILE = 0x00000080, // Missile can "walk" up steps - MF6_NOTELEFRAG = 0x00000100, // [HW] Actor can't be telefragged - MF6_TOUCHY = 0x00000200, // From MBF: killough 11/98: dies when solids touch it - MF6_CANJUMP = 0x00000400, // From MBF: a dedicated flag instead of the BOUNCES+FLOAT+sentient combo - MF6_JUMPDOWN = 0x00000800, // From MBF: generalization of dog behavior wrt. dropoffs. - MF6_VULNERABLE = 0x00001000, // Actor can be damaged (even if not shootable). - MF6_ARMED = 0x00002000, // From MBF: Object is armed (for MF6_TOUCHY objects) - MF6_FALLING = 0x00004000, // From MBF: Object is falling (for pseudotorque simulation) - MF6_LINEDONE = 0x00008000, // From MBF: Object has already run a line effect - MF6_NOTRIGGER = 0x00010000, // actor cannot trigger any line actions - MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering - MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) - MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself - MF6_ADDITIVEPOISONDAMAGE = 0x00100000, - MF6_ADDITIVEPOISONDURATION = 0x00200000, - MF6_NOMENU = 0x00400000, // Player class should not appear in the class selection menu. - MF6_BOSSCUBE = 0x00800000, // Actor spawned by A_BrainSpit, flagged for timefreeze reasons. - MF6_SEEINVISIBLE = 0x01000000, // Monsters can see invisible player. - MF6_DONTCORPSE = 0x02000000, // [RC] Don't autoset MF_CORPSE upon death and don't force Crash state change. - MF6_POISONALWAYS = 0x04000000, // Always apply poison, even when target can't take the damage. - MF6_DOHARMSPECIES = 0x08000000, // Do hurt one's own species with projectiles. - MF6_INTRYMOVE = 0x10000000, // Executing P_TryMove - MF6_NOTAUTOAIMED = 0x20000000, // Do not subject actor to player autoaim. - MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. - MF6_RELATIVETOFLOOR = 0x80000000, // [RC] Make flying actors be affected by lifts. -}; - -// --- mobj.flags7 --- -enum ActorFlag7 -{ - MF7_NEVERTARGET = 0x00000001, // can not be targetted at all, even if monster friendliness is considered. - MF7_NOTELESTOMP = 0x00000002, // cannot telefrag under any circumstances (even when set by MAPINFO) - MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. - MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag - MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag - MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters. - MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. - MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. - MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. - MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. - MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. - MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles. - MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected. - MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile. - MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway. - MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target. - MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer. - MF7_FLYCHEAT = 0x00020000, // must be part of the actor so that it can be tracked properly - MF7_NODECAL = 0x00040000, // [ZK] Forces puff to have no impact decal - MF7_FORCEDECAL = 0x00080000, // [ZK] Forces puff's decal to override the weapon's. - MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. - MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. -}; - -// --- mobj.renderflags --- -enum ActorRenderFlag -{ - RF_XFLIP = 0x0001, // Flip sprite horizontally - RF_YFLIP = 0x0002, // Flip sprite vertically - RF_ONESIDED = 0x0004, // Wall/floor sprite is visible from front only - RF_FULLBRIGHT = 0x0010, // Sprite is drawn at full brightness - - RF_RELMASK = 0x0300, // ---Relative z-coord for bound actors (these obey texture pegging) - RF_RELABSOLUTE = 0x0000, // Actor z is absolute - RF_RELUPPER = 0x0100, // Actor z is relative to upper part of wall - RF_RELLOWER = 0x0200, // Actor z is relative to lower part of wall - RF_RELMID = 0x0300, // Actor z is relative to middle part of wall - - RF_CLIPMASK = 0x0c00, // ---Clipping for bound actors - RF_CLIPFULL = 0x0000, // Clip sprite to full height of wall - RF_CLIPUPPER = 0x0400, // Clip sprite to upper part of wall - RF_CLIPMID = 0x0800, // Clip sprite to mid part of wall - RF_CLIPLOWER = 0x0c00, // Clip sprite to lower part of wall - - RF_DECALMASK = RF_RELMASK|RF_CLIPMASK, - - RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types, not all implemented - RF_FACESPRITE = 0x0000, // Face sprite - RF_WALLSPRITE = 0x1000, // Wall sprite - RF_FLOORSPRITE = 0x2000, // Floor sprite - RF_VOXELSPRITE = 0x3000, // Voxel object - RF_INVISIBLE = 0x8000, // Don't bother drawing this actor - - RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting) - RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting) -}; - -#define TRANSLUC25 (FRACUNIT/4) -#define TRANSLUC33 (FRACUNIT/3) -#define TRANSLUC50 (FRACUNIT/2) -#define TRANSLUC66 ((FRACUNIT*2)/3) -#define TRANSLUC75 ((FRACUNIT*3)/4) - -// also #defines OPAQUE -#ifndef OPAQUE -#define OPAQUE (FRACUNIT) -#endif - -// This translucency value produces the closest match to Heretic's TINTTAB. -// ~40% of the value of the overlaid image shows through. -#define HR_SHADOW (0x6800) - -// Hexen's TINTTAB is the same as Heretic's, just reversed. -#define HX_SHADOW (0x9800) -#define HX_ALTSHADOW (0x6800) - -// This could easily be a bool but then it'd be much harder to find later. ;) -enum replace_t -{ - NO_REPLACE = 0, - ALLOW_REPLACE = 1 -}; - -enum ActorBounceFlag -{ - BOUNCE_Walls = 1<<0, // bounces off of walls - BOUNCE_Floors = 1<<1, // bounces off of floors - BOUNCE_Ceilings = 1<<2, // bounces off of ceilings - BOUNCE_Actors = 1<<3, // bounces off of some actors - BOUNCE_AllActors = 1<<4, // bounces off of all actors (requires BOUNCE_Actors to be set, too) - BOUNCE_AutoOff = 1<<5, // when bouncing off a sector plane, if the new Z velocity is below 3.0, disable further bouncing - BOUNCE_HereticType = 1<<6, // goes into Death state when bouncing on floors or ceilings - - BOUNCE_UseSeeSound = 1<<7, // compatibility fallback. This will only be set by - // the compatibility handlers for the old bounce flags. - BOUNCE_NoWallSound = 1<<8, // don't make noise when bouncing off a wall - BOUNCE_Quiet = 1<<9, // Strife's grenades don't make a bouncing sound - BOUNCE_ExplodeOnWater = 1<<10, // explodes when hitting a water surface - BOUNCE_CanBounceWater = 1<<11, // can bounce on water - // MBF bouncing is a bit different from other modes as Killough coded many special behavioral cases - // for them that are not present in ZDoom, so it is necessary to identify it properly. - BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. - BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors - BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states - - BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, - - // The three "standard" types of bounciness are: - // HERETIC - Missile will only bounce off the floor once and then enter - // its death state. It does not bounce off walls at all. - // HEXEN - Missile bounces off of walls and floors indefinitely. - // DOOM - Like Hexen, but the bounce turns off if its vertical velocity - // is too low. - BOUNCE_None = 0, - BOUNCE_Heretic = BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_HereticType, - BOUNCE_Doom = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff, - BOUNCE_Hexen = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors, - BOUNCE_Grenade = BOUNCE_MBF | BOUNCE_Doom, // Bounces on walls and flats like ZDoom bounce. - BOUNCE_Classic = BOUNCE_MBF | BOUNCE_Floors | BOUNCE_Ceilings, // Bounces on flats only, but - // does not die when bouncing. - - // combined types - BOUNCE_DoomCompat = BOUNCE_Doom | BOUNCE_UseSeeSound, - BOUNCE_HereticCompat = BOUNCE_Heretic | BOUNCE_UseSeeSound, - BOUNCE_HexenCompat = BOUNCE_Hexen | BOUNCE_UseSeeSound - - // The distinction between BOUNCE_Actors and BOUNCE_AllActors: A missile with - // BOUNCE_Actors set will bounce off of reflective and "non-sentient" actors. - // A missile that also has BOUNCE_AllActors set will bounce off of any actor. - // For compatibility reasons when BOUNCE_Actors was implied by the bounce type - // being "Doom" or "Hexen" and BOUNCE_AllActors was the separate - // MF5_BOUNCEONACTORS, you must set BOUNCE_Actors for BOUNCE_AllActors to have - // an effect. - - -}; - -// [TP] Flagset definitions -typedef TFlags ActorFlags; -typedef TFlags ActorFlags2; -typedef TFlags ActorFlags3; -typedef TFlags ActorFlags4; -typedef TFlags ActorFlags5; -typedef TFlags ActorFlags6; -typedef TFlags ActorFlags7; -typedef TFlags ActorRenderFlags; -typedef TFlags ActorBounceFlags; -DEFINE_TFLAGS_OPERATORS (ActorFlags) -DEFINE_TFLAGS_OPERATORS (ActorFlags2) -DEFINE_TFLAGS_OPERATORS (ActorFlags3) -DEFINE_TFLAGS_OPERATORS (ActorFlags4) -DEFINE_TFLAGS_OPERATORS (ActorFlags5) -DEFINE_TFLAGS_OPERATORS (ActorFlags6) -DEFINE_TFLAGS_OPERATORS (ActorFlags7) -DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) -DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) - -// Used to affect the logic for thing activation through death, USESPECIAL and BUMPSPECIAL -// "thing" refers to what has the flag and the special, "trigger" refers to what used or bumped it -enum EThingSpecialActivationType -{ - THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator - THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special - THINGSPEC_ThingTargets = 1<<1, // The thing changes its target to the trigger - THINGSPEC_TriggerTargets = 1<<2, // The trigger changes its target to the thing - THINGSPEC_MonsterTrigger = 1<<3, // The thing can be triggered by a monster - THINGSPEC_MissileTrigger = 1<<4, // The thing can be triggered by a projectile - THINGSPEC_ClearSpecial = 1<<5, // Clears special after successful activation - THINGSPEC_NoDeathSpecial = 1<<6, // Don't activate special on death - THINGSPEC_TriggerActs = 1<<7, // The trigger is the activator of the special - // (overrides LEVEL_ACTOWNSPECIAL Hexen hack) - THINGSPEC_Activate = 1<<8, // The thing is activated when triggered - THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered - THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered -}; - -// [RH] Like msecnode_t, but for the blockmap -struct FBlockNode -{ - AActor *Me; // actor this node references - int BlockIndex; // index into blocklinks for the block this node is in - FBlockNode **PrevActor; // previous actor in this block - FBlockNode *NextActor; // next actor in this block - FBlockNode **PrevBlock; // previous block this actor is in - FBlockNode *NextBlock; // next block this actor is in - - static FBlockNode *Create (AActor *who, int x, int y); - void Release (); - - static FBlockNode *FreeBlocks; -}; - -class FDecalBase; -class AInventory; - -inline AActor *GetDefaultByName (const char *name) -{ - return (AActor *)(PClass::FindClass(name)->Defaults); -} - -inline AActor *GetDefaultByType (const PClass *type) -{ - return (AActor *)(type->Defaults); -} - -template -inline T *GetDefault () -{ - return (T *)(RUNTIME_CLASS(T)->Defaults); -} - -struct line_t; -struct secplane_t; -struct FStrifeDialogueNode; - -enum -{ - AMETA_BASE = 0x12000, - - AMETA_Obituary, // string (player was killed by this actor) - AMETA_HitObituary, // string (player was killed by this actor in melee) - AMETA_DeathHeight, // fixed (height on normal death) - AMETA_BurnHeight, // fixed (height on burning death) - AMETA_StrifeName, // string (for named Strife objects) - AMETA_BloodColor, // colorized blood - AMETA_GibHealth, // negative health below which this monster dies an extreme death - AMETA_WoundHealth, // health needed to enter wound state - AMETA_FastSpeed, // Speed in fast mode - AMETA_RDFactor, // Radius damage factor - AMETA_CameraHeight, // Height of camera when used as such - AMETA_HowlSound, // Sound being played when electrocuted or poisoned - AMETA_BloodType, // Blood replacement type - AMETA_BloodType2, // Bloodsplatter replacement type - AMETA_BloodType3, // AxeBlood replacement type -}; - -struct FDropItem -{ - FName Name; - int probability; - int amount; - FDropItem * Next; -}; - -class FDropItemPtrArray : public TArray -{ -public: - ~FDropItemPtrArray() - { - Clear(); - } - - void Clear(); -}; - -extern FDropItemPtrArray DropItemList; - -void FreeDropItemChain(FDropItem *chain); -int StoreDropItemChain(FDropItem *chain); - - - -// Map Object definition. -class AActor : public DThinker -{ - DECLARE_CLASS (AActor, DThinker) - HAS_OBJECT_POINTERS -public: - AActor () throw(); - AActor (const AActor &other) throw(); - AActor &operator= (const AActor &other); - void Destroy (); - ~AActor (); - - void Serialize (FArchive &arc); - - static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); - - inline AActor *GetDefault () const - { - return (AActor *)(RUNTIME_TYPE(this)->Defaults); - } - - FDropItem *GetDropItems(); - - // Return true if the monster should use a missile attack, false for melee - bool SuggestMissileAttack (fixed_t dist); - - // Adjusts the angle for deflection/reflection of incoming missiles - // Returns true if the missile should be allowed to explode anyway - bool AdjustReflectionAngle (AActor *thing, angle_t &angle); - - // Returns true if this actor is within melee range of its target - bool CheckMeleeRange(); - - virtual void BeginPlay(); // Called immediately after the actor is created - virtual void PostBeginPlay(); // Called immediately before the actor's first tick - virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world - virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. - - virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. - - virtual void Activate (AActor *activator); - virtual void Deactivate (AActor *activator); - - virtual void Tick (); - - // Called when actor dies - virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); - - // Perform some special damage action. Returns the amount of damage to do. - // Returning -1 signals the damage routine to exit immediately - virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype); - - // Like DoSpecialDamage, but called on the actor receiving the damage. - virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); - - // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed - // Made a metadata property so no longer virtual - void Howl (); - - // Actor just hit the floor - virtual void HitFloor (); - - // plays bouncing sound - void PlayBounceSound(bool onfloor); - - // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor - virtual bool FloorBounceMissile (secplane_t &plane); - - // Called when an actor is to be reflected by a disc of repulsion. - // Returns true to continue normal blast processing. - virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); - - // Called by RoughBlockCheck - bool IsOkayToAttack (AActor *target); - - // Plays the actor's ActiveSound if its voice isn't already making noise. - void PlayActiveSound (); - - // Actor had MF_SKULLFLY set and rammed into something - // Returns false to stop moving and true to keep moving - virtual bool Slam (AActor *victim); - - // Called by PIT_CheckThing() and needed for some Hexen things. - // Returns -1 for normal behavior, 0 to return false, and 1 to return true. - // I'm not sure I like it this way, but it will do for now. - virtual int SpecialMissileHit (AActor *victim); - - // Returns true if it's okay to switch target to "other" after being attacked by it. - virtual bool OkayToSwitchTarget (AActor *other); - - // Something just touched this actor. - virtual void Touch (AActor *toucher); - - // Adds the item to this actor's inventory and sets its Owner. - virtual void AddInventory (AInventory *item); - - // Removes the item from the inventory list. - virtual void RemoveInventory (AInventory *item); - - // Take the amount value of an item from the inventory list. - // If nothing is left, the item may be destroyed. - // Returns true if the initial item count is positive. - virtual bool TakeInventory (const PClass *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); - - // Uses an item and removes it from the inventory. - virtual bool UseInventory (AInventory *item); - - // Tosses an item out of the inventory. - virtual AInventory *DropInventory (AInventory *item); - - // Removes all items from the inventory. - void ClearInventory(); - - // Returns true if this view is considered "local" for the player. - bool CheckLocalView (int playernum) const; - - // Finds the first item of a particular type. - AInventory *FindInventory (const PClass *type, bool subclass = false); - AInventory *FindInventory (FName type); - template T *FindInventory () - { - return static_cast (FindInventory (RUNTIME_CLASS(T))); - } - - // Adds one item of a particular type. Returns NULL if it could not be added. - AInventory *GiveInventoryType (const PClass *type); - - // Returns the first item held with IF_INVBAR set. - AInventory *FirstInv (); - - // Tries to give the actor some ammo. - bool GiveAmmo (const PClass *type, int amount); - - // Destroys all the inventory the actor is holding. - void DestroyAllInventory (); - - // Set the alphacolor field properly - void SetShade (DWORD rgb); - void SetShade (int r, int g, int b); - - // Plays a conversation animation - void ConversationAnimation (int animnum); - - // Make this actor hate the same things as another actor - void CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth=true); - - // Moves the other actor's inventory to this one - void ObtainInventory (AActor *other); - - // Die. Now. - virtual bool Massacre (); - - // Transforms the actor into a finely-ground paste - virtual bool Grind(bool items); - - // Get this actor's team - int GetTeam(); - - // Is the other actor on my team? - bool IsTeammate (AActor *other); - - // Is the other actor my friend? - bool IsFriend (AActor *other); - - // Do I hate the other actor? - bool IsHostile (AActor *other); - - inline bool IsNoClip2() const; - - // What species am I? - virtual FName GetSpecies(); - - fixed_t GetBobOffset(fixed_t ticfrac=0) const - { - if (!(flags2 & MF2_FLOATBOB)) - { - return 0; - } - return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8; - } - - // Enter the crash state - void Crash(); - - // Return starting health adjusted by skill level - int SpawnHealth(); - int GibHealth(); - - inline bool isMissile(bool precise=true) - { - return (flags&MF_MISSILE) || (precise && GetDefault()->flags&MF_MISSILE); - } - - // Check for monsters that count as kill but excludes all friendlies. - bool CountsAsKill() const - { - return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); - } - - bool intersects(AActor *other) const - { - fixed_t blockdist = radius + other->radius; - return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); - } - - PalEntry GetBloodColor() const - { - return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); - } - - // These also set CF_INTERPVIEW for players. - void SetPitch(int p, bool interpolate, bool forceclamp = false); - void SetAngle(angle_t ang, bool interpolate); - void SetRoll(angle_t roll, bool interpolate); - - const PClass *GetBloodType(int type = 0) const - { - const PClass *bloodcls; - if (type == 0) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); - } - else if (type == 1) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); - } - else if (type == 2) - { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); - } - else return NULL; - - if (bloodcls != NULL) - { - bloodcls = bloodcls->GetReplacement(); - } - return bloodcls; - } - - inline void SetFriendPlayer(player_t *player); - - bool IsVisibleToPlayer() const; - - // Calculate amount of missile damage - virtual int GetMissileDamage(int mask, int add); - - bool CanSeek(AActor *target) const; - - fixed_t GetGravity() const; - bool IsSentient() const; - const char *GetTag(const char *def = NULL) const; - void SetTag(const char *def); - - // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector - void CheckSectorTransition(sector_t *oldsec); - -// info for drawing -// NOTE: The first member variable *must* be x. - fixed_t x,y,z; - AActor *snext, **sprev; // links in sector (if needed) - angle_t angle; - WORD sprite; // used to find patch_t and flip value - BYTE frame; // sprite frame to draw - fixed_t scaleX, scaleY; // Scaling values; FRACUNIT is normal size - FRenderStyle RenderStyle; // Style to draw this actor with - ActorRenderFlags renderflags; // Different rendering flags - FTextureID picnum; // Draw this instead of sprite if valid - DWORD effects; // [RH] see p_effect.h - fixed_t alpha; - DWORD fillcolor; // Color to draw when STYLE_Shaded - -// interaction info - fixed_t pitch; - angle_t roll; // This was fixed_t before, which is probably wrong - FBlockNode *BlockNode; // links in blocks (if needed) - struct sector_t *Sector; - subsector_t * subsector; - fixed_t floorz, ceilingz; // closest together of contacted secs - fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. - - struct sector_t *floorsector; - FTextureID floorpic; // contacted sec floorpic - int floorterrain; - struct sector_t *ceilingsector; - FTextureID ceilingpic; // contacted sec ceilingpic - fixed_t radius, height; // for movement checking - fixed_t projectilepassheight; // height for clipping projectile movement against this actor - fixed_t velx, vely, velz; // velocity - SDWORD tics; // state tic counter - FState *state; - SDWORD Damage; // For missiles and monster railgun - int projectileKickback; - ActorFlags flags; - ActorFlags2 flags2; // Heretic flags - ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable - ActorFlags4 flags4; // [RH] Even more flags! - ActorFlags5 flags5; // OMG! We need another one. - ActorFlags6 flags6; // Shit! Where did all the flags go? - ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? - - // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. - DWORD VisibleToTeam; - - int special1; // Special info - int special2; // Special info - int weaponspecial; // Special info for weapons. - int health; - BYTE movedir; // 0-7 - SBYTE visdir; - SWORD movecount; // when 0, select a new dir - SWORD strafecount; // for MF3_AVOIDMELEE - TObjPtr target; // thing being chased/attacked (or NULL) - // also the originator for missiles - TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 - TObjPtr LastHeard; // [RH] Last actor this one heard - SDWORD reactiontime; // if non 0, don't attack yet; used by - // player to freeze a bit after teleporting - SDWORD threshold; // if > 0, the target will be chased - // no matter what (even if shot) - player_t *player; // only valid if type of APlayerPawn - TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) - fixed_t SpawnPoint[3]; // For nightmare respawn - WORD SpawnAngle; - int StartHealth; - BYTE WeaveIndexXY; // Separated from special2 because it's used by globally accessible functions. - BYTE WeaveIndexZ; - int skillrespawncount; - int TIDtoHate; // TID of things to hate (0 if none) - FNameNoInit Species; // For monster families - TObjPtr tracer; // Thing being chased/attacked for tracers - TObjPtr master; // Thing which spawned this one (prevents mutual attacks) - fixed_t floorclip; // value to use for floor clipping - int tid; // thing identifier - int special; // special - int args[5]; // special arguments - - int accuracy, stamina; // [RH] Strife stats -- [XA] moved here for DECORATE/ACS access. - - AActor *inext, **iprev;// Links to other mobjs in same bucket - TObjPtr goal; // Monster's goal if not chasing anything - int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes - BYTE boomwaterlevel; // splash information for non-swimmable water sectors - BYTE MinMissileChance;// [RH] If a random # is > than this, then missile attack. - SBYTE LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0) - ActorBounceFlags BounceFlags; // which bouncing type? - DWORD SpawnFlags; // Increased to DWORD because of Doom 64 - fixed_t meleerange; // specifies how far a melee attack reaches. - fixed_t meleethreshold; // Distance below which a monster doesn't try to shoot missiles anynore - // but instead tries to come closer for a melee attack. - // This is not the same as meleerange - fixed_t maxtargetrange; // any target farther away cannot be attacked - fixed_t bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. - fixed_t wallbouncefactor; // The bounce factor for walls can be different. - int bouncecount; // Strife's grenades only bounce twice before exploding - fixed_t gravity; // [GRB] Gravity factor - fixed_t Friction; - int FastChaseStrafeCount; - fixed_t pushfactor; - int lastpush; - int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL - int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL - int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. - FString * Tag; // Strife's tag name. - int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players. - - AActor *BlockingMobj; // Actor that blocked the last move - line_t *BlockingLine; // Line that blocked the last move - - int PoisonDamage; // Damage received per tic from poison. - FNameNoInit PoisonDamageType; // Damage type dealt by poison. - int PoisonDuration; // Duration left for receiving poison damage. - int PoisonPeriod; // How often poison damage is applied. (Every X tics.) - - int PoisonDamageReceived; // Damage received per tic from poison. - FNameNoInit PoisonDamageTypeReceived; // Damage type received by poison. - int PoisonDurationReceived; // Duration left for receiving poison damage. - int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.) - TObjPtr Poisoner; // Last source of received poison damage. - - // a linked list of sectors where this object appears - struct msecnode_t *touching_sectorlist; // phares 3/14/98 - - TObjPtr Inventory; // [RH] This actor's inventory - DWORD InventoryID; // A unique ID to keep track of inventory items - - BYTE smokecounter; - BYTE FloatBobPhase; - BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) - DWORD Translation; - - // [RH] Stuff that used to be part of an Actor Info - FSoundIDNoInit SeeSound; - FSoundIDNoInit AttackSound; - FSoundIDNoInit PainSound; - FSoundIDNoInit DeathSound; - FSoundIDNoInit ActiveSound; - FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. - FSoundIDNoInit BounceSound; - FSoundIDNoInit WallBounceSound; - FSoundIDNoInit CrushPainSound; - - fixed_t Speed; - fixed_t FloatSpeed; - fixed_t MaxDropOffHeight, MaxStepHeight; - SDWORD Mass; - SWORD PainChance; - int PainThreshold; - FNameNoInit DamageType; - FNameNoInit DamageTypeReceived; - fixed_t DamageFactor; - fixed_t DamageMultiply; - - FNameNoInit PainType; - FNameNoInit DeathType; - const PClass *TeleFogSourceType; - const PClass *TeleFogDestType; - int RipperLevel; - int RipLevelMin; - int RipLevelMax; - - FState *SpawnState; - FState *SeeState; - FState *MeleeState; - FState *MissileState; - - - int ConversationRoot; // THe root of the current dialogue - FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." - - // [RH] Decal(s) this weapon/projectile generates on impact. - FDecalBase *DecalGenerator; - - // [RH] Used to interpolate the view to get >35 FPS - fixed_t PrevX, PrevY, PrevZ; - angle_t PrevAngle; - - // ThingIDs - static void ClearTIDHashes (); - void AddToHash (); - void RemoveFromHash (); - -private: - static AActor *TIDHash[128]; - static inline int TIDHASH (int key) { return key & 127; } - static FSharedStringArena mStringPropertyData; - - friend class FActorIterator; - friend bool P_IsTIDUsed(int tid); - - sector_t *LinkToWorldForMapThing (); - -public: - void LinkToWorld (bool buggy=false); - void LinkToWorld (sector_t *sector); - void UnlinkFromWorld (); - void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z); - bool InStateSequence(FState * newstate, FState * basestate); - int GetTics(FState * newstate); - bool SetState (FState *newstate, bool nofunction=false); - virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); - bool isFast(); - bool isSlow(); - void SetIdle(bool nofunction=false); - void ClearCounters(); - FState *GetRaiseState(); - void Revive(); - - FState *FindState (FName label) const - { - return GetClass()->ActorInfo->FindState(1, &label); - } - - FState *FindState (FName label, FName sublabel, bool exact = false) const - { - FName names[] = { label, sublabel }; - return GetClass()->ActorInfo->FindState(2, names, exact); - } - - FState *FindState(int numnames, FName *names, bool exact = false) const - { - return GetClass()->ActorInfo->FindState(numnames, names, exact); - } - - bool HasSpecialDeathStates () const; -}; - -class FActorIterator -{ -public: - FActorIterator (int i) : base (NULL), id (i) - { - } - FActorIterator (int i, AActor *start) : base (start), id (i) - { - } - AActor *Next () - { - if (id == 0) - return NULL; - if (!base) - base = AActor::TIDHash[id & 127]; - else - base = base->inext; - - while (base && base->tid != id) - base = base->inext; - - return base; - } -private: - AActor *base; - int id; -}; - -template -class TActorIterator : public FActorIterator -{ -public: - TActorIterator (int id) : FActorIterator (id) {} - T *Next () - { - AActor *actor; - do - { - actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); - return static_cast(actor); - } -}; - -class NActorIterator : public FActorIterator -{ - const PClass *type; -public: - NActorIterator (const PClass *cls, int id) : FActorIterator (id) { type = cls; } - NActorIterator (FName cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } - NActorIterator (const char *cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } - AActor *Next () - { - AActor *actor; - if (type == NULL) return NULL; - do - { - actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (type)); - return actor; - } -}; - -bool P_IsTIDUsed(int tid); -int P_FindUniqueTID(int start_tid, int limit); - -inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) -{ - return AActor::StaticSpawn (type, x, y, z, allowreplacement); -} - -AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); -AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); - -template -inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) -{ - return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); -} - - -void PrintMiscActorInfo(AActor * query); - -#define S_FREETARGMOBJ 1 - -#endif // __P_MOBJ_H__ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// DESCRIPTION: +// Map Objects, MObj, definition and handling. +// +//----------------------------------------------------------------------------- + + +#ifndef __P_MOBJ_H__ +#define __P_MOBJ_H__ + +// Basics. +#include "tables.h" + +// We need the thinker_t stuff. +#include "dthinker.h" + + +// States are tied to finite states are tied to animation frames. +#include "info.h" + +#include "doomdef.h" +#include "textures/textures.h" +#include "r_data/renderstyle.h" +#include "s_sound.h" +#include "memarena.h" +#include "g_level.h" +#include "tflags.h" + +struct subsector_t; +// +// NOTES: AActor +// +// Actors are used to tell the refresh where to draw an image, +// tell the world simulation when objects are contacted, +// and tell the sound driver how to position a sound. +// +// The refresh uses the next and prev links to follow +// lists of things in sectors as they are being drawn. +// The sprite, frame, and angle elements determine which patch_t +// is used to draw the sprite if it is visible. +// The sprite and frame values are almost always set +// from state_t structures. +// The statescr.exe utility generates the states.h and states.c +// files that contain the sprite/frame numbers from the +// statescr.txt source file. +// The xyz origin point represents a point at the bottom middle +// of the sprite (between the feet of a biped). +// This is the default origin position for patch_ts grabbed +// with lumpy.exe. +// A walking creature will have its z equal to the floor +// it is standing on. +// +// The sound code uses the x,y, and sometimes z fields +// to do stereo positioning of any sound emitted by the actor. +// +// The play simulation uses the blocklinks, x,y,z, radius, height +// to determine when AActors are touching each other, +// touching lines in the map, or hit by trace lines (gunshots, +// lines of sight, etc). +// The AActor->flags element has various bit flags +// used by the simulation. +// +// Every actor is linked into a single sector +// based on its origin coordinates. +// The subsector_t is found with R_PointInSubsector(x,y), +// and the sector_t can be found with subsector->sector. +// The sector links are only used by the rendering code, +// the play simulation does not care about them at all. +// +// Any actor that needs to be acted upon by something else +// in the play world (block movement, be shot, etc) will also +// need to be linked into the blockmap. +// If the thing has the MF_NOBLOCK flag set, it will not use +// the block links. It can still interact with other things, +// but only as the instigator (missiles will run into other +// things, but nothing can run into a missile). +// Each block in the grid is 128*128 units, and knows about +// every line_t that it contains a piece of, and every +// interactable actor that has its origin contained. +// +// A valid actor is an actor that has the proper subsector_t +// filled in for its xy coordinates and is linked into the +// sector from which the subsector was made, or has the +// MF_NOSECTOR flag set (the subsector_t needs to be valid +// even if MF_NOSECTOR is set), and is linked into a blockmap +// block or has the MF_NOBLOCKMAP flag set. +// Links should only be modified by the P_[Un]SetThingPosition() +// functions. +// Do not change the MF_NO* flags while a thing is valid. +// +// Any questions? +// + +// --- mobj.flags --- +enum ActorFlag +{ + MF_SPECIAL = 0x00000001, // call P_SpecialThing when touched + MF_SOLID = 0x00000002, + MF_SHOOTABLE = 0x00000004, + MF_NOSECTOR = 0x00000008, // don't use the sector links + // (invisible but touchable) + MF_NOBLOCKMAP = 0x00000010, // don't use the blocklinks + // (inert but displayable) + MF_AMBUSH = 0x00000020, // not activated by sound; deaf monster + MF_JUSTHIT = 0x00000040, // try to attack right back + MF_JUSTATTACKED = 0x00000080, // take at least one step before attacking + MF_SPAWNCEILING = 0x00000100, // hang from ceiling instead of floor + MF_NOGRAVITY = 0x00000200, // don't apply gravity every tic + +// movement flags + MF_DROPOFF = 0x00000400, // allow jumps from high places + MF_PICKUP = 0x00000800, // for players to pick up items + MF_NOCLIP = 0x00001000, // player cheat + MF_INCHASE = 0x00002000, // [RH] used by A_Chase and A_Look to avoid recursion + MF_FLOAT = 0x00004000, // allow moves to any height, no gravity + MF_TELEPORT = 0x00008000, // don't cross lines or look at heights + MF_MISSILE = 0x00010000, // don't hit same species, explode on block + + MF_DROPPED = 0x00020000, // dropped by a demon, not level spawned + MF_SHADOW = 0x00040000, // actor is hard for monsters to see + MF_NOBLOOD = 0x00080000, // don't bleed when shot (use puff) + MF_CORPSE = 0x00100000, // don't stop moving halfway off a step + MF_INFLOAT = 0x00200000, // floating to a height for a move, don't + // auto float to target's height + MF_INBOUNCE = 0x00200000, // used by Heretic bouncing missiles + + MF_COUNTKILL = 0x00400000, // count towards intermission kill total + MF_COUNTITEM = 0x00800000, // count towards intermission item total + + MF_SKULLFLY = 0x01000000, // skull in flight + MF_NOTDMATCH = 0x02000000, // don't spawn in death match (key cards) + + MF_SPAWNSOUNDSOURCE = 0x04000000, // Plays missile's see sound at spawning object. + MF_FRIENDLY = 0x08000000, // [RH] Friendly monsters for Strife (and MBF) + MF_UNMORPHED = 0x10000000, // [RH] Actor is the unmorphed version of something else + MF_NOLIFTDROP = 0x20000000, // [RH] Used with MF_NOGRAVITY to avoid dropping with lifts + MF_STEALTH = 0x40000000, // [RH] Andy Baker's stealth monsters + MF_ICECORPSE = 0x80000000, // a frozen corpse (for blasting) [RH] was 0x800000 + + // --- dummies for unknown/unimplemented Strife flags --- + MF_STRIFEx8000000 = 0, // seems related to MF_SHADOW +}; + +// --- mobj.flags2 --- +enum ActorFlag2 +{ + MF2_DONTREFLECT = 0x00000001, // this projectile cannot be reflected + MF2_WINDTHRUST = 0x00000002, // gets pushed around by the wind specials + MF2_DONTSEEKINVISIBLE=0x00000004, // For seeker missiles: Don't home in on invisible/shadow targets + MF2_BLASTED = 0x00000008, // actor will temporarily take damage from impact + MF2_FLY = 0x00000010, // fly mode is active + MF2_FLOORCLIP = 0x00000020, // if feet are allowed to be clipped + MF2_SPAWNFLOAT = 0x00000040, // spawn random float z + MF2_NOTELEPORT = 0x00000080, // does not teleport + MF2_RIP = 0x00000100, // missile rips through solid targets + MF2_PUSHABLE = 0x00000200, // can be pushed by other moving actors + MF2_SLIDE = 0x00000400, // slides against walls + MF2_ONMOBJ = 0x00000800, // actor is resting on top of another actor + MF2_PASSMOBJ = 0x00001000, // Enable z block checking. If on, + // this flag will allow the actor to + // pass over/under other actors. + MF2_CANNOTPUSH = 0x00002000, // cannot push other pushable mobjs + MF2_THRUGHOST = 0x00004000, // missile will pass through ghosts [RH] was 8 + MF2_BOSS = 0x00008000, // mobj is a major boss + + MF2_DONTTRANSLATE = 0x00010000, // Don't apply palette translations + MF2_NODMGTHRUST = 0x00020000, // does not thrust target when damaging + MF2_TELESTOMP = 0x00040000, // mobj can stomp another + MF2_FLOATBOB = 0x00080000, // use float bobbing z movement + MF2_THRUACTORS = 0x00100000, // performs no actor<->actor collision checks + MF2_IMPACT = 0x00200000, // an MF_MISSILE mobj can activate SPAC_IMPACT + MF2_PUSHWALL = 0x00400000, // mobj can push walls + MF2_MCROSS = 0x00800000, // can activate monster cross lines + MF2_PCROSS = 0x01000000, // can activate projectile cross lines + MF2_CANTLEAVEFLOORPIC=0x02000000, // stay within a certain floor type + MF2_NONSHOOTABLE = 0x04000000, // mobj is totally non-shootable, + // but still considered solid + MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable + MF2_DORMANT = 0x10000000, // thing is dormant + MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the + // args should not be taken from the mapthing definition + MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) + MF2_REFLECTIVE = 0x80000000, // reflects missiles +}; + +// --- mobj.flags3 --- +enum ActorFlag3 +{ + MF3_FLOORHUGGER = 0x00000001, // Missile stays on floor + MF3_CEILINGHUGGER = 0x00000002, // Missile stays on ceiling + MF3_NORADIUSDMG = 0x00000004, // Actor does not take radius damage + MF3_GHOST = 0x00000008, // Actor is a ghost + MF3_ALWAYSPUFF = 0x00000010, // Puff always appears, even when hit nothing + MF3_SPECIALFLOORCLIP= 0x00000020, // Actor uses floorclip for special effect (e.g. Wraith) + MF3_DONTSPLASH = 0x00000040, // Thing doesn't make a splash + MF3_NOSIGHTCHECK = 0x00000080, // Go after first acceptable target without checking sight + MF3_DONTOVERLAP = 0x00000100, // Don't pass over/under other things with this bit set + MF3_DONTMORPH = 0x00000200, // Immune to arti_egg + MF3_DONTSQUASH = 0x00000400, // Death ball can't squash this actor + MF3_EXPLOCOUNT = 0x00000800, // Don't explode until special2 counts to special1 + MF3_FULLVOLACTIVE = 0x00001000, // Active sound is played at full volume + MF3_ISMONSTER = 0x00002000, // Actor is a monster + MF3_SKYEXPLODE = 0x00004000, // Explode missile when hitting sky + MF3_STAYMORPHED = 0x00008000, // Monster cannot unmorph + MF3_DONTBLAST = 0x00010000, // Actor cannot be pushed by blasting + MF3_CANBLAST = 0x00020000, // Actor is not a monster but can be blasted + MF3_NOTARGET = 0x00040000, // This actor not targetted when it hurts something else + MF3_DONTGIB = 0x00080000, // Don't gib this corpse + MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines + MF3_CRASHED = 0x00200000, // Actor entered its crash state + MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) + MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) + MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV + MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things + MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact + MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood + MF3_NOEXPLODEFLOOR = 0x10000000, // Missile stops at floor instead of exploding + MF3_WARNBOT = 0x20000000, // Missile warns bot + MF3_PUFFONACTORS = 0x40000000, // Puff appears even when hit bleeding actors + MF3_HUNTPLAYERS = 0x80000000, // Used with TIDtoHate, means to hate players too +}; + +// --- mobj.flags4 --- +enum ActorFlag4 +{ + MF4_NOHATEPLAYERS = 0x00000001, // Ignore player attacks + MF4_QUICKTORETALIATE= 0x00000002, // Always switch targets when hurt + MF4_NOICEDEATH = 0x00000004, // Actor never enters an ice death, not even the generic one + MF4_BOSSDEATH = 0x00000008, // A_FreezeDeathChunks calls A_BossDeath + MF4_RANDOMIZE = 0x00000010, // Missile has random initial tic count + MF4_NOSKIN = 0x00000020, // Player cannot use skins + MF4_FIXMAPTHINGPOS = 0x00000040, // Fix this actor's position when spawned as a map thing + MF4_ACTLIKEBRIDGE = 0x00000080, // Pickups can "stand" on this actor / cannot be moved by any sector action. + MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x + + MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials + MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack + MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack + MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG + MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying. + MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger + MF4_INCOMBAT = 0x00008000, // Don't alert others when attacked by a dagger + MF4_LOOKALLAROUND = 0x00010000, // Monster has eyes in the back of its head + MF4_STANDSTILL = 0x00020000, // Monster should not chase targets unless attacked? + MF4_SPECTRAL = 0x00040000, + MF4_SCROLLMOVE = 0x00080000, // velocity has been applied by a scroller + MF4_NOSPLASHALERT = 0x00100000, // Splashes don't alert this monster + MF4_SYNCHRONIZED = 0x00200000, // For actors spawned at load-time only: Do not randomize tics + MF4_NOTARGETSWITCH = 0x00400000, // monster never switches target until current one is dead + MF4_VFRICTION = 0x00800000, // Internal flag used by A_PainAttack to push a monster down + MF4_DONTHARMCLASS = 0x01000000, // Don't hurt one's own kind with explosions (hitscans, too?) + MF4_SHIELDREFLECT = 0x02000000, + MF4_DEFLECT = 0x04000000, // different projectile reflection styles + MF4_ALLOWPARTICLES = 0x08000000, // this puff type can be replaced by particles + MF4_NOEXTREMEDEATH = 0x10000000, // this projectile or weapon never gibs its victim + MF4_EXTREMEDEATH = 0x20000000, // this projectile or weapon always gibs its victim + MF4_FRIGHTENED = 0x40000000, // Monster runs away from player + MF4_BOSSSPAWNED = 0x80000000, // Spawned by a boss spawn cube +}; + +// --- mobj.flags5 --- + +enum ActorFlag5 +{ + MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. + /* = 0x00000002, reserved for use by scripting branch */ + MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. + MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this + MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret + MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs + MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage + MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set. + MF5_BLOODSPLATTER = 0x00000100, // Blood splatter like in Raven's games. + MF5_OLDRADIUSDMG = 0x00000200, // Use old radius damage code (for barrels and boss brain) + MF5_DEHEXPLOSION = 0x00000400, // Use the DEHACKED explosion options when this projectile explodes + MF5_PIERCEARMOR = 0x00000800, // Armor doesn't protect against damage from this actor + MF5_NOBLOODDECALS = 0x00001000, // Actor bleeds but doesn't spawn blood decals + MF5_USESPECIAL = 0x00002000, // Actor executes its special when being 'used'. + MF5_NOPAIN = 0x00004000, // If set the pain state won't be entered + MF5_ALWAYSFAST = 0x00008000, // always uses 'fast' attacking logic + MF5_NEVERFAST = 0x00010000, // never uses 'fast' attacking logic + MF5_ALWAYSRESPAWN = 0x00020000, // always respawns, regardless of skill setting + MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting + MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hitting this actor + MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt + MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks + MF5_NOTIMEFREEZE = 0x00400000, // Actor is not affected by time freezer + MF5_PUFFGETSOWNER = 0x00800000, // [BB] Sets the owner of the puff to the player who fired it + MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to remove + // dependence of main engine code of specific actor types. + MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later. + MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range + MF5_BRIGHT = 0x08000000, // Actor is always rendered fullbright + MF5_CANTSEEK = 0x10000000, // seeker missiles cannot home in on this actor + MF5_INCONVERSATION = 0x20000000, // Actor is having a conversation + MF5_PAINLESS = 0x40000000, // Actor always inflicts painless damage. + MF5_MOVEWITHSECTOR = 0x80000000, // P_ChangeSector() will still process this actor if it has MF_NOBLOCKMAP +}; + +// --- mobj.flags6 --- +enum ActorFlag6 +{ + MF6_NOBOSSRIP = 0x00000001, // For rippermissiles: Don't rip through bosses. + MF6_THRUSPECIES = 0x00000002, // Actors passes through other of the same species. + MF6_MTHRUSPECIES = 0x00000004, // Missile passes through actors of its shooter's species. + MF6_FORCEPAIN = 0x00000008, // forces target into painstate (unless it has the NOPAIN flag) + MF6_NOFEAR = 0x00000010, // Not scared of frightening players + MF6_BUMPSPECIAL = 0x00000020, // Actor executes its special when being collided (as the ST flag) + MF6_DONTHARMSPECIES = 0x00000040, // Don't hurt one's own species with explosions (hitscans, too?) + MF6_STEPMISSILE = 0x00000080, // Missile can "walk" up steps + MF6_NOTELEFRAG = 0x00000100, // [HW] Actor can't be telefragged + MF6_TOUCHY = 0x00000200, // From MBF: killough 11/98: dies when solids touch it + MF6_CANJUMP = 0x00000400, // From MBF: a dedicated flag instead of the BOUNCES+FLOAT+sentient combo + MF6_JUMPDOWN = 0x00000800, // From MBF: generalization of dog behavior wrt. dropoffs. + MF6_VULNERABLE = 0x00001000, // Actor can be damaged (even if not shootable). + MF6_ARMED = 0x00002000, // From MBF: Object is armed (for MF6_TOUCHY objects) + MF6_FALLING = 0x00004000, // From MBF: Object is falling (for pseudotorque simulation) + MF6_LINEDONE = 0x00008000, // From MBF: Object has already run a line effect + MF6_NOTRIGGER = 0x00010000, // actor cannot trigger any line actions + MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering + MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) + MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself + MF6_ADDITIVEPOISONDAMAGE = 0x00100000, + MF6_ADDITIVEPOISONDURATION = 0x00200000, + MF6_NOMENU = 0x00400000, // Player class should not appear in the class selection menu. + MF6_BOSSCUBE = 0x00800000, // Actor spawned by A_BrainSpit, flagged for timefreeze reasons. + MF6_SEEINVISIBLE = 0x01000000, // Monsters can see invisible player. + MF6_DONTCORPSE = 0x02000000, // [RC] Don't autoset MF_CORPSE upon death and don't force Crash state change. + MF6_POISONALWAYS = 0x04000000, // Always apply poison, even when target can't take the damage. + MF6_DOHARMSPECIES = 0x08000000, // Do hurt one's own species with projectiles. + MF6_INTRYMOVE = 0x10000000, // Executing P_TryMove + MF6_NOTAUTOAIMED = 0x20000000, // Do not subject actor to player autoaim. + MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. + MF6_RELATIVETOFLOOR = 0x80000000, // [RC] Make flying actors be affected by lifts. +}; + +// --- mobj.flags7 --- +enum ActorFlag7 +{ + MF7_NEVERTARGET = 0x00000001, // can not be targetted at all, even if monster friendliness is considered. + MF7_NOTELESTOMP = 0x00000002, // cannot telefrag under any circumstances (even when set by MAPINFO) + MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. + MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag + MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag + MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters. + MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. + MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. + MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. + MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't. + MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN. + MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles. + MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected. + MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile. + MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway. + MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target. + MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer. + MF7_FLYCHEAT = 0x00020000, // must be part of the actor so that it can be tracked properly + MF7_NODECAL = 0x00040000, // [ZK] Forces puff to have no impact decal + MF7_FORCEDECAL = 0x00080000, // [ZK] Forces puff's decal to override the weapon's. + MF7_LAXTELEFRAGDMG = 0x00100000, // [MC] Telefrag damage can be reduced. + MF7_ICESHATTER = 0x00200000, // [MC] Shatters ice corpses regardless of damagetype. +}; + +// --- mobj.renderflags --- +enum ActorRenderFlag +{ + RF_XFLIP = 0x0001, // Flip sprite horizontally + RF_YFLIP = 0x0002, // Flip sprite vertically + RF_ONESIDED = 0x0004, // Wall/floor sprite is visible from front only + RF_FULLBRIGHT = 0x0010, // Sprite is drawn at full brightness + + RF_RELMASK = 0x0300, // ---Relative z-coord for bound actors (these obey texture pegging) + RF_RELABSOLUTE = 0x0000, // Actor z is absolute + RF_RELUPPER = 0x0100, // Actor z is relative to upper part of wall + RF_RELLOWER = 0x0200, // Actor z is relative to lower part of wall + RF_RELMID = 0x0300, // Actor z is relative to middle part of wall + + RF_CLIPMASK = 0x0c00, // ---Clipping for bound actors + RF_CLIPFULL = 0x0000, // Clip sprite to full height of wall + RF_CLIPUPPER = 0x0400, // Clip sprite to upper part of wall + RF_CLIPMID = 0x0800, // Clip sprite to mid part of wall + RF_CLIPLOWER = 0x0c00, // Clip sprite to lower part of wall + + RF_DECALMASK = RF_RELMASK|RF_CLIPMASK, + + RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types, not all implemented + RF_FACESPRITE = 0x0000, // Face sprite + RF_WALLSPRITE = 0x1000, // Wall sprite + RF_FLOORSPRITE = 0x2000, // Floor sprite + RF_VOXELSPRITE = 0x3000, // Voxel object + RF_INVISIBLE = 0x8000, // Don't bother drawing this actor + + RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting) + RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting) +}; + +#define TRANSLUC25 (FRACUNIT/4) +#define TRANSLUC33 (FRACUNIT/3) +#define TRANSLUC50 (FRACUNIT/2) +#define TRANSLUC66 ((FRACUNIT*2)/3) +#define TRANSLUC75 ((FRACUNIT*3)/4) + +// also #defines OPAQUE +#ifndef OPAQUE +#define OPAQUE (FRACUNIT) +#endif + +// This translucency value produces the closest match to Heretic's TINTTAB. +// ~40% of the value of the overlaid image shows through. +#define HR_SHADOW (0x6800) + +// Hexen's TINTTAB is the same as Heretic's, just reversed. +#define HX_SHADOW (0x9800) +#define HX_ALTSHADOW (0x6800) + +// This could easily be a bool but then it'd be much harder to find later. ;) +enum replace_t +{ + NO_REPLACE = 0, + ALLOW_REPLACE = 1 +}; + +enum ActorBounceFlag +{ + BOUNCE_Walls = 1<<0, // bounces off of walls + BOUNCE_Floors = 1<<1, // bounces off of floors + BOUNCE_Ceilings = 1<<2, // bounces off of ceilings + BOUNCE_Actors = 1<<3, // bounces off of some actors + BOUNCE_AllActors = 1<<4, // bounces off of all actors (requires BOUNCE_Actors to be set, too) + BOUNCE_AutoOff = 1<<5, // when bouncing off a sector plane, if the new Z velocity is below 3.0, disable further bouncing + BOUNCE_HereticType = 1<<6, // goes into Death state when bouncing on floors or ceilings + + BOUNCE_UseSeeSound = 1<<7, // compatibility fallback. This will only be set by + // the compatibility handlers for the old bounce flags. + BOUNCE_NoWallSound = 1<<8, // don't make noise when bouncing off a wall + BOUNCE_Quiet = 1<<9, // Strife's grenades don't make a bouncing sound + BOUNCE_ExplodeOnWater = 1<<10, // explodes when hitting a water surface + BOUNCE_CanBounceWater = 1<<11, // can bounce on water + // MBF bouncing is a bit different from other modes as Killough coded many special behavioral cases + // for them that are not present in ZDoom, so it is necessary to identify it properly. + BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. + BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors + BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states + + BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, + + // The three "standard" types of bounciness are: + // HERETIC - Missile will only bounce off the floor once and then enter + // its death state. It does not bounce off walls at all. + // HEXEN - Missile bounces off of walls and floors indefinitely. + // DOOM - Like Hexen, but the bounce turns off if its vertical velocity + // is too low. + BOUNCE_None = 0, + BOUNCE_Heretic = BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_HereticType, + BOUNCE_Doom = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff, + BOUNCE_Hexen = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors, + BOUNCE_Grenade = BOUNCE_MBF | BOUNCE_Doom, // Bounces on walls and flats like ZDoom bounce. + BOUNCE_Classic = BOUNCE_MBF | BOUNCE_Floors | BOUNCE_Ceilings, // Bounces on flats only, but + // does not die when bouncing. + + // combined types + BOUNCE_DoomCompat = BOUNCE_Doom | BOUNCE_UseSeeSound, + BOUNCE_HereticCompat = BOUNCE_Heretic | BOUNCE_UseSeeSound, + BOUNCE_HexenCompat = BOUNCE_Hexen | BOUNCE_UseSeeSound + + // The distinction between BOUNCE_Actors and BOUNCE_AllActors: A missile with + // BOUNCE_Actors set will bounce off of reflective and "non-sentient" actors. + // A missile that also has BOUNCE_AllActors set will bounce off of any actor. + // For compatibility reasons when BOUNCE_Actors was implied by the bounce type + // being "Doom" or "Hexen" and BOUNCE_AllActors was the separate + // MF5_BOUNCEONACTORS, you must set BOUNCE_Actors for BOUNCE_AllActors to have + // an effect. + + +}; + +// [TP] Flagset definitions +typedef TFlags ActorFlags; +typedef TFlags ActorFlags2; +typedef TFlags ActorFlags3; +typedef TFlags ActorFlags4; +typedef TFlags ActorFlags5; +typedef TFlags ActorFlags6; +typedef TFlags ActorFlags7; +typedef TFlags ActorRenderFlags; +typedef TFlags ActorBounceFlags; +DEFINE_TFLAGS_OPERATORS (ActorFlags) +DEFINE_TFLAGS_OPERATORS (ActorFlags2) +DEFINE_TFLAGS_OPERATORS (ActorFlags3) +DEFINE_TFLAGS_OPERATORS (ActorFlags4) +DEFINE_TFLAGS_OPERATORS (ActorFlags5) +DEFINE_TFLAGS_OPERATORS (ActorFlags6) +DEFINE_TFLAGS_OPERATORS (ActorFlags7) +DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) +DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) + +// Used to affect the logic for thing activation through death, USESPECIAL and BUMPSPECIAL +// "thing" refers to what has the flag and the special, "trigger" refers to what used or bumped it +enum EThingSpecialActivationType +{ + THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator + THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special + THINGSPEC_ThingTargets = 1<<1, // The thing changes its target to the trigger + THINGSPEC_TriggerTargets = 1<<2, // The trigger changes its target to the thing + THINGSPEC_MonsterTrigger = 1<<3, // The thing can be triggered by a monster + THINGSPEC_MissileTrigger = 1<<4, // The thing can be triggered by a projectile + THINGSPEC_ClearSpecial = 1<<5, // Clears special after successful activation + THINGSPEC_NoDeathSpecial = 1<<6, // Don't activate special on death + THINGSPEC_TriggerActs = 1<<7, // The trigger is the activator of the special + // (overrides LEVEL_ACTOWNSPECIAL Hexen hack) + THINGSPEC_Activate = 1<<8, // The thing is activated when triggered + THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered + THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered +}; + +// [RH] Like msecnode_t, but for the blockmap +struct FBlockNode +{ + AActor *Me; // actor this node references + int BlockIndex; // index into blocklinks for the block this node is in + FBlockNode **PrevActor; // previous actor in this block + FBlockNode *NextActor; // next actor in this block + FBlockNode **PrevBlock; // previous block this actor is in + FBlockNode *NextBlock; // next block this actor is in + + static FBlockNode *Create (AActor *who, int x, int y); + void Release (); + + static FBlockNode *FreeBlocks; +}; + +class FDecalBase; +class AInventory; + +inline AActor *GetDefaultByName (const char *name) +{ + return (AActor *)(PClass::FindClass(name)->Defaults); +} + +inline AActor *GetDefaultByType (const PClass *type) +{ + return (AActor *)(type->Defaults); +} + +template +inline T *GetDefault () +{ + return (T *)(RUNTIME_CLASS(T)->Defaults); +} + +struct line_t; +struct secplane_t; +struct FStrifeDialogueNode; + +enum +{ + AMETA_BASE = 0x12000, + + AMETA_Obituary, // string (player was killed by this actor) + AMETA_HitObituary, // string (player was killed by this actor in melee) + AMETA_DeathHeight, // fixed (height on normal death) + AMETA_BurnHeight, // fixed (height on burning death) + AMETA_StrifeName, // string (for named Strife objects) + AMETA_BloodColor, // colorized blood + AMETA_GibHealth, // negative health below which this monster dies an extreme death + AMETA_WoundHealth, // health needed to enter wound state + AMETA_FastSpeed, // Speed in fast mode + AMETA_RDFactor, // Radius damage factor + AMETA_CameraHeight, // Height of camera when used as such + AMETA_HowlSound, // Sound being played when electrocuted or poisoned + AMETA_BloodType, // Blood replacement type + AMETA_BloodType2, // Bloodsplatter replacement type + AMETA_BloodType3, // AxeBlood replacement type +}; + +struct FDropItem +{ + FName Name; + int probability; + int amount; + FDropItem * Next; +}; + +class FDropItemPtrArray : public TArray +{ +public: + ~FDropItemPtrArray() + { + Clear(); + } + + void Clear(); +}; + +extern FDropItemPtrArray DropItemList; + +void FreeDropItemChain(FDropItem *chain); +int StoreDropItemChain(FDropItem *chain); +fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... + + + +// Map Object definition. +class AActor : public DThinker +{ + DECLARE_CLASS (AActor, DThinker) + HAS_OBJECT_POINTERS +public: + AActor () throw(); + AActor (const AActor &other) throw(); + AActor &operator= (const AActor &other); + void Destroy (); + ~AActor (); + + void Serialize (FArchive &arc); + + static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); + + inline AActor *GetDefault () const + { + return (AActor *)(RUNTIME_TYPE(this)->Defaults); + } + + FDropItem *GetDropItems(); + + // Return true if the monster should use a missile attack, false for melee + bool SuggestMissileAttack (fixed_t dist); + + // Adjusts the angle for deflection/reflection of incoming missiles + // Returns true if the missile should be allowed to explode anyway + bool AdjustReflectionAngle (AActor *thing, angle_t &angle); + + // Returns true if this actor is within melee range of its target + bool CheckMeleeRange(); + + virtual void BeginPlay(); // Called immediately after the actor is created + virtual void PostBeginPlay(); // Called immediately before the actor's first tick + virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world + virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. + + virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. + + virtual void Activate (AActor *activator); + virtual void Deactivate (AActor *activator); + + virtual void Tick (); + + // Called when actor dies + virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); + + // Perform some special damage action. Returns the amount of damage to do. + // Returning -1 signals the damage routine to exit immediately + virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype); + + // Like DoSpecialDamage, but called on the actor receiving the damage. + virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); + + // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed + // Made a metadata property so no longer virtual + void Howl (); + + // Actor just hit the floor + virtual void HitFloor (); + + // plays bouncing sound + void PlayBounceSound(bool onfloor); + + // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor + virtual bool FloorBounceMissile (secplane_t &plane); + + // Called when an actor is to be reflected by a disc of repulsion. + // Returns true to continue normal blast processing. + virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); + + // Called by RoughBlockCheck + bool IsOkayToAttack (AActor *target); + + // Plays the actor's ActiveSound if its voice isn't already making noise. + void PlayActiveSound (); + + // Actor had MF_SKULLFLY set and rammed into something + // Returns false to stop moving and true to keep moving + virtual bool Slam (AActor *victim); + + // Called by PIT_CheckThing() and needed for some Hexen things. + // Returns -1 for normal behavior, 0 to return false, and 1 to return true. + // I'm not sure I like it this way, but it will do for now. + virtual int SpecialMissileHit (AActor *victim); + + // Returns true if it's okay to switch target to "other" after being attacked by it. + virtual bool OkayToSwitchTarget (AActor *other); + + // Something just touched this actor. + virtual void Touch (AActor *toucher); + + // Adds the item to this actor's inventory and sets its Owner. + virtual void AddInventory (AInventory *item); + + // Removes the item from the inventory list. + virtual void RemoveInventory (AInventory *item); + + // Take the amount value of an item from the inventory list. + // If nothing is left, the item may be destroyed. + // Returns true if the initial item count is positive. + virtual bool TakeInventory (const PClass *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); + + // Uses an item and removes it from the inventory. + virtual bool UseInventory (AInventory *item); + + // Tosses an item out of the inventory. + virtual AInventory *DropInventory (AInventory *item); + + // Removes all items from the inventory. + void ClearInventory(); + + // Returns true if this view is considered "local" for the player. + bool CheckLocalView (int playernum) const; + + // Finds the first item of a particular type. + AInventory *FindInventory (const PClass *type, bool subclass = false); + AInventory *FindInventory (FName type); + template T *FindInventory () + { + return static_cast (FindInventory (RUNTIME_CLASS(T))); + } + + // Adds one item of a particular type. Returns NULL if it could not be added. + AInventory *GiveInventoryType (const PClass *type); + + // Returns the first item held with IF_INVBAR set. + AInventory *FirstInv (); + + // Tries to give the actor some ammo. + bool GiveAmmo (const PClass *type, int amount); + + // Destroys all the inventory the actor is holding. + void DestroyAllInventory (); + + // Set the alphacolor field properly + void SetShade (DWORD rgb); + void SetShade (int r, int g, int b); + + // Plays a conversation animation + void ConversationAnimation (int animnum); + + // Make this actor hate the same things as another actor + void CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth=true); + + // Moves the other actor's inventory to this one + void ObtainInventory (AActor *other); + + // Die. Now. + virtual bool Massacre (); + + // Transforms the actor into a finely-ground paste + virtual bool Grind(bool items); + + // Get this actor's team + int GetTeam(); + + // Is the other actor on my team? + bool IsTeammate (AActor *other); + + // Is the other actor my friend? + bool IsFriend (AActor *other); + + // Do I hate the other actor? + bool IsHostile (AActor *other); + + inline bool IsNoClip2() const; + + // What species am I? + virtual FName GetSpecies(); + + fixed_t GetBobOffset(fixed_t ticfrac=0) const + { + if (!(flags2 & MF2_FLOATBOB)) + { + return 0; + } + return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8; + } + + // Enter the crash state + void Crash(); + + // Return starting health adjusted by skill level + int SpawnHealth(); + int GibHealth(); + + inline bool isMissile(bool precise=true) + { + return (flags&MF_MISSILE) || (precise && GetDefault()->flags&MF_MISSILE); + } + + // Check for monsters that count as kill but excludes all friendlies. + bool CountsAsKill() const + { + return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); + } + + bool intersects(AActor *other) const + { + fixed_t blockdist = radius + other->radius; + return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); + } + + PalEntry GetBloodColor() const + { + return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); + } + + // These also set CF_INTERPVIEW for players. + void SetPitch(int p, bool interpolate, bool forceclamp = false); + void SetAngle(angle_t ang, bool interpolate); + void SetRoll(angle_t roll, bool interpolate); + + const PClass *GetBloodType(int type = 0) const + { + const PClass *bloodcls; + if (type == 0) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + } + else if (type == 1) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); + } + else if (type == 2) + { + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); + } + else return NULL; + + if (bloodcls != NULL) + { + bloodcls = bloodcls->GetReplacement(); + } + return bloodcls; + } + + // 'absolute' is reserved for a linked portal implementation which needs + // to distinguish between portal-aware and portal-unaware distance calculation. + fixed_t AproxDistance(AActor *other, bool absolute = false) + { + return P_AproxDistance(x - other->x, y - other->y); + } + + // same with 'ref' here. + fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return P_AproxDistance(x - otherx, y - othery); + } + + fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) + { + return P_AproxDistance(x - other->x + xadd, y - other->y + yadd); + } + + fixed_t AproxDistance3D(AActor *other, bool absolute = false) + { + return P_AproxDistance(AproxDistance(other), z - other->z); + } + + // more precise, but slower version, being used in a few places + fixed_t Distance2D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length()); + } + + // a full 3D version of the above + fixed_t Distance3D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); + } + + inline void SetFriendPlayer(player_t *player); + + bool IsVisibleToPlayer() const; + + // Calculate amount of missile damage + virtual int GetMissileDamage(int mask, int add); + + bool CanSeek(AActor *target) const; + + fixed_t GetGravity() const; + bool IsSentient() const; + const char *GetTag(const char *def = NULL) const; + void SetTag(const char *def); + + // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector + void CheckSectorTransition(sector_t *oldsec); + +// info for drawing +// NOTE: The first member variable *must* be x. + fixed_t x,y,z; + AActor *snext, **sprev; // links in sector (if needed) + angle_t angle; + WORD sprite; // used to find patch_t and flip value + BYTE frame; // sprite frame to draw + fixed_t scaleX, scaleY; // Scaling values; FRACUNIT is normal size + FRenderStyle RenderStyle; // Style to draw this actor with + ActorRenderFlags renderflags; // Different rendering flags + FTextureID picnum; // Draw this instead of sprite if valid + DWORD effects; // [RH] see p_effect.h + fixed_t alpha; + DWORD fillcolor; // Color to draw when STYLE_Shaded + +// interaction info + fixed_t pitch; + angle_t roll; // This was fixed_t before, which is probably wrong + FBlockNode *BlockNode; // links in blocks (if needed) + struct sector_t *Sector; + subsector_t * subsector; + fixed_t floorz, ceilingz; // closest together of contacted secs + fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. + + struct sector_t *floorsector; + FTextureID floorpic; // contacted sec floorpic + int floorterrain; + struct sector_t *ceilingsector; + FTextureID ceilingpic; // contacted sec ceilingpic + fixed_t radius, height; // for movement checking + fixed_t projectilepassheight; // height for clipping projectile movement against this actor + fixed_t velx, vely, velz; // velocity + SDWORD tics; // state tic counter + FState *state; + SDWORD Damage; // For missiles and monster railgun + int projectileKickback; + ActorFlags flags; + ActorFlags2 flags2; // Heretic flags + ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable + ActorFlags4 flags4; // [RH] Even more flags! + ActorFlags5 flags5; // OMG! We need another one. + ActorFlags6 flags6; // Shit! Where did all the flags go? + ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? + + // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. + DWORD VisibleToTeam; + + int special1; // Special info + int special2; // Special info + int weaponspecial; // Special info for weapons. + int health; + BYTE movedir; // 0-7 + SBYTE visdir; + SWORD movecount; // when 0, select a new dir + SWORD strafecount; // for MF3_AVOIDMELEE + TObjPtr target; // thing being chased/attacked (or NULL) + // also the originator for missiles + TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 + TObjPtr LastHeard; // [RH] Last actor this one heard + SDWORD reactiontime; // if non 0, don't attack yet; used by + // player to freeze a bit after teleporting + SDWORD threshold; // if > 0, the target will be chased + // no matter what (even if shot) + player_t *player; // only valid if type of APlayerPawn + TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) + fixed_t SpawnPoint[3]; // For nightmare respawn + WORD SpawnAngle; + int StartHealth; + BYTE WeaveIndexXY; // Separated from special2 because it's used by globally accessible functions. + BYTE WeaveIndexZ; + int skillrespawncount; + int TIDtoHate; // TID of things to hate (0 if none) + FNameNoInit Species; // For monster families + TObjPtr tracer; // Thing being chased/attacked for tracers + TObjPtr master; // Thing which spawned this one (prevents mutual attacks) + fixed_t floorclip; // value to use for floor clipping + int tid; // thing identifier + int special; // special + int args[5]; // special arguments + + int accuracy, stamina; // [RH] Strife stats -- [XA] moved here for DECORATE/ACS access. + + AActor *inext, **iprev;// Links to other mobjs in same bucket + TObjPtr goal; // Monster's goal if not chasing anything + int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes + BYTE boomwaterlevel; // splash information for non-swimmable water sectors + BYTE MinMissileChance;// [RH] If a random # is > than this, then missile attack. + SBYTE LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0) + ActorBounceFlags BounceFlags; // which bouncing type? + DWORD SpawnFlags; // Increased to DWORD because of Doom 64 + fixed_t meleerange; // specifies how far a melee attack reaches. + fixed_t meleethreshold; // Distance below which a monster doesn't try to shoot missiles anynore + // but instead tries to come closer for a melee attack. + // This is not the same as meleerange + fixed_t maxtargetrange; // any target farther away cannot be attacked + fixed_t bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. + fixed_t wallbouncefactor; // The bounce factor for walls can be different. + int bouncecount; // Strife's grenades only bounce twice before exploding + fixed_t gravity; // [GRB] Gravity factor + fixed_t Friction; + int FastChaseStrafeCount; + fixed_t pushfactor; + int lastpush; + int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL + int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL + int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. + FString * Tag; // Strife's tag name. + int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players. + + AActor *BlockingMobj; // Actor that blocked the last move + line_t *BlockingLine; // Line that blocked the last move + + int PoisonDamage; // Damage received per tic from poison. + FNameNoInit PoisonDamageType; // Damage type dealt by poison. + int PoisonDuration; // Duration left for receiving poison damage. + int PoisonPeriod; // How often poison damage is applied. (Every X tics.) + + int PoisonDamageReceived; // Damage received per tic from poison. + FNameNoInit PoisonDamageTypeReceived; // Damage type received by poison. + int PoisonDurationReceived; // Duration left for receiving poison damage. + int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.) + TObjPtr Poisoner; // Last source of received poison damage. + + // a linked list of sectors where this object appears + struct msecnode_t *touching_sectorlist; // phares 3/14/98 + + TObjPtr Inventory; // [RH] This actor's inventory + DWORD InventoryID; // A unique ID to keep track of inventory items + + BYTE smokecounter; + BYTE FloatBobPhase; + BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) + DWORD Translation; + + // [RH] Stuff that used to be part of an Actor Info + FSoundIDNoInit SeeSound; + FSoundIDNoInit AttackSound; + FSoundIDNoInit PainSound; + FSoundIDNoInit DeathSound; + FSoundIDNoInit ActiveSound; + FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. + FSoundIDNoInit BounceSound; + FSoundIDNoInit WallBounceSound; + FSoundIDNoInit CrushPainSound; + + fixed_t Speed; + fixed_t FloatSpeed; + fixed_t MaxDropOffHeight, MaxStepHeight; + SDWORD Mass; + SWORD PainChance; + int PainThreshold; + FNameNoInit DamageType; + FNameNoInit DamageTypeReceived; + fixed_t DamageFactor; + fixed_t DamageMultiply; + + FNameNoInit PainType; + FNameNoInit DeathType; + const PClass *TeleFogSourceType; + const PClass *TeleFogDestType; + int RipperLevel; + int RipLevelMin; + int RipLevelMax; + + FState *SpawnState; + FState *SeeState; + FState *MeleeState; + FState *MissileState; + + + int ConversationRoot; // THe root of the current dialogue + FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." + + // [RH] Decal(s) this weapon/projectile generates on impact. + FDecalBase *DecalGenerator; + + // [RH] Used to interpolate the view to get >35 FPS + fixed_t PrevX, PrevY, PrevZ; + angle_t PrevAngle; + + // ThingIDs + static void ClearTIDHashes (); + void AddToHash (); + void RemoveFromHash (); + +private: + static AActor *TIDHash[128]; + static inline int TIDHASH (int key) { return key & 127; } + static FSharedStringArena mStringPropertyData; + + friend class FActorIterator; + friend bool P_IsTIDUsed(int tid); + + sector_t *LinkToWorldForMapThing (); + +public: + void LinkToWorld (bool buggy=false); + void LinkToWorld (sector_t *sector); + void UnlinkFromWorld (); + void AdjustFloorClip (); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z); + bool InStateSequence(FState * newstate, FState * basestate); + int GetTics(FState * newstate); + bool SetState (FState *newstate, bool nofunction=false); + virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); + bool isFast(); + bool isSlow(); + void SetIdle(bool nofunction=false); + void ClearCounters(); + FState *GetRaiseState(); + void Revive(); + + FState *FindState (FName label) const + { + return GetClass()->ActorInfo->FindState(1, &label); + } + + FState *FindState (FName label, FName sublabel, bool exact = false) const + { + FName names[] = { label, sublabel }; + return GetClass()->ActorInfo->FindState(2, names, exact); + } + + FState *FindState(int numnames, FName *names, bool exact = false) const + { + return GetClass()->ActorInfo->FindState(numnames, names, exact); + } + + bool HasSpecialDeathStates () const; +}; + +class FActorIterator +{ +public: + FActorIterator (int i) : base (NULL), id (i) + { + } + FActorIterator (int i, AActor *start) : base (start), id (i) + { + } + AActor *Next () + { + if (id == 0) + return NULL; + if (!base) + base = AActor::TIDHash[id & 127]; + else + base = base->inext; + + while (base && base->tid != id) + base = base->inext; + + return base; + } +private: + AActor *base; + int id; +}; + +template +class TActorIterator : public FActorIterator +{ +public: + TActorIterator (int id) : FActorIterator (id) {} + T *Next () + { + AActor *actor; + do + { + actor = FActorIterator::Next (); + } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); + return static_cast(actor); + } +}; + +class NActorIterator : public FActorIterator +{ + const PClass *type; +public: + NActorIterator (const PClass *cls, int id) : FActorIterator (id) { type = cls; } + NActorIterator (FName cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } + NActorIterator (const char *cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); } + AActor *Next () + { + AActor *actor; + if (type == NULL) return NULL; + do + { + actor = FActorIterator::Next (); + } while (actor && !actor->IsKindOf (type)); + return actor; + } +}; + +bool P_IsTIDUsed(int tid); +int P_FindUniqueTID(int start_tid, int limit); + +inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +{ + return AActor::StaticSpawn (type, x, y, z, allowreplacement); +} + +AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); +AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); + +template +inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +{ + return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); +} + + +void PrintMiscActorInfo(AActor * query); + +#define S_FREETARGMOBJ 1 + +#endif // __P_MOBJ_H__ diff --git a/src/b_func.cpp b/src/b_func.cpp index f93625612..87b1e5416 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -37,7 +37,7 @@ bool DBot::Reachable (AActor *rtarget) sector_t *last_s = player->mo->Sector; fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y); - fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y); + fixed_t estimated_dist = player->mo->AproxDistance(rtarget); bool reachable = true; FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); @@ -165,10 +165,8 @@ void DBot::Dofire (ticcmd_t *cmd) //MAKEME: Decrease the rocket suicides even more. no_fire = true; - //angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); //Distance to enemy. - dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx), - (player->mo->y + player->mo->vely) - (enemy->y + enemy->vely)); + dist = player->mo->AproxDistance(enemy, player->mo->velx - enemy->velx, player->mo->vely - enemy->vely); //FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go. if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON) @@ -219,7 +217,7 @@ void DBot::Dofire (ticcmd_t *cmd) } // prediction aiming shootmissile: - dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y); + dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); @@ -331,8 +329,7 @@ AActor *DBot::Choose_Mate () { if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY)) { - test = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + test = client->mo->AproxDistance(player->mo); if (test < closest_dist) { @@ -402,8 +399,7 @@ AActor *DBot::Find_enemy () if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. //if(P_CheckSight(player->mo, players[count].mo)) { - temp = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + temp = client->mo->AproxDistance(player->mo); //Too dark? if (temp > DARK_DIST && @@ -505,7 +501,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) actor = bglobal.body2; - dist = P_AproxDistance (actor->x-enemy->x, actor->y-enemy->y); + dist = actor->AproxDistance (enemy); if (dist < SAFE_SELF_MISDIST) return 0; //Predict. diff --git a/src/b_move.cpp b/src/b_move.cpp index 4759f22d9..c608c5d03 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -347,7 +347,7 @@ void DBot::Pitch (AActor *target) double diff; diff = target->z - player->mo->z; - aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y)); + aim = atan(diff / (double)player->mo->AproxDistance(target)); player->mo->pitch = -(int)(aim * ANGLE_180/M_PI); } diff --git a/src/b_think.cpp b/src/b_think.cpp index 34baeee9c..73c5066ab 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -81,7 +81,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) int r; stuck = false; - dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0; + dist = dest ? player->mo->AproxDistance(dest) : 0; if (missile && ((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2))) @@ -96,14 +96,14 @@ void DBot::ThinkForMove (ticcmd_t *cmd) player->mo->pitch += 80; //HOW TO MOVE: - if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. - if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000) + if ((player->mo->AproxDistance(oldx, oldy)<50000) && t_strafe<=0) { t_strafe = 5; @@ -156,7 +156,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) t_fight = AFTERTICS; if (t_strafe <= 0 && - (P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000 + (player->mo->AproxDistance(oldx, oldy)<50000 || ((pr_botmove()%30)==10)) ) { @@ -168,7 +168,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); if (player->ReadyWeapon == NULL || - P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) > + player->mo->AproxDistance(enemy) > player->ReadyWeapon->MoveCombatDist) { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) @@ -208,7 +208,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); - matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y); + matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) cmd->ucmd.forwardmove = FORWARDRUN; else if (matedist > FRIEND_DIST) diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index fdc0257cb..1182292e0 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -36,7 +36,7 @@ void A_SkullAttack(AActor *self, fixed_t speed) an = self->angle >> ANGLETOFINESHIFT; self->velx = FixedMul (speed, finecosine[an]); self->vely = FixedMul (speed, finesine[an]); - dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); + dist = self->AproxDistance (dest); dist = dist / speed; if (dist < 1) diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 0600a59eb..90c6e0a51 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -102,10 +102,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // change slope - dist = P_AproxDistance (dest->x - self->x, - dest->y - self->y); - - dist = dist / self->Speed; + dist = self->AproxDistance (dest) / self->Speed; if (dist < 1) dist = 1; diff --git a/src/g_game.cpp b/src/g_game.cpp index 64e746cef..b7d10251b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1479,8 +1479,7 @@ static fixed_t PlayersRangeFromSpot (FPlayerStart *spot) if (!playeringame[i] || !players[i].mo || players[i].health <= 0) continue; - distance = P_AproxDistance (players[i].mo->x - spot->x, - players[i].mo->y - spot->y); + distance = players[i].mo->AproxDistance (spot->x, spot->y); if (distance < closest) closest = distance; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index dba16b622..75c05bf2b 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -91,8 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) P_TraceBleed (newdam > 0 ? newdam : damage, target, self); return; } - dist = P_AproxDistance (self->x-target->x, self->y-target->y) - > 8*64*FRACUNIT; + dist = self->AproxDistance (target) > 8*64*FRACUNIT; randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index a78b0b4c8..53ce08b50 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -141,7 +141,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { // Must be monster, player, missile, touchy or vulnerable continue; } - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance (mo); if (dist > radius) { // Out of range continue; diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 2b469e5af..73ffeac88 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -264,12 +264,11 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist) { an = R_PointToAngle2(actor->x, actor->y, child->x, child->y)>>ANGLETOFINESHIFT; - oldDistance = P_AproxDistance (child->x-actor->x, child->y-actor->y); + oldDistance = child->AproxDistance (actor); if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]), actor->y+FixedMul(dist, finesine[an]), true)) { - newDistance = P_AproxDistance (child->x-actor->x, - child->y-actor->y)-FRACUNIT; + newDistance = child->AproxDistance (actor)-FRACUNIT; if (oldDistance < FRACUNIT) { if (child->z < actor->z) @@ -425,7 +424,7 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); + dist = actor->AproxDistance (target); dist = dist / actor->Speed; if (dist < 1) { diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index fdf2428af..5b18c0d57 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -59,22 +59,16 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) angle = actor->angle>>ANGLETOFINESHIFT; actor->velx = FixedMul (actor->Speed, finecosine[angle]); actor->vely = FixedMul (actor->Speed, finesine[angle]); + dist = actor->AproxDistance (target) / actor->Speed; if (actor->z+actor->height < target->z || target->z+target->height < actor->z) { - dist = P_AproxDistance(target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; if (dist < 1) { dist = 1; } actor->velz = (target->z - actor->z)/dist; } - else - { - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; - } if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64) { // attack the destination mobj if it's attackable AActor *oldTarget; diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index c588dd2ae..b1cfafc0c 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -158,7 +158,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->special2 = 0; self->velx = self->vely = 0; - dist = P_AproxDistance (self->x - target->x, self->y - target->y); + dist = self->AproxDistance (target); if (dist < FIREDEMON_ATTACK_RANGE) { if (pr_firedemonchase() < 30) diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index b827f666b..d1d39ddd4 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -37,7 +37,7 @@ bool AArtiHealingRadius::Use (bool pickup) if (playeringame[i] && players[i].mo != NULL && players[i].mo->health > 0 && - P_AproxDistance (players[i].mo->x - Owner->x, players[i].mo->y - Owner->y) <= HEAL_RADIUS_DIST) + players[i].mo->AproxDistance (Owner) <= HEAL_RADIUS_DIST) { // Q: Is it worth it to make this selectable as a player property? // A: Probably not - but it sure doesn't hurt. diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 9ca0a70e8..498b4e955 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -665,8 +665,7 @@ void A_SorcOffense2(AActor *actor) if (mo) { mo->special2 = 35*5/2; // 5 seconds - dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y); - dist = dist/mo->Speed; + dist = mo->AproxDistance(dest) / mo->Speed; if(dist < 1) dist = 1; mo->velz = (dest->z - mo->z) / dist; } diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 5323fb851..ca849dd97 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -388,8 +388,7 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; + dist = actor->AproxDistance (target) / actor->Speed; if (dist < 1) { dist = 1; @@ -495,8 +494,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - x, dest->y - y); - dist = dist/th->Speed; + dist = dest->AproxDistance (x, y, source) / th->Speed; if (dist < 1) { dist = 1; diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 0f9d9cd55..c0095226e 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -185,7 +185,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) { S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM); } - dist = P_AproxDistance (self->x-target->x, self->y-target->y); + dist = self->AproxDistance (target); if (target->z+target->height > self->z && target->z+target->height < self->z+self->height && dist < (friendly ? 16*64*FRACUNIT : 8*64*FRACUNIT) @@ -489,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) mo = player->mo; if (mo == master) continue; if (mo->health <= 0) continue; - dist = P_AproxDistance(self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; self->target = mo; break; @@ -514,7 +514,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) if (!(mo->flags3 & MF3_ISMONSTER)) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_SHOOTABLE)) continue; - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; if ((mo == master) || (mo == self)) continue; if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 3c8d704aa..195f3ccbf 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -129,7 +129,7 @@ void DEarthquake::Tick () AActor *victim = players[i].mo; fixed_t dist; - dist = P_AproxDistance (victim->x - m_Spot->x, victim->y - m_Spot->y); + dist = m_Spot->AproxDistance (victim, true); // Check if in damage radius if (dist < m_DamageRadius && victim->z <= victim->floorz) { @@ -242,8 +242,7 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger { if (quake->m_Spot != NULL) { - fixed_t dist = P_AproxDistance (victim->x - quake->m_Spot->x, - victim->y - quake->m_Spot->y); + fixed_t dist = quake->m_Spot->AproxDistance (victim, true); if (dist < quake->m_TremorRadius) { ++count; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index fbfbbf550..d3994ed84 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -158,7 +158,7 @@ struct FSpotList while (true) { - distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y); + distance = Spots[i]->AproxDistance(x, y); if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break; diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 7ef0b24a1..cf5f03a23 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -11,9 +11,9 @@ static bool CrusaderCheckRange (AActor *self) { - if (P_CheckSight (self, self->target) && self->reactiontime == 0) + if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 70ca805f8..1a0739d36 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -20,7 +20,7 @@ bool InquisitorCheckDistance (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } @@ -85,7 +85,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) speed = self->Speed * 2/3; self->velx += FixedMul (speed, finecosine[an]); self->vely += FixedMul (speed, finesine[an]); - dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); + dist = self->AproxDistance (self->target); dist /= speed; if (dist < 1) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5291101a5..489fb107d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -138,7 +138,7 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun for (actor = sec->thinglist; actor != NULL; actor = actor->snext) { if (actor != soundtarget && (!splash || !(actor->flags4 & MF4_NOSPLASHALERT)) && - (!maxdist || (P_AproxDistance(actor->x - emitter->x, actor->y - emitter->y) <= maxdist))) + (!maxdist || (actor->AproxDistance(emitter) <= maxdist))) { actor->LastHeard = soundtarget; } @@ -231,7 +231,7 @@ bool AActor::CheckMeleeRange () if (!pl) return false; - dist = P_AproxDistance (pl->x - x, pl->y - y); + dist = AproxDistance (pl); if (dist >= meleerange + pl->radius) return false; @@ -275,7 +275,7 @@ bool P_CheckMeleeRange2 (AActor *actor) return false; } mo = actor->target; - dist = P_AproxDistance (mo->x-actor->x, mo->y-actor->y); + dist = mo->AproxDistance (actor); if (dist >= MELEERANGE*2 || dist < MELEERANGE-20*FRACUNIT + mo->radius) { return false; @@ -348,8 +348,7 @@ bool P_CheckMissileRange (AActor *actor) // OPTIMIZE: get this from a global checksight // [RH] What? - dist = P_AproxDistance (actor->x-actor->target->x, - actor->y-actor->target->y) - 64*FRACUNIT; + dist = actor->AproxDistance (actor->target) - 64*FRACUNIT; if (actor->MeleeState == NULL) dist -= 128*FRACUNIT; // no melee attack, so fire more @@ -394,7 +393,7 @@ bool P_HitFriend(AActor * self) if (self->flags&MF_FRIENDLY && self->target != NULL) { angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); - fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y); + fixed_t dist = self->AproxDistance (self->target); P_AimLineAttack (self, angle, dist, &linetarget, 0, true); if (linetarget != NULL && linetarget != self->target) { @@ -450,7 +449,7 @@ bool P_Move (AActor *actor) if ((actor->flags6 & MF6_JUMPDOWN) && target && !(target->IsFriend(actor)) && - P_AproxDistance(actor->x - target->x, actor->y - target->y) < FRACUNIT*144 && + actor->AproxDistance(target) < FRACUNIT*144 && pr_dropoff() < 235) { dropoff = 2; @@ -933,7 +932,7 @@ void P_NewChaseDir(AActor * actor) if (actor->flags3 & MF3_AVOIDMELEE) { bool ismeleeattacker = false; - fixed_t dist = P_AproxDistance(actor->x-target->x, actor->y-target->y); + fixed_t dist = actor->AproxDistance(target); if (target->player == NULL) { ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2); @@ -1151,7 +1150,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams fov = allaround ? 0 : ANGLE_180; } - fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y); + fixed_t dist = lookee->AproxDistance (other); if (maxdist && dist > maxdist) return false; // [KS] too far @@ -1202,8 +1201,7 @@ bool P_LookForMonsters (AActor *actor) { // Not a valid monster continue; } - if (P_AproxDistance (actor->x-mo->x, actor->y-mo->y) - > MONS_LOOK_RANGE) + if (mo->AproxDistance (actor) > MONS_LOOK_RANGE) { // Out of range continue; } @@ -1703,10 +1701,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || player->mo->flags3 & MF3_GHOST) { - if ((P_AproxDistance (player->mo->x - actor->x, - player->mo->y - actor->y) > 2*MELEERANGE) - && P_AproxDistance (player->mo->velx, player->mo->vely) - < 5*FRACUNIT) + if ((player->mo->AproxDistance (actor) > 2*MELEERANGE) + && P_AproxDistance (player->mo->velx, player->mo->vely) < 5*FRACUNIT) { // Player is sneaking - can't detect continue; } @@ -1903,8 +1899,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) } else { - dist = P_AproxDistance (targ->x - self->x, - targ->y - self->y); + dist = self->AproxDistance (targ); // [KS] If the target is too far away, don't respond to the sound. if (maxheardist && dist > maxheardist) @@ -1975,8 +1970,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { if (self->flags & MF_AMBUSH) { - dist = P_AproxDistance (self->target->x - self->x, - self->target->y - self->y); + dist = self->AproxDistance (self->target); if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) && (!minseedist || dist > minseedist) && (!maxseedist || dist < maxseedist)) @@ -2390,7 +2384,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->FastChaseStrafeCount = 0; actor->velx = 0; actor->vely = 0; - fixed_t dist = P_AproxDistance (actor->x - actor->target->x, actor->y - actor->target->y); + fixed_t dist = actor->AproxDistance (actor->target); if (dist < CLASS_BOSS_STRAFE_RANGE) { if (pr_chase() < 100) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7aeb9d115..58b4d2c1a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1075,8 +1075,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)) { - fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y); - fixed_t olddist = P_AproxDistance(thing->x - tm.thing->x, thing->y - tm.thing->y); + fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing); + fixed_t olddist = thing->AproxDistance(tm.thing); if (newdist > olddist) { @@ -1754,7 +1754,7 @@ void P_FakeZMovement(AActor *mo) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { - fixed_t dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); + fixed_t dist = mo->AproxDistance(mo->target); fixed_t delta = (mo->target->z + (mo->height >> 1)) - mo->z; if (delta < 0 && dist < -(delta * 3)) mo->z -= mo->FloatSpeed; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3d0d8e072..3eeb7c71a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1669,8 +1669,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci if (actor->z + actor->height < target->z || target->z + target->height < actor->z) { // Need to seek vertically - dist = P_AproxDistance (target->x - actor->x, target->y - actor->y); - dist = dist / speed; + dist = actor->AproxDistance (target) / speed; if (dist < 1) { dist = 1; @@ -2380,7 +2379,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // float down towards target if too close if (!(mo->flags & (MF_SKULLFLY | MF_INFLOAT))) { - dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); + dist = mo->AproxDistance (mo->target); delta = (mo->target->z + (mo->height>>1)) - mo->z; if (delta < 0 && dist < -(delta*3)) mo->z -= mo->FloatSpeed; @@ -3392,7 +3391,7 @@ void AActor::Tick () if (health > 0 && !players[i].Bot->enemy && player ? !IsTeammate (players[i].mo) : true - && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST + && AproxDistance (players[i].mo) < MAX_MONSTER_TARGET_DIST && P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING)) { //Probably a monster, so go kill it. players[i].Bot->enemy = this; @@ -5788,7 +5787,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); if (th->Speed) dist = dist / th->Speed; if (dist < 1) @@ -5849,7 +5848,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl { an += pr_spawnmissile.Random2() << 20; } - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); speed = GetDefaultSpeed (type); dist /= speed; velz = dist != 0 ? (dest->z - source->z)/dist : speed; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 918d07ed2..b7bc9a7b0 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2225,7 +2225,7 @@ void DPusher::Tick () { int sx = m_X; int sy = m_Y; - int dist = P_AproxDistance (thing->x - sx,thing->y - sy); + int dist = thing->AproxDistance (sx, sy); int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); // If speed <= 0, you're outside the effective radius. You also have diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89299e0fa..864641b0d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -670,7 +670,7 @@ void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) // No target - no jump if (!target) return; - if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + if (self->AproxDistance(target) < dist && (noz || ((self->z > target->z && self->z - (target->z + target->height) < dist) || (self->z <= target->z && target->z - (self->z + self->height) < dist)))) @@ -3342,8 +3342,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (target) { - FVector2 xyvec(target->x - x1, target->y - y1); - fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1); + fixed_t xydist = self->Distance2D(target); + fixed_t distance = P_AproxDistance(xydist, target->z - z1); if (range && !(flags & CLOFF_CHECKPARTIAL)) { @@ -3372,11 +3372,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else if (flags & CLOFF_AIM_VERT_NOOFFSET) { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + offsetheight + target->height / 2); } else { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + target->height / 2); } } else if (flags & CLOFF_ALLOWNULL) @@ -3546,8 +3546,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -3635,8 +3634,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -5950,7 +5948,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) continue; //Make sure it's in range and respect the desire for Z or not. - if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance && + if (ref->AproxDistance(mo) < distance && ((flags & CPXF_NOZ) || ((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) || (ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance)))) From 2c0f64cf9fa06834cb10522e7399b950de486e19 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 20:46:26 +0100 Subject: [PATCH 283/335] - refactoring of R_PointToAngle2 when used to calculate direction between two actors. --- src/actor.h | 22 ++++++++++++++++- src/b_func.cpp | 11 ++++----- src/b_move.cpp | 2 +- src/b_think.cpp | 8 +++---- src/fragglescript/t_func.cpp | 4 ++-- src/g_doom/a_doomweaps.cpp | 8 ++----- src/g_doom/a_revenant.cpp | 2 +- src/g_doom/a_scriptedmarine.cpp | 5 ++-- src/g_heretic/a_chicken.cpp | 6 ++--- src/g_heretic/a_hereticweaps.cpp | 12 ++++------ src/g_hexen/a_blastradius.cpp | 4 ++-- src/g_hexen/a_clericholy.cpp | 3 +-- src/g_hexen/a_clericstaff.cpp | 4 ++-- src/g_hexen/a_dragon.cpp | 12 ++++------ src/g_hexen/a_fighterplayer.cpp | 2 +- src/g_hexen/a_firedemon.cpp | 2 +- src/g_hexen/a_flies.cpp | 2 +- src/g_hexen/a_hexenspecialdecs.cpp | 3 +-- src/g_hexen/a_korax.cpp | 2 +- src/g_hexen/a_magelightning.cpp | 2 +- src/g_raven/a_minotaur.cpp | 2 +- src/g_shared/sbar_mugshot.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 5 +--- src/p_conversation.cpp | 2 +- src/p_enemy.cpp | 18 +++++--------- src/p_interaction.cpp | 2 +- src/p_map.cpp | 6 ++--- src/p_mobj.cpp | 11 ++++----- src/p_spec.cpp | 2 +- src/p_things.cpp | 3 ++- src/thingdef/thingdef_codeptr.cpp | 38 ++++++++---------------------- 31 files changed, 92 insertions(+), 115 deletions(-) diff --git a/src/actor.h b/src/actor.h index 0cd87ec52..114dd1179 100644 --- a/src/actor.h +++ b/src/actor.h @@ -612,7 +612,7 @@ extern FDropItemPtrArray DropItemList; void FreeDropItemChain(FDropItem *chain); int StoreDropItemChain(FDropItem *chain); fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... - +angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h // Map Object definition. @@ -889,6 +889,26 @@ public: return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); } + angle_t AngleTo(AActor *other, bool absolute = false) const + { + return R_PointToAngle2(x, y, other->x, other->y); + } + + angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const + { + return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs); + } + + fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return R_PointToAngle2(x, y, otherx, othery); + } + + fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) + { + return R_PointToAngle2(myx, myy, other->x, other->y); + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; diff --git a/src/b_func.cpp b/src/b_func.cpp index 87b1e5416..9594d29d8 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -123,7 +123,7 @@ bool DBot::Check_LOS (AActor *to, angle_t vangle) if (vangle == 0) return false; //Looker seems to be blind. - return absangle(R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2; + return absangle(player->mo->AngleTo(to) - player->mo->angle) <= vangle/2; } //------------------------------------- @@ -220,14 +220,14 @@ shootmissile: dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); - angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); + angle = player->mo->AngleTo(bglobal.body1); if (Check_LOS (enemy, SHOOTFOV)) no_fire = false; } else { //Other weapons, mostly instant hit stuff. - angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); aiming_penalty = 0; if (enemy->flags & MF_SHADOW) aiming_penalty += (pr_botdofire()%25)+10; @@ -263,7 +263,6 @@ shootmissile: cmd->ucmd.buttons |= BT_ATTACK; } //Prevents bot from jerking, when firing automatic things with low skill. - //player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); } bool FCajunMaster::IsLeader (player_t *player) @@ -518,7 +517,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y); + ang = actor->AngleTo(bglobal.body1); return ang; } } @@ -528,7 +527,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + ang = player->mo->AngleTo(enemy); return ang; } } diff --git a/src/b_move.cpp b/src/b_move.cpp index c608c5d03..5cacd5664 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -35,7 +35,7 @@ void DBot::Roam (ticcmd_t *cmd) if (Reachable(dest)) { // Straight towards it. - angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y); + angle = player->mo->AngleTo(dest); } else if (player->mo->movedir < 8) // turn towards movement direction if not there yet { diff --git a/src/b_think.cpp b/src/b_think.cpp index 73c5066ab..ced5b4b4e 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -99,7 +99,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) if (missile && (player->mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y); + angle = player->mo->AngleTo(missile); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. @@ -165,7 +165,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) sleft = !sleft; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); if (player->ReadyWeapon == NULL || player->mo->AproxDistance(enemy) > @@ -206,7 +206,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) goto roam; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); + angle = player->mo->AngleTo(mate); matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) @@ -241,7 +241,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) (pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. else //hide while t_fight, but keep view at enemy. - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); } //Just a monster, so kill it. else dest = enemy; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index fdf904764..ceabc9ce5 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -3145,8 +3145,8 @@ void FParser::SF_MoveCamera(void) } // set step variables based on distance and speed - mobjangle = R_PointToAngle2(cam->x, cam->y, target->x, target->y); - xydist = R_PointToDist2(target->x - cam->x, target->y - cam->y); + mobjangle = cam->AngleTo(target); + xydist = cam->Distance2D(target); xstep = FixedMul(finecosine[mobjangle >> ANGLETOFINESHIFT], movespeed); ystep = FixedMul(finesine[mobjangle >> ANGLETOFINESHIFT], movespeed); diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 899f1f7d5..79dd6253f 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -59,10 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -218,8 +215,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // turn to face target if (!(Flags & SF_NOTURN)) { - angle = R_PointToAngle2(self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90 / 20)) diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 90c6e0a51..06fdfa6aa 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return; // change angle - exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); + exact = self->AngleTo(dest); if (exact != self->angle) { diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index be39b545b..6e75d80e6 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -276,7 +276,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target - angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90/20)) @@ -326,7 +326,8 @@ static void MarinePunch(AActor *self, int damagemul) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); + } } diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 082774a3d..f4ad4c211 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -178,8 +178,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; @@ -211,8 +210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index afc4f6007..711bbd960 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -90,8 +90,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) { //S_StartSound(player->mo, sfx_stfhit); // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -307,8 +306,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); } // turn to face target - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle-self->angle > ANG180) { if ((int)(angle-self->angle) < -ANG90/20) @@ -648,8 +646,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) } else { // Seek - angle = R_PointToAngle2(self->x, self->y, - target->x, target->y); + self->angle = self->AngleTo(target); newAngle = true; } } @@ -662,8 +659,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) if (linetarget && self->target != linetarget) { self->tracer = linetarget; - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); newAngle = true; break; } diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index 53ce08b50..c7fb17fef 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -33,13 +33,13 @@ void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor * Owner return; } - angle = R_PointToAngle2 (Owner->x, Owner->y, victim->x, victim->y); + angle = Owner->AngleTo(victim); angle >>= ANGLETOFINESHIFT; victim->velx = FixedMul (speed, finecosine[angle]); victim->vely = FixedMul (speed, finesine[angle]); // Spawn blast puff - ang = R_PointToAngle2 (victim->x, victim->y, Owner->x, Owner->y); + ang = victim->AngleTo(Owner); ang >>= ANGLETOFINESHIFT; x = victim->x + FixedMul (victim->radius+FRACUNIT, finecosine[ang]); y = victim->y + FixedMul (victim->radius+FRACUNIT, finesine[ang]); diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 73ffeac88..39fee109d 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -262,8 +262,7 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist) child = actor->tracer; if (child) { - an = R_PointToAngle2(actor->x, actor->y, child->x, - child->y)>>ANGLETOFINESHIFT; + an = actor->AngleTo(child) >> ANGLETOFINESHIFT; oldDistance = child->AproxDistance (actor); if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]), actor->y+FixedMul(dist, finesine[an]), true)) diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index b397fc12b..eeda968fa 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) && (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE)))) { @@ -103,7 +103,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) { newLife = player->health+(damage>>4); diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 5b18c0d57..d33e7b07b 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -73,8 +73,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { // attack the destination mobj if it's attackable AActor *oldTarget; - if (absangle(actor->angle-R_PointToAngle2(actor->x, actor->y, - target->x, target->y)) < ANGLE_45/2) + if (absangle(actor->angle - actor->AngleTo(target)) < ANGLE_45/2) { oldTarget = actor->target; actor->target = target; @@ -99,8 +98,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { AActor *bestActor = NULL; bestAngle = ANGLE_MAX; - angleToTarget = R_PointToAngle2(actor->x, actor->y, - actor->target->x, actor->target->y); + angleToTarget = actor->AngleTo(actor->target); for (i = 0; i < 5; i++) { if (!target->args[i]) @@ -113,8 +111,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { continue; } - angleToSpot = R_PointToAngle2(actor->x, actor->y, - mo->x, mo->y); + angleToSpot = actor->AngleTo(mo); if (absangle(angleToSpot-angleToTarget) < bestAngle) { bestAngle = absangle(angleToSpot-angleToTarget); @@ -190,8 +187,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) self->target = NULL; return; } - angle = R_PointToAngle2(self->x, self->y, self->target->x, - self->target->y); + angle = self->AngleTo(self->target); if (absangle(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange()) { int damage = pr_dragonflight.HitDice (8); diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 5df183901..82cb8bd05 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -30,7 +30,7 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) angle_t angle; int difference; - angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + angle = pmo->AngleTo(linetarget); difference = (int)angle - (int)pmo->angle; if (abs(difference) > MAX_ANGLE_ADJUST) { diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index b1cfafc0c..c003dc21d 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -163,7 +163,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { if (pr_firedemonchase() < 30) { - ang = R_PointToAngle2 (self->x, self->y, target->x, target->y); + ang = self->AngleTo(target); if (pr_firedemonchase() < 128) ang += ANGLE_90; else diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp index 3c677d5cb..683cbebe1 100644 --- a/src/g_hexen/a_flies.cpp +++ b/src/g_hexen/a_flies.cpp @@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) return; } - angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y); + angle_t ang = self->AngleTo(targ); self->angle = ang; self->args[0]++; ang >>= ANGLETOFINESHIFT; diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 9d0c098fe..ad10a464c 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -109,8 +109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) if (playeringame[i]) { AActor *pmo = players[i].mo; - if (P_CheckSight (self, pmo) && (absangle(R_PointToAngle2 (pmo->x, - pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45)) + if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); return; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index ca849dd97..a941f1a65 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -485,7 +485,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); th->target = source; // Originator - an = R_PointToAngle2(x, y, dest->x, dest->y); + an = source->AngleXYTo(x, y, dest); if (dest->flags & MF_SHADOW) { // Invisible target an += pr_kmissile.Random2()<<21; diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 9953cf1d0..a13e3a274 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -190,7 +190,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) } else { - self->angle = R_PointToAngle2(self->x, self->y, target->x, target->y); + self->angle = self->AngleTo(target); self->velx = 0; self->vely = 0; P_ThrustMobj (self, self->angle, self->Speed>>1); diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index c0095226e..c2348a9e3 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -390,7 +390,7 @@ void P_MinotaurSlam (AActor *source, AActor *target) fixed_t thrust; int damage; - angle = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle = source->AngleTo(target); angle >>= ANGLETOFINESHIFT; thrust = 16*FRACUNIT+(pr_minotaurslam()<<10); target->velx += FixedMul (thrust, finecosine[angle]); diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index b8f419ef0..ea1c8528e 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -366,7 +366,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) if (player->mo != NULL) { // The next 12 lines are from the Doom statusbar code. - badguyangle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); + badguyangle = player->mo->AngleTo(player->attacker); if (badguyangle > player->mo->angle) { // whether right or left diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index a41058492..f5d4a3576 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -118,10 +118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) S_Sound (self, CHAN_WEAPON, linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); self->flags |= MF_JUSTATTACKED; P_DaggerAlert (self, linetarget); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 85edc53ab..db5fd400c 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1117,7 +1117,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang if (facetalker) { A_FaceTarget (npc); - pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y); + pc->angle = pc->AngleTo(npc); } if ((npc->flags & MF_FRIENDLY) || (npc->flags4 & MF4_NOHATEPLAYERS)) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 489fb107d..7b7e27b2e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -392,7 +392,7 @@ bool P_HitFriend(AActor * self) if (self->flags&MF_FRIENDLY && self->target != NULL) { - angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); + angle_t angle = self->AngleTo(self->target); fixed_t dist = self->AproxDistance (self->target); P_AimLineAttack (self, angle, dist, &linetarget, 0, true); if (linetarget != NULL && linetarget != self->target) @@ -1160,7 +1160,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams if (fov && fov < ANGLE_MAX) { - angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle; + angle_t an = lookee->AngleTo(other) - lookee->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -2389,7 +2389,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi { if (pr_chase() < 100) { - angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + angle_t ang = actor->AngleTo(actor->target); if (pr_chase() < 128) ang += ANGLE_90; else ang -= ANGLE_90; actor->velx = 13 * finecosine[ang>>ANGLETOFINESHIFT]; @@ -2743,7 +2743,7 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a self->flags &= ~MF_AMBUSH; - angle_t other_angle = R_PointToAngle2 (self->x, self->y, other->x, other->y); + angle_t other_angle = self->AngleTo(other); // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. // It also means that there is no need to check for going past the other. @@ -2916,10 +2916,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->flags &= ~MF_AMBUSH; - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + self->angle = self->AngleTo(self->target); self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target); if (linetarget == NULL) @@ -2932,10 +2929,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) } // Let the aim trail behind the player - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE)) { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b2e27adc8..240a77378 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1164,7 +1164,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } else { - ang = R_PointToAngle2 (origin->x, origin->y, target->x, target->y); + ang = origin->AngleTo(target); } // Calculate this as float to avoid overflows so that the diff --git a/src/p_map.cpp b/src/p_map.cpp index 58b4d2c1a..3381f763f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3066,7 +3066,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) if (!ontop) { fixed_t speed; - angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8); + angle_t angle = BlockingMobj->AngleTo(mo) + ANGLE_1*((pr_bounce() % 16) - 8); speed = P_AproxDistance(mo->velx, mo->vely); speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent mo->angle = angle; @@ -4084,7 +4084,7 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) pitch = 0; } P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2, - target, R_PointToAngle2(missile->x, missile->y, target->x, target->y), + target, missile->AngleTo(target), pitch); } @@ -4853,7 +4853,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { velz *= 0.8f; } - angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; + angle_t ang = bombspot->AngleTo(thing) >> ANGLETOFINESHIFT; thing->velx += fixed_t(finecosine[ang] * thrust); thing->vely += fixed_t(finesine[ang] * thrust); if (!(flags & RADF_NODAMAGE)) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3eeb7c71a..750cc18fb 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1556,7 +1556,7 @@ int P_FaceMobj (AActor *source, AActor *target, angle_t *delta) angle_t angle2; angle1 = source->angle; - angle2 = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle2 = source->AngleTo(target); if (angle2 > angle1) { diff = angle2 - angle1; @@ -2019,7 +2019,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) // Don't change the angle if there's THRUREFLECT on the monster. if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); + angle = BlockingMobj->AngleTo(mo); bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); // Change angle for deflection/reflection @@ -3088,8 +3088,7 @@ bool AActor::IsOkayToAttack (AActor *link) // to only allow the check to succeed if the enemy was in a ~84� FOV of the player if (flags3 & MF3_SCREENSEEKER) { - angle_t angle = R_PointToAngle2(Friend->x, - Friend->y, link->x, link->y) - Friend->angle; + angle_t angle = Friend->AngleTo(link) - Friend->angle; angle >>= 24; if (angle>226 || angle<30) { @@ -5035,7 +5034,7 @@ AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t puff->target = source; - if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y); + if (source != NULL) puff->angle = puff->AngleTo(source); // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark @@ -5782,7 +5781,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const P_PlaySpawnSound(th, source); th->target = owner; // record missile's originator - th->angle = an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + th->angle = an = source->AngleTo(dest); an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index b7bc9a7b0..698cf4f72 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2233,7 +2233,7 @@ void DPusher::Tick () if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) { - angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); + angle_t pushangle = thing->AngleTo(sx, sy); if (m_Source->GetClass()->TypeName == NAME_PointPusher) pushangle += ANG180; // away pushangle >>= ANGLETOFINESHIFT; diff --git a/src/p_things.cpp b/src/p_things.cpp index 7e38a3c68..631f1be5e 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -304,7 +304,8 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam } else { -nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y); +nolead: + mobj->angle = mobj->AngleTo(targ); aim.Resize (fspeed); mobj->velx = fixed_t(aim[0]); mobj->vely = fixed_t(aim[1]); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 864641b0d..b6575ee19 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1487,10 +1487,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (!(flags & CPF_NOTURN)) { // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; @@ -1614,10 +1611,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim) { - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + self->angle = self->AngleTo(self->target); } self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL); if (linetarget == NULL && aim) @@ -1631,9 +1625,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // Let the aim trail behind the player if (aim) { - saved_angle = self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + saved_angle = self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (aim == CRF_AIMDIRECT) { @@ -1642,9 +1634,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) self->x += Spawnofs_XY * finecosine[self->angle]; self->y += Spawnofs_XY * finesine[self->angle]; Spawnofs_XY = 0; - self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->angle = self->AngleTo(self->target,- self->target->velx * 3, -self->target->vely * 3); } if (self->target->flags & MF_SHADOW) @@ -3357,7 +3347,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { ang = self->angle; } - else ang = R_PointToAngle2 (x1, y1, target->x, target->y); + else ang = self->AngleTo (target); angle += ang; @@ -3576,11 +3566,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (viewport->x, - viewport->y, - target->x, - target->y) - - viewport->angle; + an = viewport->AngleTo(target) - viewport->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -3654,11 +3640,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (target->x, - target->y, - self->x, - self->y) - - target->angle; + an = target->AngleTo(self) - target->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -4588,7 +4570,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // Target can dodge if it can see enemy - angle_t angle = R_PointToAngle2(self->target->x, self->target->y, self->x, self->y) - self->target->angle; + angle_t angle = self->target->AngleTo(self) - self->target->angle; angle >>= 24; bool dodge = (P_CheckSight(self->target, self) && (angle>226 || angle<30)); @@ -4627,7 +4609,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) dx = self->target->x; dy = self->target->y; dz = self->target->z + (self->target->height>>1); - angle = R_PointToAngle2(dx, dy, self->x, self->y); + angle = self->target->AngleTo(self); dx += FixedMul(self->target->radius, finecosine[angle>>ANGLETOFINESHIFT]); dy += FixedMul(self->target->radius, finesine[angle>>ANGLETOFINESHIFT]); @@ -4662,7 +4644,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if (spawnblood) { P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target); - P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0); + P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0); } } } From 918a2ed56231ecd7662a6fb46baea3e559877d10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 22:26:08 +0100 Subject: [PATCH 284/335] -fixed: Eternity-style skyboxes must check if some portal copy definitions have been set for them. --- src/g_shared/a_skies.cpp | 55 +++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 54661ea14..1915a260a 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -37,6 +37,7 @@ #include "p_local.h" #include "p_lnspec.h" #include "farchive.h" +#include "r_sky.h" // arg0 = Visibility*4 for this skybox @@ -87,6 +88,24 @@ void ASkyViewpoint::Destroy () class ASkyCamCompat : public ASkyViewpoint { DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint) + + // skyboxify all tagged sectors + // This involves changing their texture to the sky flat, because while + // EE works with any texture for its skybox portals, ZDoom doesn't. + void SkyboxifySector(sector_t *sector, int plane) + { + // plane: 0=floor, 1=ceiling, 2=both + if (plane == 1 || plane == 2) + { + sector->CeilingSkyBox = this; + sector->SetTexture(sector_t::ceiling, skyflatnum, false); + } + if (plane == 0 || plane == 2) + { + sector->FloorSkyBox = this; + sector->SetTexture(sector_t::floor, skyflatnum, false); + } + } public: void BeginPlay (); }; @@ -116,23 +135,35 @@ void ASkyCamCompat::BeginPlay () // Then, change the alpha alpha = refline->args[4]; - // Finally, skyboxify all tagged sectors - // This involves changing their texture to the sky flat, because while - // EE works with any texture for its skybox portals, ZDoom doesn't. FSectorTagIterator it(skybox_id); int secnum; while ((secnum = it.Next()) >= 0) { - // plane: 0=floor, 1=ceiling, 2=both - if (refline->args[2] == 1 || refline->args[2] == 2) + SkyboxifySector(§ors[secnum], refline->args[2]); + } + // and finally, check for portal copy linedefs + for (int j=0;jargs[2] || lines[j].args[2] == 3) && + lines[j].args[3] == skybox_id) { - sectors[secnum].CeilingSkyBox = this; - sectors[secnum].SetTexture(sector_t::ceiling, skyflatnum, false); - } - if (refline->args[2] == 0 || refline->args[2] == 2) - { - sectors[secnum].FloorSkyBox = this; - sectors[secnum].SetTexture(sector_t::floor, skyflatnum, false); + if (lines[j].args[0] == 0) + { + SkyboxifySector(lines[j].frontsector, refline->args[2]); + } + else + { + FSectorTagIterator itr(lines[j].args[0]); + int s; + while ((s = itr.Next()) >= 0) + { + SkyboxifySector(§ors[s], refline->args[2]); + } + } } } } From 4f0046105dd615eb88b1eab9f97b03acb5104b1f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 21:09:16 -0600 Subject: [PATCH 285/335] Change texture atlas display to show allocated rectangles --- src/win32/fb_d3d9.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 1641df365..474183086 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1833,8 +1833,8 @@ void D3DFB::DrawPackedTextures(int packnum) { D3DCOLOR empty_colors[8] = { - 0xFFFF9999, 0xFF99FF99, 0xFF9999FF, 0xFFFFFF99, - 0xFFFF99FF, 0xFF99FFFF, 0xFFFFCC99, 0xFF99CCFF + 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, + 0x80FF00FF, 0x8000FFFF, 0x80FF8000, 0x800080FF }; Atlas *pack; int x = 8, y = 8; @@ -1869,7 +1869,14 @@ void D3DFB::DrawPackedTextures(int packnum) } AddColorOnlyRect(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); - AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); + int back = 0; + for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next) + { + AddColorOnlyQuad(x + box->Area.left, y + box->Area.top, + box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, empty_colors[back]); + back = (back + 1) & 7; + } +// AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); CheckQuadBatch(); From 670058fa3c1afb9afababec32afad204dbb7216f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 21:54:28 -0600 Subject: [PATCH 286/335] Switch to the bottom-left picker for the Skyline Bin Packer --- src/SkylineBinPack.cpp | 69 +++++++++++++++++++++++++++++++++++++++++- src/SkylineBinPack.h | 3 ++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp index 33f862043..4e9de153e 100644 --- a/src/SkylineBinPack.cpp +++ b/src/SkylineBinPack.cpp @@ -119,7 +119,7 @@ Rect SkylineBinPack::Insert(int width, int height) return newNode; } - return InsertMinWaste(width, height); + return InsertBottomLeft(width, height); } bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const @@ -254,6 +254,73 @@ void SkylineBinPack::MergeSkylines() } } +Rect SkylineBinPack::InsertBottomLeft(int width, int height) +{ + int bestHeight; + int bestWidth; + int bestIndex; + Rect newNode = FindPositionForNewNodeBottomLeft(width, height, bestHeight, bestWidth, bestIndex); + + if (bestIndex != -1) + { + assert(disjointRects.Disjoint(newNode)); + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(Rect)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestIndex = -1; + // Used to break ties if there are nodes at the same level. Then pick the narrowest one. + bestWidth = INT_MAX; + Rect newNode = { 0, 0, 0, 0 }; + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + if (RectangleFits(i, width, height, y)) + { + if (y + height < bestHeight || (y + height == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + height; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; + assert(disjointRects.Disjoint(newNode)); + } + } +/* if (RectangleFits(i, height, width, y)) + { + if (y + width < bestHeight || (y + width == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + width; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + } +*/ } + + return newNode; +} + Rect SkylineBinPack::InsertMinWaste(int width, int height) { int bestHeight; diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h index f93ddd29d..937c88de6 100644 --- a/src/SkylineBinPack.h +++ b/src/SkylineBinPack.h @@ -72,7 +72,10 @@ private: bool useWasteMap; GuillotineBinPack wasteMap; + Rect InsertBottomLeft(int width, int height); Rect InsertMinWaste(int width, int height); + + Rect FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const; Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const; bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const; From aaac5ac7a122d7d0cae223964b0624ae3af3c02e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 22:01:29 -0600 Subject: [PATCH 287/335] Use not so brilliant backgrounds for allocated atlas backgrounds --- src/win32/fb_d3d9.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 474183086..bfb618b51 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1833,8 +1833,8 @@ void D3DFB::DrawPackedTextures(int packnum) { D3DCOLOR empty_colors[8] = { - 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, - 0x80FF00FF, 0x8000FFFF, 0x80FF8000, 0x800080FF + 0x50FF0000, 0x5000FF00, 0x500000FF, 0x50FFFF00, + 0x50FF00FF, 0x5000FFFF, 0x50FF8000, 0x500080FF }; Atlas *pack; int x = 8, y = 8; From 42e9a6a711816bb2fce51166220cb7d8bc19f063 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 22:14:35 -0600 Subject: [PATCH 288/335] Make atlas size a macro definition and default it to 512x512 (was 256x256) --- src/win32/fb_d3d9.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index bfb618b51..4e3a14c18 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -85,6 +85,10 @@ // The number of quads we can batch together. #define MAX_QUAD_BATCH (NUM_INDEXES / 6) +// The default size for a texture atlas. +#define DEF_ATLAS_WIDTH 512 +#define DEF_ATLAS_HEIGHT 512 + // TYPES ------------------------------------------------------------------- IMPLEMENT_CLASS(D3DFB) @@ -1872,8 +1876,11 @@ void D3DFB::DrawPackedTextures(int packnum) int back = 0; for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next) { - AddColorOnlyQuad(x + box->Area.left, y + box->Area.top, - box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, empty_colors[back]); + AddColorOnlyQuad( + x + box->Area.left * 256 / pack->Width, + y + box->Area.top * 256 / pack->Height, + (box->Area.right - box->Area.left) * 256 / pack->Width, + (box->Area.bottom - box->Area.top) * 256 / pack->Height, empty_colors[back]); back = (back + 1) & 7; } // AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); @@ -1980,8 +1987,8 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D Rect box; bool padded; - // check for 254 to account for padding - if (w > 254 || h > 254 || wrapping) + // The - 2 to account for padding + if (w > 256 - 2 || h > 256 - 2 || wrapping) { // Create a new texture atlas. pack = new Atlas(this, w, h, format); pack->OneUse = true; @@ -2006,7 +2013,7 @@ D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3D } if (pack == NULL) { // Create a new texture atlas. - pack = new Atlas(this, 256, 256, format); + pack = new Atlas(this, DEF_ATLAS_WIDTH, DEF_ATLAS_HEIGHT, format); box = pack->Packer.Insert(w, h); } padded = true; From 7115590c1d85e54f5edda4eca04466ad23e6b861 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 11 Jan 2016 15:29:44 +0100 Subject: [PATCH 289/335] - moved setup code for Eternity-style skyboxes to p_spec.cpp and consolidated most of it with nearly identical parts of the stacked sector portal setup code. --- src/g_shared/a_sharedglobal.h | 14 +++++ src/g_shared/a_skies.cpp | 87 --------------------------- src/p_spec.cpp | 108 +++++++++++++++++++++++----------- 3 files changed, 89 insertions(+), 120 deletions(-) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 2688249ea..8a1c31307 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -100,6 +100,20 @@ public: TObjPtr Mate; }; +// For an EE compatible linedef based definition. +class ASkyCamCompat : public ASkyViewpoint +{ + DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint) + +public: + void BeginPlay () + { + // Do not call the SkyViewpoint's super method because it would trash our setup + AActor::BeginPlay(); + } +}; + + class AStackPoint : public ASkyViewpoint { DECLARE_CLASS (AStackPoint, ASkyViewpoint) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 1915a260a..ef5623746 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -83,95 +83,8 @@ void ASkyViewpoint::Destroy () Super::Destroy(); } -// For an RR compatible linedef based definition. This searches the viewpoint's sector -// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. -class ASkyCamCompat : public ASkyViewpoint -{ - DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint) - - // skyboxify all tagged sectors - // This involves changing their texture to the sky flat, because while - // EE works with any texture for its skybox portals, ZDoom doesn't. - void SkyboxifySector(sector_t *sector, int plane) - { - // plane: 0=floor, 1=ceiling, 2=both - if (plane == 1 || plane == 2) - { - sector->CeilingSkyBox = this; - sector->SetTexture(sector_t::ceiling, skyflatnum, false); - } - if (plane == 0 || plane == 2) - { - sector->FloorSkyBox = this; - sector->SetTexture(sector_t::floor, skyflatnum, false); - } - } -public: - void BeginPlay (); -}; - IMPLEMENT_CLASS (ASkyCamCompat) -extern FTextureID skyflatnum; - -void ASkyCamCompat::BeginPlay () -{ - if (Sector == NULL) - { - Printf("Sector not initialized for SkyCamCompat\n"); - Sector = P_PointInSector(x, y); - } - if (Sector) - { - line_t * refline = NULL; - for (short i = 0; i < Sector->linecount; i++) - { - refline = Sector->lines[i]; - if (refline->special == Sector_SetPortal && refline->args[1] == 2) - { - // We found the setup linedef for this skybox, so let's use it for our init. - int skybox_id = refline->args[0]; - - // Then, change the alpha - alpha = refline->args[4]; - - FSectorTagIterator it(skybox_id); - int secnum; - while ((secnum = it.Next()) >= 0) - { - SkyboxifySector(§ors[secnum], refline->args[2]); - } - // and finally, check for portal copy linedefs - for (int j=0;jargs[2] || lines[j].args[2] == 3) && - lines[j].args[3] == skybox_id) - { - if (lines[j].args[0] == 0) - { - SkyboxifySector(lines[j].frontsector, refline->args[2]); - } - else - { - FSectorTagIterator itr(lines[j].args[0]); - int s; - while ((s = itr.Next()) >= 0) - { - SkyboxifySector(§ors[s], refline->args[2]); - } - } - } - } - } - } - } - // Do not call the SkyViewpoint's super method because it would trash our setup - AActor::BeginPlay(); -} //--------------------------------------------------------------------------- diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 698cf4f72..08a43fe2a 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -62,6 +62,7 @@ #include "farchive.h" #include "a_keys.h" #include "c_dispatch.h" +#include "r_sky.h" // State. #include "r_state.h" @@ -71,7 +72,6 @@ #include "r_data/r_interpolate.h" static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); -void P_SetupPortals(); EXTERN_CVAR(Bool, cl_predict_specials) @@ -986,7 +986,7 @@ void P_SetupPortals() } } -inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha) +static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha) { // plane: 0=floor, 1=ceiling, 2=both if (plane > 0) @@ -996,6 +996,8 @@ inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t sector->CeilingSkyBox = portal; if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) sector->SetAlpha(sector_t::ceiling, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum); } } if (plane == 2 || plane == 0) @@ -1006,6 +1008,42 @@ inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t } if (sector->GetAlpha(sector_t::floor) == OPAQUE) sector->SetAlpha(sector_t::floor, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum); + } +} + +static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines) +{ + int s; + FSectorTagIterator itr(sectortag); + while ((s = itr.Next()) >= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + + for (int j=0;j= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + } + } } } @@ -1039,42 +1077,39 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) reference->flags |= MF_JUSTATTACKED; anchor->flags |= MF_JUSTATTACKED; - int s; - FSectorTagIterator itr(sectortag); - while ((s = itr.Next()) >= 0) - { - SetPortal(§ors[s], plane, reference, alpha); - } - - for (int j=0;j= 0) - { - SetPortal(§ors[s], plane, reference, alpha); - } - } - } - } - + CopyPortal(sectortag, plane, reference, alpha, false); return; } } } +// This searches the viewpoint's sector +// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. +void P_SpawnSkybox(ASkyViewpoint *origin) +{ + sector_t *Sector = origin->Sector; + if (Sector == NULL) + { + Printf("Sector not initialized for SkyCamCompat\n"); + origin->Sector = Sector = P_PointInSector(origin->x, origin->y); + } + if (Sector) + { + line_t * refline = NULL; + for (short i = 0; i < Sector->linecount; i++) + { + refline = Sector->lines[i]; + if (refline->special == Sector_SetPortal && refline->args[1] == 2) + { + // We found the setup linedef for this skybox, so let's use it for our init. + CopyPortal(refline->args[0], refline->args[2], origin, 0, true); + return; + } + } + } +} + + // // P_SetSectorDamage @@ -1327,6 +1362,13 @@ void P_SpawnSpecials (void) P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + TThinkerIterator it2; + ASkyCamCompat *pt2; + while ((pt2 = it2.Next())) + { + P_SpawnSkybox(pt2); + } + for (i = 0; i < numlines; i++) { switch (lines[i].special) From 7843ece01a896c03bd947f7e612632e6379ea6cb Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 11 Jan 2016 15:08:38 -0600 Subject: [PATCH 290/335] Fixed: Friendly fire damage didn't take LAXTELEFRAGDMG into account. --- src/p_interaction.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 240a77378..5534fb14a 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1045,7 +1045,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, return -1; } - if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with NOTELEFRAGPIERCE or it may not guarantee its effect. + if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. { if (player && damage > 1) { @@ -1221,7 +1221,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, ((player && player != source->player) || (!player && target != source)) && target->IsTeammate (source)) { - if (rawdamage < TELEFRAG_DAMAGE) //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. + //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. + if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG)) { // Still allow telefragging :-( damage = (int)((float)damage * level.teamdamage); if (damage < 0) From cd9e18a72b0718f41d168d30b0ca03efddd36989 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 11 Jan 2016 23:44:13 +0100 Subject: [PATCH 291/335] - fixed: operator<< (FArchive &arc, secspecial_t &p) erroneously read the old special in the compatibility handler as a short, but it must be read as an int. - bumped savegame version to bring it in line with a GZDoom exclusive change. --- src/p_sectors.cpp | 2 +- src/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 5a60933ba..6c5c08a56 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -883,7 +883,7 @@ FArchive &operator<< (FArchive &arc, secspecial_t &p) { if (SaveVersion < 4529) { - short special; + int special; arc << special; sector_t sec; P_InitSectorSpecial(&sec, special, true); diff --git a/src/version.h b/src/version.h index 6a0eb9c4b..b8c4facb0 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4530 +#define SAVEVER 4531 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From 61e48013dcd922d51a61838c04a0c5ed2b307661 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 11 Jan 2016 23:46:12 +0100 Subject: [PATCH 292/335] - fixed a warning in WildMidi code. --- src/wildmidi/wildmidi_lib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 0a527ec2a..20857da12 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -573,7 +573,7 @@ static inline int wm_isdigit(int c) { #define TOKEN_CNT_INC 8 static char** WM_LC_Tokenize_Line(char *line_data) { - int line_length = strlen(line_data); + int line_length = (int)strlen(line_data); int token_data_length = 0; int line_ofs = 0; int token_start = 0; From 56f7ace9be160fbebf61e495c7cf6d1b7aaf8992 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 17:01:29 -0600 Subject: [PATCH 293/335] include in the bin packers to make GCC happy --- src/GuillotineBinPack.cpp | 1 + src/SkylineBinPack.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/GuillotineBinPack.cpp b/src/GuillotineBinPack.cpp index 2131ed5db..5efbbf8a1 100644 --- a/src/GuillotineBinPack.cpp +++ b/src/GuillotineBinPack.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "templates.h" #include "GuillotineBinPack.h" diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp index 4e9de153e..cb0be54e1 100644 --- a/src/SkylineBinPack.cpp +++ b/src/SkylineBinPack.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "templates.h" #include "SkylineBinPack.h" From a74d3524906506f6cd7db85d4866c7e937b711f2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 17:31:23 -0600 Subject: [PATCH 294/335] Update gus_pat.cpp's envelope fudging to current git version --- src/wildmidi/common.h | 40 ++++++----- src/wildmidi/gus_pat.cpp | 148 +++++++++++++++++++++++++++++++-------- 2 files changed, 138 insertions(+), 50 deletions(-) diff --git a/src/wildmidi/common.h b/src/wildmidi/common.h index 44e90efdd..efe08dd25 100644 --- a/src/wildmidi/common.h +++ b/src/wildmidi/common.h @@ -27,14 +27,14 @@ #ifndef __COMMON_H #define __COMMON_H -#define SAMPLE_16BIT 0x01 -#define SAMPLE_UNSIGNED 0x02 -#define SAMPLE_LOOP 0x04 -#define SAMPLE_PINGPONG 0x08 -#define SAMPLE_REVERSE 0x10 -#define SAMPLE_SUSTAIN 0x20 -#define SAMPLE_ENVELOPE 0x40 -#define SAMPLE_CLAMPED 0x80 +#define SAMPLE_16BIT 0x01 +#define SAMPLE_UNSIGNED 0x02 +#define SAMPLE_LOOP 0x04 +#define SAMPLE_PINGPONG 0x08 +#define SAMPLE_REVERSE 0x10 +#define SAMPLE_SUSTAIN 0x20 +#define SAMPLE_ENVELOPE 0x40 +#define SAMPLE_CLAMPED 0x80 #ifdef DEBUG_SAMPLES #define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) @@ -45,21 +45,23 @@ extern unsigned short int _WM_SampleRate; struct _sample { - unsigned long int data_length; - unsigned long int loop_start; - unsigned long int loop_end; - unsigned long int loop_size; + unsigned int data_length; + unsigned int loop_start; + unsigned int loop_end; + unsigned int loop_size; unsigned char loop_fraction; - unsigned short int rate; - unsigned long int freq_low; - unsigned long int freq_high; - unsigned long int freq_root; + unsigned short rate; + unsigned int freq_low; + unsigned int freq_high; + unsigned int freq_root; unsigned char modes; - signed long int env_rate[7]; - signed long int env_target[7]; - unsigned long int inc_div; + signed int env_rate[7]; + signed int env_target[7]; + unsigned int inc_div; signed short *data; struct _sample *next; + + unsigned int note_off_decay; }; struct _env { diff --git a/src/wildmidi/gus_pat.cpp b/src/wildmidi/gus_pat.cpp index be3422db5..83d311367 100644 --- a/src/wildmidi/gus_pat.cpp +++ b/src/wildmidi/gus_pat.cpp @@ -1,31 +1,26 @@ /* - gus_pat.c - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . + * gus_pat.c -- Midi Wavetable Processing library + * + * Copyright (C) WildMIDI Developers 2001-2015 + * + * This file is part of WildMIDI. + * + * WildMIDI is free software: you can redistribute and/or modify the player + * under the terms of the GNU General Public License and you can redistribute + * and/or modify the library under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of + * the licenses, or(at your option) any later version. + * + * WildMIDI is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License and the + * GNU Lesser General Public License along with WildMIDI. If not, see + * . */ -//#include "config.h" - #include #include #include @@ -737,6 +732,8 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { }; unsigned long int tmp_loop; + /*unused*/fix_release; + SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename); if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) { @@ -839,17 +836,80 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { /* FIXME: Experimental Hacky Fix + + This looks for "dodgy" release envelope settings that faulty editors + may have set and attempts to corrects it. + if (fix_release) + Lets make this automatic ... */ - if (fix_release) { - if (env_time_table[gus_patch[gus_ptr + 40]] - < env_time_table[gus_patch[gus_ptr + 41]]) { - unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = tmp_hack_rate; + { + /* + After studying faulty gus_pats this way may work better + Testing to determine if any further adjustments are required + */ + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) { + unsigned char tmp_hack_rate = 0; + + if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 2 3 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } else if (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 2 2 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + + } else { + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 3 2 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } else { + // 2 3 1 or 1 2 1 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = tmp_hack_rate; + } + } + } else if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { + unsigned char tmp_hack_rate = 0; + + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 2 1 3 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = tmp_hack_rate; + } else { + // 3 1 2 + tmp_hack_rate = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } } + +#if 0 + if ((env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) && (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]])) { + uint8_t tmp_hack_rate = 0; + tmp_hack_rate = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = tmp_hack_rate; + tmp_hack_rate = gus_patch[gus_ptr + 47]; + gus_patch[gus_ptr + 47] = gus_patch[gus_ptr + 46]; + gus_patch[gus_ptr + 48] = gus_patch[gus_ptr + 46]; + gus_patch[gus_ptr + 46] = tmp_hack_rate; + } +#endif } for (i = 0; i < 6; i++) { + GUSPAT_INT_DEBUG("Envelope #",i); if (gus_sample->modes & SAMPLE_ENVELOPE) { unsigned char env_rate = gus_patch[gus_ptr + 37 + i]; gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i]; @@ -886,6 +946,32 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { return NULL; } + /* + Test and set decay expected decay time after a note off + NOTE: This sets samples for full range decay + */ + if (gus_sample->modes & SAMPLE_ENVELOPE) { + double samples_f = 0.0; + + if (gus_sample->modes & SAMPLE_CLAMPED) { + samples_f = (4194301.0 - (float)gus_sample->env_target[5]) / gus_sample->env_rate[5]; + } else { + if (gus_sample->modes & SAMPLE_SUSTAIN) { + samples_f = (4194301.0 - (float)gus_sample->env_target[3]) / gus_sample->env_rate[3]; + samples_f += (float)(gus_sample->env_target[3] - gus_sample->env_target[4]) / gus_sample->env_rate[4]; + } else { + samples_f = (4194301.0 - (float)gus_sample->env_target[4]) / gus_sample->env_rate[4]; + } + samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5]; + } + samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6]; + + gus_sample->note_off_decay = (unsigned)samples_f; + + } else { + gus_sample->note_off_decay = gus_sample->data_length * _WM_SampleRate / gus_sample->rate; + } + gus_ptr += tmp_cnt; gus_sample->loop_start = (gus_sample->loop_start << 10) | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); From 7f44bc6d0e3d953e5be31a459643a570538cc761 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 18:59:56 -0600 Subject: [PATCH 295/335] Add Yamaha and GM reset sysex handling to WildMidi --- src/wildmidi/wildmidi_lib.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 20857da12..d29a939fd 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -1976,7 +1976,7 @@ static void do_sysex_roland_drum_track(struct _mdi *mdi, } } -static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { +static void do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) { int i; for (i = 0; i < 16; i++) { mdi->channel[i].bank = 0; @@ -2003,6 +2003,14 @@ static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { UNUSED(data); /* NOOP, to please the compiler gods */ } +static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { + do_sysex_gm_reset(mdi, data); +} + +static void do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) { + do_sysex_gm_reset(mdi, data); +} + static int add_handle(void * handle) { struct _hndl *tmp_handle = NULL; @@ -2967,6 +2975,20 @@ void WildMidi_Renderer::LongEvent(const unsigned char *data, int len) } } } + // For non-Roland Sysex messages */ + else + { + const unsigned char gm_reset[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 }; + const unsigned char yamaha_reset[] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7}; + if (len == 6 && memcmp(gm_reset, data, 6) == 0) + { + do_sysex_gm_reset((_mdi *)handle, NULL); + } + else if (len == 9 && memcmp(yamaha_reset, data, 9) == 0) + { + do_sysex_yamaha_reset((_mdi *)handle, NULL); + } + } } void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len) From 88beae55bd6ed7c6ab43351c5eef3aa9dff94a8d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 19:15:27 -0600 Subject: [PATCH 296/335] Add separate NRPN coarse/fine adjustment for WildMidi --- src/wildmidi/wildmidi_lib.cpp | 46 +++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index d29a939fd..d50090a3c 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -1794,9 +1794,19 @@ static void do_control_data_decrement(struct _mdi *mdi, mdi->channel[ch].pitch_range--; } } -static void do_control_non_registered_param(struct _mdi *mdi, +static void do_control_non_registered_param_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80) + | data->data; + mdi->channel[ch].reg_non = 1; +} + +static void do_control_non_registered_param_course(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F) + | (data->data << 7); mdi->channel[ch].reg_non = 1; } @@ -2913,23 +2923,23 @@ void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2) ev.data = parm2; switch (parm1) { - case 0: do_control_bank_select(mdi, &ev); break; - case 6: do_control_data_entry_course(mdi, &ev); break; // [sic] - case 7: do_control_channel_volume(mdi, &ev); break; - case 8: do_control_channel_balance(mdi, &ev); break; - case 10: do_control_channel_pan(mdi, &ev); break; - case 11: do_control_channel_expression(mdi, &ev); break; - case 38: do_control_data_entry_fine(mdi, &ev); break; - case 64: do_control_channel_hold(mdi, &ev); break; - case 96: do_control_data_increment(mdi, &ev); break; - case 97: do_control_data_decrement(mdi, &ev); break; - case 98: - case 99: do_control_non_registered_param(mdi, &ev); break; - case 100: do_control_registered_param_fine(mdi, &ev); break; - case 101: do_control_registered_param_course(mdi, &ev); break; // [sic] - case 120: do_control_channel_sound_off(mdi, &ev); break; - case 121: do_control_channel_controllers_off(mdi, &ev); break; - case 123: do_control_channel_notes_off(mdi, &ev); break; + case 0: do_control_bank_select(mdi, &ev); break; + case 6: do_control_data_entry_course(mdi, &ev); break; // [sic] + case 7: do_control_channel_volume(mdi, &ev); break; + case 8: do_control_channel_balance(mdi, &ev); break; + case 10: do_control_channel_pan(mdi, &ev); break; + case 11: do_control_channel_expression(mdi, &ev); break; + case 38: do_control_data_entry_fine(mdi, &ev); break; + case 64: do_control_channel_hold(mdi, &ev); break; + case 96: do_control_data_increment(mdi, &ev); break; + case 97: do_control_data_decrement(mdi, &ev); break; + case 98: do_control_non_registered_param_fine(mdi, &ev); break; + case 99: do_control_non_registered_param_course(mdi, &ev); break; // [sic] + case 100: do_control_registered_param_fine(mdi, &ev); break; + case 101: do_control_registered_param_course(mdi, &ev); break; // [sic] + case 120: do_control_channel_sound_off(mdi, &ev); break; + case 121: do_control_channel_controllers_off(mdi, &ev); break; + case 123: do_control_channel_notes_off(mdi, &ev); break; } } } From 50ecec199fb7dd53d0f21a13e13479c838f4d1a4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 19:15:55 -0600 Subject: [PATCH 297/335] More stuff we don't need in WildMidi removed --- src/wildmidi/wildmidi_lib.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index d50090a3c..1cf5c04df 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -130,18 +130,6 @@ struct _note { unsigned char is_off; }; -struct _miditrack { - unsigned long int length; - unsigned long int ptr; - unsigned long int delta; - unsigned char running_event; - unsigned char EOT; -}; - -struct _mdi_patches { - struct _patch *patch; - struct _mdi_patch *next; -}; struct _event_data { unsigned char channel; From 7f01a6a30aaa4d303f8e8979e8e0fd81a0f0e379 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 19:19:06 -0600 Subject: [PATCH 298/335] Import envelope tweaks for current WildMidi git --- src/wildmidi/wildmidi_lib.cpp | 164 ++++++++++++++++------------------ 1 file changed, 78 insertions(+), 86 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 1cf5c04df..beadbc19d 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -1374,47 +1374,47 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { return return_sample; } + static void do_note_off_extra(struct _note *nte) { nte->is_off = 0; - if (nte->hold) { - nte->hold |= HOLD_OFF; - } else { - if (!(nte->modes & SAMPLE_ENVELOPE)) { - if (nte->modes & SAMPLE_LOOP) { - nte->modes ^= SAMPLE_LOOP; - } - nte->env_inc = 0; - } else if (nte->modes & SAMPLE_CLAMPED) { - if (nte->env < 5) { - nte->env = 5; - if (nte->env_level > nte->sample->env_target[5]) { - nte->env_inc = -nte->sample->env_rate[5]; - } else { - nte->env_inc = nte->sample->env_rate[5]; - } - } -#if 1 - } else if (nte->modes & SAMPLE_SUSTAIN) { - if (nte->env < 3) { - nte->env = 3; - if (nte->env_level > nte->sample->env_target[3]) { - nte->env_inc = -nte->sample->env_rate[3]; - } else { - nte->env_inc = nte->sample->env_rate[3]; - } - } -#endif - } else if (nte->env < 4) { - nte->env = 4; - if (nte->env_level > nte->sample->env_target[4]) { - nte->env_inc = -nte->sample->env_rate[4]; + if (!(nte->modes & SAMPLE_ENVELOPE)) { + if (nte->modes & SAMPLE_LOOP) { + nte->modes ^= SAMPLE_LOOP; + } + nte->env_inc = 0; + + } else if (nte->hold) { + nte->hold |= HOLD_OFF; + + } else if (nte->modes & SAMPLE_SUSTAIN) { + if (nte->env < 3) { + nte->env = 3; + if (nte->env_level > nte->sample->env_target[3]) { + nte->env_inc = -nte->sample->env_rate[3]; } else { - nte->env_inc = nte->sample->env_rate[4]; + nte->env_inc = nte->sample->env_rate[3]; } } + + } else if (nte->modes & SAMPLE_CLAMPED) { + if (nte->env < 5) { + nte->env = 5; + if (nte->env_level > nte->sample->env_target[5]) { + nte->env_inc = -nte->sample->env_rate[5]; + } else { + nte->env_inc = nte->sample->env_rate[5]; + } + } + } else if (nte->env < 4) { + nte->env = 4; + if (nte->env_level > nte->sample->env_target[4]) { + nte->env_inc = -nte->sample->env_rate[4]; + } else { + nte->env_inc = nte->sample->env_rate[4]; + } } } @@ -2174,19 +2174,16 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) * ======================== */ note_data->sample_pos += note_data->sample_inc; - if (note_data->sample_pos > note_data->sample->loop_end) { - if (note_data->modes & SAMPLE_LOOP) { + if (note_data->modes & SAMPLE_LOOP) { + if (note_data->sample_pos > note_data->sample->loop_end) { note_data->sample_pos = - note_data->sample->loop_start - + ((note_data->sample_pos - - note_data->sample->loop_start) - % note_data->sample->loop_size); - } else if (note_data->sample_pos >= note_data->sample->data_length) { - if (note_data->replay == NULL) { - goto KILL_NOTE; - } - goto RESTART_NOTE; + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); } + } else if (note_data->sample_pos >= note_data->sample->data_length) { + goto END_THIS_NOTE; } if (note_data->env_inc == 0) { @@ -2195,35 +2192,32 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) } note_data->env_level += note_data->env_inc; - if (note_data->env_level > 4194304) { - note_data->env_level = - note_data->sample->env_target[note_data->env]; - } - if (((note_data->env_inc < 0) - && (note_data->env_level - > note_data->sample->env_target[note_data->env])) - || ((note_data->env_inc > 0) - && (note_data->env_level - < note_data->sample->env_target[note_data->env]))) - { - note_data = note_data->next; - continue; + if (note_data->env_inc < 0) { + if (note_data->env_level > note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } else if (note_data->env_inc > 0) { + if (note_data->env_level < note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } } + // Yes could have a condition here but + // it would create another bottleneck note_data->env_level = note_data->sample->env_target[note_data->env]; switch (note_data->env) { case 0: -#if 0 if (!(note_data->modes & SAMPLE_ENVELOPE)) { note_data->env_inc = 0; note_data = note_data->next; continue; } -#endif break; case 2: - if (note_data->modes & SAMPLE_SUSTAIN) { + if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) { note_data->env_inc = 0; note_data = note_data->next; continue; @@ -2242,7 +2236,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) break; case 5: if (note_data->env_level == 0) { - goto KILL_NOTE; + goto END_THIS_NOTE; } /* sample release */ if (note_data->modes & SAMPLE_LOOP) @@ -2251,8 +2245,9 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) note_data = note_data->next; continue; case 6: + END_THIS_NOTE: if (note_data->replay != NULL) { - RESTART_NOTE: note_data->active = 0; + note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; @@ -2273,7 +2268,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) note_data->active = 1; } } else { - KILL_NOTE: note_data->active = 0; + note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; @@ -2417,10 +2412,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) - note_data->sample->loop_start) % note_data->sample->loop_size); } else if (note_data->sample_pos >= note_data->sample->data_length) { - if (note_data->replay == NULL) { - goto KILL_NOTE; - } - goto RESTART_NOTE; + goto END_THIS_NOTE; } } @@ -2430,33 +2422,32 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) } note_data->env_level += note_data->env_inc; - if (note_data->env_level > 4194304) { - note_data->env_level = - note_data->sample->env_target[note_data->env]; - } - if ( - ((note_data->env_inc < 0) - && (note_data->env_level - > note_data->sample->env_target[note_data->env])) - || ((note_data->env_inc > 0) - && (note_data->env_level - < note_data->sample->env_target[note_data->env])) - ) { - note_data = note_data->next; - continue; + if (note_data->env_inc < 0) { + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } else if (note_data->env_inc > 0) { + if (note_data->env_level + < note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } } + // Yes could have a condition here but + // it would create another bottleneck + note_data->env_level = note_data->sample->env_target[note_data->env]; switch (note_data->env) { case 0: -#if 0 if (!(note_data->modes & SAMPLE_ENVELOPE)) { note_data->env_inc = 0; note_data = note_data->next; continue; } -#endif break; case 2: if (note_data->modes & SAMPLE_SUSTAIN) { @@ -2478,7 +2469,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) break; case 5: if (note_data->env_level == 0) { - goto KILL_NOTE; + goto END_THIS_NOTE; } /* sample release */ if (note_data->modes & SAMPLE_LOOP) @@ -2487,8 +2478,9 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) note_data = note_data->next; continue; case 6: + END_THIS_NOTE: if (note_data->replay != NULL) { - RESTART_NOTE: note_data->active = 0; + note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; @@ -2509,7 +2501,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) note_data->active = 1; } } else { - KILL_NOTE: note_data->active = 0; + note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; From 5b4a6483b53e1c08d6562fd585ee189261e6624e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 19:19:57 -0600 Subject: [PATCH 299/335] Remove get_decay_samples. Not needed. --- src/wildmidi/wildmidi_lib.cpp | 44 ----------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index beadbc19d..ce33e8bf7 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2090,50 +2090,6 @@ static void freeMDI(struct _mdi *mdi) { free(mdi); } -static unsigned long int get_decay_samples(struct _patch *patch, unsigned char note) { - - struct _sample *sample = NULL; - unsigned long int freq = 0; - unsigned long int decay_samples = 0; - - if (patch == NULL) - return 0; - - /* first get the freq we need so we can check the right sample */ - if (patch->patchid & 0x80) { - /* is a drum patch */ - if (patch->note) { - freq = freq_table[(patch->note % 12) * 100] - >> (10 - (patch->note / 12)); - } else { - freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); - } - } else { - freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); - } - - /* get the sample */ - sample = get_sample_data(patch, (freq / 100)); - if (sample == NULL) - return 0; - - if (patch->patchid & 0x80) { - float sratedata = ((float) sample->rate / (float) _WM_SampleRate) - * (float) (sample->data_length >> 10); - decay_samples = (unsigned long int) sratedata; - /* printf("Drums (%i / %i) * %lu = %f\n", sample->rate, _WM_SampleRate, (sample->data_length >> 10), sratedata);*/ - } else if (sample->modes & SAMPLE_CLAMPED) { - decay_samples = (4194303 / sample->env_rate[5]); - /* printf("clamped 4194303 / %lu = %lu\n", sample->env_rate[5], decay_samples);*/ - } else { - decay_samples = - ((4194303 - sample->env_target[4]) / sample->env_rate[4]) - + (sample->env_target[4] / sample->env_rate[5]); - /* printf("NOT clamped ((4194303 - %lu) / %lu) + (%lu / %lu)) = %lu\n", sample->env_target[4], sample->env_rate[4], sample->env_target[4], sample->env_rate[5], decay_samples);*/ - } - return decay_samples; -} - static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) { struct _mdi *mdi = (struct _mdi *)handle; From 268d2faaf6eb74194676533da9b637bd029a7d4e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 19:21:41 -0600 Subject: [PATCH 300/335] Import volume handling changes from current WildMidi git MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Description there reads: > Major work done on “log†volumes. Calculations are now based on decibels. --- src/wildmidi/wildmidi_lib.cpp | 377 ++++++++++++++++------------------ 1 file changed, 175 insertions(+), 202 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index ce33e8bf7..6b846bd3f 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -116,24 +116,24 @@ struct _note { unsigned char velocity; struct _patch *patch; struct _sample *sample; - unsigned long int sample_pos; - unsigned long int sample_inc; - signed long int env_inc; + unsigned int sample_pos; + unsigned int sample_inc; + signed int env_inc; unsigned char env; - signed long int env_level; + signed int env_level; unsigned char modes; unsigned char hold; unsigned char active; struct _note *replay; struct _note *next; - unsigned long int vol_lvl; + unsigned int left_mix_volume; + unsigned int right_mix_volume; unsigned char is_off; }; - struct _event_data { unsigned char channel; - unsigned long int data; + unsigned int data; }; struct _mdi { @@ -274,30 +274,64 @@ static signed short int lin_volume[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 878, 886, 894, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 983, 991, 999, 1007, 1015, 1024 }; -/* f: pow(( VOLUME / 127.0 ), 2.0 ) * 1024.0 */ -static signed short int sqr_volume[] = { 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 9, - 10, 12, 14, 16, 18, 20, 22, 25, 27, 30, 33, 36, 39, 42, 46, 49, 53, 57, - 61, 65, 69, 73, 77, 82, 86, 91, 96, 101, 106, 111, 117, 122, 128, 134, - 140, 146, 152, 158, 165, 171, 178, 185, 192, 199, 206, 213, 221, 228, - 236, 244, 251, 260, 268, 276, 284, 293, 302, 311, 320, 329, 338, 347, - 357, 366, 376, 386, 396, 406, 416, 426, 437, 447, 458, 469, 480, 491, - 502, 514, 525, 537, 549, 560, 572, 585, 597, 609, 622, 634, 647, 660, - 673, 686, 699, 713, 726, 740, 754, 768, 782, 796, 810, 825, 839, 854, - 869, 884, 899, 914, 929, 944, 960, 976, 992, 1007, 1024 }; +/* f: As per midi 2 standard */ +static float dBm_volume[] = { -999999.999999f, -84.15214884f, -72.11094901f, + -65.06729865f, -60.06974919f, -56.19334866f, -53.02609882f, -50.34822724f, + -48.02854936f, -45.98244846f, -44.15214884f, -42.49644143f, -40.984899f, + -39.59441475f, -38.30702741f, -37.10849848f, -35.98734953f, -34.93419198f, + -33.94124863f, -33.0020048f, -32.11094901f, -31.26337705f, -30.45524161f, + -29.6830354f, -28.94369917f, -28.23454849f, -27.55321492f, -26.89759827f, + -26.26582758f, -25.65622892f, -25.06729865f, -24.49768108f, -23.94614971f, + -23.41159124f, -22.89299216f, -22.38942706f, -21.90004881f, -21.42407988f, + -20.96080497f, -20.50956456f, -20.06974919f, -19.64079457f, -19.22217722f, + -18.81341062f, -18.41404178f, -18.02364829f, -17.64183557f, -17.26823452f, + -16.90249934f, -16.54430564f, -16.19334866f, -15.84934179f, -15.51201509f, + -15.18111405f, -14.85639845f, -14.53764126f, -14.22462776f, -13.91715461f, + -13.6150291f, -13.31806837f, -13.02609882f, -12.73895544f, -12.45648126f, + -12.17852686f, -11.90494988f, -11.63561457f, -11.37039142f, -11.10915673f, + -10.85179233f, -10.59818521f, -10.34822724f, -10.10181489f, -9.858848981f, + -9.619234433f, -9.382880049f, -9.149698303f, -8.919605147f, -8.692519831f, + -8.468364731f, -8.247065187f, -8.028549359f, -7.812748083f, -7.599594743f, + -7.389025143f, -7.180977396f, -6.97539181f, -6.772210788f, -6.571378733f, + -6.372841952f, -6.176548572f, -5.982448461f, -5.790493145f, -5.600635744f, + -5.412830896f, -5.227034694f, -5.043204627f, -4.861299517f, -4.681279468f, + -4.503105811f, -4.326741054f, -4.152148838f, -3.979293887f, -3.808141968f, + -3.63865985f, -3.470815266f, -3.304576875f, -3.139914228f, -2.976797731f, + -2.815198619f, -2.655088921f, -2.496441432f, -2.339229687f, -2.183427931f, + -2.029011099f, -1.875954785f, -1.724235224f, -1.573829269f, -1.424714368f, + -1.276868546f, -1.130270383f, -0.9848989963f, -0.8407340256f, -0.6977556112f, + -0.5559443807f, -0.4152814317f, -0.2757483179f, -0.1373270335f, 0 }; -/* f: pow(( VOLUME / 127.0 ), 0.5 ) * 1024.0 */ -static signed short int pan_volume[] = { 0, 90, 128, 157, 181, 203, 222, 240, - 257, 272, 287, 301, 314, 327, 339, 351, 363, 374, 385, 396, 406, 416, - 426, 435, 445, 454, 463, 472, 480, 489, 497, 505, 514, 521, 529, 537, - 545, 552, 560, 567, 574, 581, 588, 595, 602, 609, 616, 622, 629, 636, - 642, 648, 655, 661, 667, 673, 679, 686, 692, 697, 703, 709, 715, 721, - 726, 732, 738, 743, 749, 754, 760, 765, 771, 776, 781, 786, 792, 797, - 802, 807, 812, 817, 822, 827, 832, 837, 842, 847, 852, 857, 862, 866, - 871, 876, 880, 885, 890, 894, 899, 904, 908, 913, 917, 922, 926, 931, - 935, 939, 944, 948, 953, 957, 961, 965, 970, 974, 978, 982, 987, 991, - 995, 999, 1003, 1007, 1011, 1015, 1019, 1024 }; +/* f: As per midi 2 standard */ +static float dBm_pan_volume[] = { -999999.999999f, -38.15389834f -32.13396282f, + -28.61324502f, -26.1160207f, -24.179814f, -22.5986259f, -21.26257033f, + -20.10605521f, -19.08677237f, -18.17583419f, -17.35263639f, -16.60196565f, + -15.91226889f, -15.2745658f, -14.6817375f, -14.12804519f, -13.60879499f, + -13.12009875f, -12.65869962f, -12.22184237f, -11.80717543f, -11.41267571f, + -11.03659017f, -10.67738981f, -10.33373306f, -10.00443638f, -9.6884504f, + -9.384840381f, -9.092770127f, -8.811488624f, -8.540318866f, -8.278648457f, + -8.025921658f, -7.781632628f, -7.545319633f, -7.316560087f, -7.094966257f, + -6.880181552f, -6.671877289f, -6.46974987f, -6.273518306f, -6.082922045f, + -5.897719045f, -5.717684082f, -5.542607236f, -5.372292553f, -5.206556845f, + -5.045228616f, -4.888147106f, -4.735161423f, -4.586129765f, -4.44091872f, + -4.299402626f, -4.161462998f, -4.026988004f, -3.895871989f, -3.76801504f, + -3.643322591f, -3.52170506f, -3.403077519f, -3.287359388f, -3.174474158f, + -3.064349129f, -2.956915181f, -2.852106549f, -2.749860626f, -2.650117773f, + -2.55282115f, -2.457916557f, -2.36535228f, -2.27507896f, -2.187049463f, + -2.101218759f, -2.017543814f, -1.935983486f,-1.856498429f, -1.779051001f, + -1.703605184f, -1.630126502f, -1.558581949f, -1.48893992f, -1.421170148f, + -1.35524364f, -1.291132623f, -1.228810491f, -1.168251755f, -1.109431992f, + -1.052327808f, -0.9969167902f, -0.9431774708f, -0.8910892898f, -0.8406325604f, + -0.7917884361f, -0.7445388804f, -0.6988666373f, -0.6547552046f, -0.612188808f, + -0.5711523768f, -0.5316315211f, -0.4936125107f, -0.4570822543f, -0.4220282808f, + -0.3884387214f, -0.3563022927f, -0.3256082808f, -0.2963465264f, -0.2685074109f, + -0.2420818435f, -0.2170612483f, -0.1934375538f, -0.1712031815f, -0.1503510361f, + -0.1308744964f, -0.1127674066f, -0.09602406855f, -0.08063923423f, + -0.06660809932f, -0.05392629701f, -0.04258989258f, -0.03259537844f, + -0.02393966977f, -0.01662010072f, -0.01063442111f, -0.005980793601f, + -0.002657791522f, -0.000664397052f, 0 }; -static unsigned long int freq_table[] = { 837201792, 837685632, 838169728, +static unsigned int freq_table[] = { 837201792, 837685632, 838169728, 838653568, 839138240, 839623232, 840108480, 840593984, 841079680, 841565184, 842051648, 842538240, 843025152, 843512320, 843999232, 844486976, 844975040, 845463360, 845951936, 846440320, 846929536, @@ -1179,7 +1213,6 @@ static int load_sample(struct _patch *sample_patch) { samp_max = tmp_sample->data[i]; if (tmp_sample->data[i] < samp_min) samp_min = tmp_sample->data[i]; - } if (samp_max > tmp_max) tmp_max = samp_max; @@ -1374,6 +1407,78 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { return return_sample; } +/* Should be called in any function that effects note volumes */ +void _WM_AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte) { + double premix_dBm; + double premix_lin; + unsigned char pan_ofs; + double premix_dBm_left; + double premix_dBm_right; + double premix_left; + double premix_right; + double volume_adj; + unsigned vol_ofs; + + /* + Pointless CPU heating checks to shoosh up a compiler + */ + if (ch > 0x0f) ch = 0x0f; + + pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64; + + vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127; + + /* + This value is to reduce the chance of clipping. + Higher value means lower overall volume, + Lower value means higher overall volume. + NOTE: The lower the value the higher the chance of clipping. + FIXME: Still needs tuning. Clipping heard at a value of 3.75 + */ +#define VOL_DIVISOR 4.0 + volume_adj = ((float)WM_MasterVolume / 1024.0) / VOL_DIVISOR; + + if (pan_ofs > 127) pan_ofs = 127; + premix_dBm_left = dBm_pan_volume[(127-pan_ofs)]; + premix_dBm_right = dBm_pan_volume[pan_ofs]; + + if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { + premix_dBm = dBm_volume[vol_ofs]; + + premix_dBm_left += premix_dBm; + premix_dBm_right += premix_dBm; + + premix_left = (pow(10.0,(premix_dBm_left / 20.0))) * volume_adj; + premix_right = (pow(10.0,(premix_dBm_right / 20.0))) * volume_adj; + } else { + premix_lin = (float)(lin_volume[vol_ofs]) / 1024.0; + + premix_left = premix_lin * pow(10.0, (premix_dBm_left / 20)) * volume_adj; + premix_right = premix_lin * pow(10.0, (premix_dBm_right / 20)) * volume_adj; + } + nte->left_mix_volume = (int)(premix_left * 1024.0); + nte->right_mix_volume = (int)(premix_right * 1024.0); +} + +/* Should be called in any function that effects channel volumes */ +/* Calling this function with a value > 15 will make it adjust notes on all channels */ +void _WM_AdjustChannelVolumes(struct _mdi *mdi, unsigned char ch) { + struct _note *nte = mdi->note; + if (nte != NULL) { + do { + if (ch <= 15) { + if ((nte->noteid >> 8) == ch) { + goto _DO_ADJUST; + } + } else { + _DO_ADJUST: + _WM_AdjustNoteVolumes(mdi, ch, nte); + if (nte->replay) _WM_AdjustNoteVolumes(mdi, ch, nte->replay); + } + nte = nte->next; + } while (nte != NULL); + } +} static void do_note_off_extra(struct _note *nte) { @@ -1435,7 +1540,10 @@ static void do_note_off(struct _mdi *mdi, struct _event_data *data) { return; } - if (nte->env == 0) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) { + // This is a fix for notes that end before the + // initial step of the envelope has completed + // making it impossible to hear them at times. nte->is_off = 1; } else { do_note_off_extra(nte); @@ -1463,24 +1571,6 @@ static inline unsigned long int get_inc(struct _mdi *mdi, struct _note *nte) { / nte->sample->inc_div)); } -static inline unsigned long int get_volume(struct _mdi *mdi, unsigned char ch, - struct _note *nte) { - signed long int volume; - - if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { - volume = (sqr_volume[mdi->channel[ch].volume] - * sqr_volume[mdi->channel[ch].expression] - * sqr_volume[nte->velocity]) / 1048576; - } else { - volume = (lin_volume[mdi->channel[ch].volume] - * lin_volume[mdi->channel[ch].expression] - * lin_volume[nte->velocity]) / 1048576; - } - - volume = volume * nte->patch->amp / 100; - return (volume); -} - static void do_note_on(struct _mdi *mdi, struct _event_data *data) { struct _note *nte; struct _note *prev_nte; @@ -1490,7 +1580,7 @@ static void do_note_on(struct _mdi *mdi, struct _event_data *data) { struct _sample *sample; unsigned char ch = data->channel; unsigned char note = (unsigned char)(data->data >> 8); - unsigned char velocity = (data->data & 0xFF); + unsigned char velocity = (unsigned char)(data->data & 0xFF); if (velocity == 0x00) { do_note_off(mdi, data); @@ -1568,9 +1658,9 @@ static void do_note_on(struct _mdi *mdi, struct _event_data *data) { nte->env_level = 0; nte->modes = sample->modes; nte->hold = mdi->channel[ch].hold; - nte->vol_lvl = get_volume(mdi, ch, nte); nte->replay = NULL; nte->is_off = 0; + _WM_AdjustNoteVolumes(mdi, ch, nte); } static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) { @@ -1587,40 +1677,14 @@ static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) { } } - nte->velocity = data->data & 0xff; - nte->vol_lvl = get_volume(mdi, ch, nte); - + nte->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, nte); if (nte->replay) { - nte->replay->velocity = data->data & 0xff; - nte->replay->vol_lvl = get_volume(mdi, ch, nte->replay); + nte->replay->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, nte->replay); } } -static void do_pan_adjust(struct _mdi *mdi, unsigned char ch) { - signed short int pan_adjust = mdi->channel[ch].balance - + mdi->channel[ch].pan; - signed short int left, right; - int amp = 32; - - if (pan_adjust > 63) { - pan_adjust = 63; - } else if (pan_adjust < -64) { - pan_adjust = -64; - } - - pan_adjust += 64; -/* if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) {*/ - left = (pan_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576; - right = (pan_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576; -/* } else { - left = (lin_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576; - right= (lin_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576; - }*/ - - mdi->channel[ch].left_adjust = left; - mdi->channel[ch].right_adjust = right; -} - static void do_control_bank_select(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; mdi->channel[ch].bank = (unsigned char)data->data; @@ -1646,33 +1710,22 @@ static void do_control_channel_volume(struct _mdi *mdi, unsigned char ch = data->channel; mdi->channel[ch].volume = (unsigned char)data->data; - - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->vol_lvl = get_volume(mdi, ch, note_data); - if (note_data->replay) - note_data->replay->vol_lvl = get_volume(mdi, ch, - note_data->replay); - } - note_data = note_data->next; - } while (note_data); - } + _WM_AdjustChannelVolumes(mdi, ch); } static void do_control_channel_balance(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; - mdi->channel[ch].balance = (signed char)(data->data - 64); - do_pan_adjust(mdi, ch); + mdi->channel[ch].balance = (signed char)(data->data); + _WM_AdjustChannelVolumes(mdi, ch); } static void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) { unsigned char ch = data->channel; - mdi->channel[ch].pan = (signed char)(data->data - 64); - do_pan_adjust(mdi, ch); + mdi->channel[ch].pan = (signed char)(data->data); + _WM_AdjustChannelVolumes(mdi, ch); } static void do_control_channel_expression(struct _mdi *mdi, @@ -1681,18 +1734,7 @@ static void do_control_channel_expression(struct _mdi *mdi, unsigned char ch = data->channel; mdi->channel[ch].expression = (unsigned char)data->data; - - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->vol_lvl = get_volume(mdi, ch, note_data); - if (note_data->replay) - note_data->replay->vol_lvl = get_volume(mdi, ch, - note_data->replay); - } - note_data = note_data->next; - } while (note_data); - } + _WM_AdjustChannelVolumes(mdi, ch); } static void do_control_data_entry_fine(struct _mdi *mdi, @@ -1839,33 +1881,13 @@ static void do_control_channel_controllers_off(struct _mdi *mdi, mdi->channel[ch].expression = 127; mdi->channel[ch].pressure = 127; - mdi->channel[ch].volume = 100; - mdi->channel[ch].pan = 0; - mdi->channel[ch].balance = 0; mdi->channel[ch].reg_data = 0xffff; mdi->channel[ch].pitch_range = 200; mdi->channel[ch].pitch = 0; mdi->channel[ch].pitch_adjust = 0; mdi->channel[ch].hold = 0; - do_pan_adjust(mdi, ch); - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->sample_inc = get_inc(mdi, note_data); - note_data->velocity = 0; - note_data->vol_lvl = get_volume(mdi, ch, note_data); - note_data->hold = 0; - - if (note_data->replay) { - note_data->replay->velocity = (unsigned char)data->data; - note_data->replay->vol_lvl = get_volume(mdi, ch, - note_data->replay); - } - } - note_data = note_data->next; - } while (note_data); - } + _WM_AdjustChannelVolumes(mdi, ch); } static void do_control_channel_notes_off(struct _mdi *mdi, @@ -1917,20 +1939,16 @@ static void do_channel_pressure(struct _mdi *mdi, struct _event_data *data) { MIDI_EVENT_DEBUG(__FUNCTION__,ch); - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->velocity = (unsigned char)data->data; - note_data->vol_lvl = get_volume(mdi, ch, note_data); - - if (note_data->replay) { - note_data->replay->velocity = (unsigned char)data->data; - note_data->replay->vol_lvl = get_volume(mdi, ch, - note_data->replay); - } + while (note_data) { + if ((note_data->noteid >> 8) == ch) { + note_data->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, note_data); + if (note_data->replay) { + note_data->replay->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, note_data->replay); } - note_data = note_data->next; - } while (note_data); + } + note_data = note_data->next; } } @@ -1987,16 +2005,17 @@ static void do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) { mdi->channel[i].volume = 100; mdi->channel[i].pressure = 127; mdi->channel[i].expression = 127; - mdi->channel[i].balance = 0; - mdi->channel[i].pan = 0; - mdi->channel[i].left_adjust = 1; - mdi->channel[i].right_adjust = 1; + mdi->channel[i].balance = 64; + mdi->channel[i].pan = 64; mdi->channel[i].pitch = 0; mdi->channel[i].pitch_range = 200; mdi->channel[i].reg_data = 0xFFFF; mdi->channel[i].isdrum = 0; - do_pan_adjust(mdi, i); } + /* I would not expect notes to be active when this event + triggers but we'll adjust active notes as well just in case */ + _WM_AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels + mdi->channel[9].isdrum = 1; UNUSED(data); /* NOOP, to please the compiler gods */ } @@ -2095,7 +2114,6 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) struct _mdi *mdi = (struct _mdi *)handle; unsigned long int data_pos; signed int premix, left_mix, right_mix; - signed int vol_mul; struct _note *note_data = NULL; do { @@ -2109,20 +2127,11 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) * =================== */ data_pos = note_data->sample_pos >> FPBITS; - vol_mul = ((note_data->vol_lvl - * (note_data->env_level >> 12)) >> FPBITS); + premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024; - premix = (note_data->sample->data[data_pos] - + ((note_data->sample->data[data_pos + 1] - - note_data->sample->data[data_pos]) - * (signed long int) (note_data->sample_pos - & FPMASK)>> FPBITS)) * vol_mul - / 1024; - left_mix += premix - * mdi->channel[note_data->noteid >> 8].left_adjust; - right_mix += premix - * mdi->channel[note_data->noteid >> 8].right_adjust; + left_mix += (premix * (int)note_data->left_mix_volume) / 1024; + right_mix += (premix * (int)note_data->right_mix_volume) / 1024; /* * ======================== @@ -2269,10 +2278,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) * mix the channels together * ========================= */ - left_mix /= 1024; - right_mix /= 1024; } - *buffer++ = left_mix; *buffer++ = right_mix; } while (--count); @@ -2286,7 +2292,6 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) struct _mdi *mdi = (struct _mdi *)handle; unsigned long int data_pos; signed int premix, left_mix, right_mix; - signed int vol_mul; struct _note *note_data = NULL; signed short int *sptr; double y, xd; @@ -2305,8 +2310,6 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) * =================== */ data_pos = note_data->sample_pos >> FPBITS; - vol_mul = ((note_data->vol_lvl - * (note_data->env_level >> 12)) >> FPBITS); /* check to see if we're near one of the ends */ left = data_pos; @@ -2346,12 +2349,10 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) } while (gptr <= gend); } - premix = (long) (y * vol_mul / 1024); + premix = (int)((y * (note_data->env_level >> 12)) / 1024); - left_mix += premix - * mdi->channel[note_data->noteid >> 8].left_adjust; - right_mix += premix - * mdi->channel[note_data->noteid >> 8].right_adjust; + left_mix += (premix * (int)note_data->left_mix_volume) / 1024; + right_mix += (premix * (int)note_data->right_mix_volume) / 1024; /* * ======================== @@ -2502,10 +2503,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) * mix the channels together * ========================= */ - left_mix /= 1024; - right_mix /= 1024; } - *buffer++ = left_mix; *buffer++ = right_mix; } while (--count); @@ -2598,16 +2596,6 @@ WM_SYMBOL int WildMidi_MasterVolume(unsigned char master_volume) { WM_MasterVolume = lin_volume[master_volume]; - if (tmp_handle) { - while (tmp_handle) { - mdi = (struct _mdi *) tmp_handle->handle; - for (i = 0; i < 16; i++) { - do_pan_adjust(mdi, i); - } - tmp_handle = tmp_handle->next; - } - } - return 0; } @@ -2688,7 +2676,6 @@ midi *WildMidi_NewMidi() { WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, unsigned short int setting) { struct _mdi *mdi; - int i; if (!WM_Initialized) { _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); @@ -2719,22 +2706,8 @@ WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, | (options & setting)); if (options & WM_MO_LOG_VOLUME) { - struct _note *note_data = mdi->note; - - for (i = 0; i < 16; i++) { - do_pan_adjust(mdi, i); - } - - if (note_data) { - do { - note_data->vol_lvl = get_volume(mdi, (note_data->noteid >> 8), - note_data); - if (note_data->replay) - note_data->replay->vol_lvl = get_volume(mdi, - (note_data->noteid >> 8), note_data->replay); - note_data = note_data->next; - } while (note_data); - } + _WM_AdjustChannelVolumes(mdi, 16); // Settings greater than 15 + // adjust all channels } else if (options & WM_MO_REVERB) { _WM_reset_reverb(mdi->reverb); } From 27bf86e1ebdfdb42cf1eb85cb7ffd51188a2e688 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 20:01:14 -0600 Subject: [PATCH 301/335] Fix(?) dBm_pan_volume table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The missing comma on the first line of dBm_pan_volume's definition looked suspicious, so I checked the MIDI specification at http://www.midi.org/techspecs/rp36.php and found the equations there gave different dB values than were in the table. So I rebuilt it using the equation given there: 20*log (sin (Pi /2* max(0,CC#10 – 1)/126)) --- src/wildmidi/wildmidi_lib.cpp | 64 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 6b846bd3f..0a01a9402 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -303,33 +303,39 @@ static float dBm_volume[] = { -999999.999999f, -84.15214884f, -72.11094901f, -0.5559443807f, -0.4152814317f, -0.2757483179f, -0.1373270335f, 0 }; /* f: As per midi 2 standard */ -static float dBm_pan_volume[] = { -999999.999999f, -38.15389834f -32.13396282f, - -28.61324502f, -26.1160207f, -24.179814f, -22.5986259f, -21.26257033f, - -20.10605521f, -19.08677237f, -18.17583419f, -17.35263639f, -16.60196565f, - -15.91226889f, -15.2745658f, -14.6817375f, -14.12804519f, -13.60879499f, - -13.12009875f, -12.65869962f, -12.22184237f, -11.80717543f, -11.41267571f, - -11.03659017f, -10.67738981f, -10.33373306f, -10.00443638f, -9.6884504f, - -9.384840381f, -9.092770127f, -8.811488624f, -8.540318866f, -8.278648457f, - -8.025921658f, -7.781632628f, -7.545319633f, -7.316560087f, -7.094966257f, - -6.880181552f, -6.671877289f, -6.46974987f, -6.273518306f, -6.082922045f, - -5.897719045f, -5.717684082f, -5.542607236f, -5.372292553f, -5.206556845f, - -5.045228616f, -4.888147106f, -4.735161423f, -4.586129765f, -4.44091872f, - -4.299402626f, -4.161462998f, -4.026988004f, -3.895871989f, -3.76801504f, - -3.643322591f, -3.52170506f, -3.403077519f, -3.287359388f, -3.174474158f, - -3.064349129f, -2.956915181f, -2.852106549f, -2.749860626f, -2.650117773f, - -2.55282115f, -2.457916557f, -2.36535228f, -2.27507896f, -2.187049463f, - -2.101218759f, -2.017543814f, -1.935983486f,-1.856498429f, -1.779051001f, - -1.703605184f, -1.630126502f, -1.558581949f, -1.48893992f, -1.421170148f, - -1.35524364f, -1.291132623f, -1.228810491f, -1.168251755f, -1.109431992f, - -1.052327808f, -0.9969167902f, -0.9431774708f, -0.8910892898f, -0.8406325604f, - -0.7917884361f, -0.7445388804f, -0.6988666373f, -0.6547552046f, -0.612188808f, - -0.5711523768f, -0.5316315211f, -0.4936125107f, -0.4570822543f, -0.4220282808f, - -0.3884387214f, -0.3563022927f, -0.3256082808f, -0.2963465264f, -0.2685074109f, - -0.2420818435f, -0.2170612483f, -0.1934375538f, -0.1712031815f, -0.1503510361f, - -0.1308744964f, -0.1127674066f, -0.09602406855f, -0.08063923423f, - -0.06660809932f, -0.05392629701f, -0.04258989258f, -0.03259537844f, - -0.02393966977f, -0.01662010072f, -0.01063442111f, -0.005980793601f, - -0.002657791522f, -0.000664397052f, 0 }; +static float dBm_pan_volume[127] = { + -999999.999999f, -87.6945020928f, -73.8331126923f, -65.7264009888f, + -59.9763864074f, -55.5181788833f, -51.8774481743f, -48.8011722841f, + -46.1383198371f, -43.7914727130f, -41.6941147218f, -39.7988027954f, + -38.0705069530f, -36.4826252703f, -35.0144798827f, -33.6496789707f, + -32.3750084716f, -31.1796603753f, -30.0546819321f, -28.9925739783f, + -27.9869924122f, -27.0325225804f, -26.1245061976f, -25.2589067713f, + -24.4322036893f, -23.6413079424f, -22.8834943857f, -22.1563467917f, + -21.4577129008f, -20.7856673630f, -20.1384809653f, -19.5145949062f, + -18.9125991563f, -18.3312141503f, -17.7692752119f, -17.2257192381f, + -16.6995732597f, -16.1899445690f, -15.6960121652f, -15.2170193110f, + -14.7522670314f, -14.3011084168f, -13.8629436112f, -13.4372153915f, + -13.0234052546f, -12.6210299451f, -12.2296383638f, -11.8488088095f, + -11.4781465116f, -11.1172814164f, -10.7658661983f, -10.4235744668f, + -10.0900991491f, -9.7651510261f, -9.4484574055f, -9.1397609172f, + -8.8388184168f, -8.5453999868f, -8.2592880250f, -7.9802764101f, + -7.7081697387f, -7.4427826248f, -7.1839390567f, -6.9314718056f, + -6.6852218807f, -6.4450380272f, -6.2107762624f, -5.9822994468f, + -5.7594768878f, -5.5421839719f, -5.3303018237f, -5.1237169899f, + -4.9223211445f, -4.7260108155f, -4.5346871303f, -4.3482555779f, + -4.1666257875f, -3.9897113219f, -3.8174294843f, -3.6497011373f, + -3.4864505345f, -3.3276051620f, -3.1730955900f, -3.0228553340f, + -2.8768207245f, -2.7349307844f, -2.5971271143f, -2.4633537845f, + -2.3335572335f, -2.2076861725f, -2.0856914960f, -1.9675261968f, + -1.8531452871f, -1.7425057233f, -1.6355663356f, -1.5322877618f, + -1.4326323846f, -1.3365642732f, -1.2440491272f, -1.1550542250f, + -1.0695483746f, -0.9875018671f, -0.9088864335f, -0.8336752037f, + -0.7618426682f, -0.6933646420f, -0.6282182304f, -0.5663817981f, + -0.5078349388f, -0.4525584478f, -0.4005342959f, -0.3517456058f, + -0.3061766293f, -0.2638127266f, -0.2246403475f, -0.1886470134f, + -0.1558213016f, -0.1261528303f, -0.0996322457f, -0.0762512098f, + -0.0560023899f, -0.0388794497f, -0.0248770409f, -0.0139907967f, + -0.0062173263f, -0.0015542108f, 0.0000000000f }; static unsigned int freq_table[] = { 837201792, 837685632, 838169728, 838653568, 839138240, 839623232, 840108480, 840593984, 841079680, @@ -1438,8 +1444,10 @@ void _WM_AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte #define VOL_DIVISOR 4.0 volume_adj = ((float)WM_MasterVolume / 1024.0) / VOL_DIVISOR; + // Pan 0 and 1 are both hard left so 64 can be centered if (pan_ofs > 127) pan_ofs = 127; - premix_dBm_left = dBm_pan_volume[(127-pan_ofs)]; + if (--pan_ofs < 0) pan_ofs = 0; + premix_dBm_left = dBm_pan_volume[126-pan_ofs]; premix_dBm_right = dBm_pan_volume[pan_ofs]; if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { From 141cd660eb79972fb76006e881cb76fb13ee0ffb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 20:07:14 -0600 Subject: [PATCH 302/335] Didn't need note_off_decay in the WildMidi sample struct --- src/wildmidi/common.h | 2 -- src/wildmidi/gus_pat.cpp | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/wildmidi/common.h b/src/wildmidi/common.h index efe08dd25..a089329e0 100644 --- a/src/wildmidi/common.h +++ b/src/wildmidi/common.h @@ -60,8 +60,6 @@ struct _sample { unsigned int inc_div; signed short *data; struct _sample *next; - - unsigned int note_off_decay; }; struct _env { diff --git a/src/wildmidi/gus_pat.cpp b/src/wildmidi/gus_pat.cpp index 83d311367..8f4824dc5 100644 --- a/src/wildmidi/gus_pat.cpp +++ b/src/wildmidi/gus_pat.cpp @@ -965,11 +965,6 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5]; } samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6]; - - gus_sample->note_off_decay = (unsigned)samples_f; - - } else { - gus_sample->note_off_decay = gus_sample->data_length * _WM_SampleRate / gus_sample->rate; } gus_ptr += tmp_cnt; From 46f04830e21b8d38b9149bf939dc05da4a343292 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 11 Jan 2016 21:11:36 -0600 Subject: [PATCH 303/335] Update VC2005 project files --- dumb/vc6/dumb_static/dumb_static.vcproj | 4 --- lzma/lzmalib.vcproj | 47 +++++++++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj index 497fe4a99..6d6736259 100644 --- a/dumb/vc6/dumb_static/dumb_static.vcproj +++ b/dumb/vc6/dumb_static/dumb_static.vcproj @@ -1203,10 +1203,6 @@ /> - - + + @@ -303,10 +306,6 @@ RelativePath=".\C\7zDec.c" > - - @@ -323,10 +322,18 @@ RelativePath=".\C\Bra86.c" > + + + + @@ -347,6 +354,14 @@ RelativePath=".\C\LzmaEnc.c" > + + + + @@ -381,10 +396,18 @@ RelativePath=".\C\Bra.h" > + + + + @@ -409,6 +432,18 @@ RelativePath=".\C\LzmaEnc.h" > + + + + + + From b87c612aba25b3d900d65c50a8c95eb75cdd897d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 12 Jan 2016 11:12:19 +0100 Subject: [PATCH 304/335] - Fixed Clang warning on wildMIDI code. Now that '_event_data.data' is changed to 'unsigned int', the 'unsigned long' cast is not needed anymore. --- src/wildmidi/wildmidi_lib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 0a01a9402..4464e7798 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2893,7 +2893,7 @@ void WildMidi_Renderer::LongEvent(const unsigned char *data, int len) { sysex_ch -= 1; } - _event_data ev = { sysex_ch, static_cast(data[8]) }; + _event_data ev = { sysex_ch, data[8] }; do_sysex_roland_drum_track((_mdi *)handle, &ev); } else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00) From dc66f4cb3ff00dadd2dab2928d4bfa3407d961be Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 12 Jan 2016 06:34:29 -0600 Subject: [PATCH 305/335] Make _WM_AdjustNoteVolume's pan_ofs a signed int --- src/wildmidi/wildmidi_lib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 4464e7798..5f711bf35 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -1417,7 +1417,7 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) { void _WM_AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte) { double premix_dBm; double premix_lin; - unsigned char pan_ofs; + int pan_ofs; double premix_dBm_left; double premix_dBm_right; double premix_left; From 37f18055af94ac2fa77a5ee92e58aad6870fdbf8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 12 Jan 2016 21:34:41 +0100 Subject: [PATCH 306/335] - turned sector_t::FloorSkyBox and CeilingSkyBox into an array. - removed unused SpreadCeilingPortal function. --- src/dobject.cpp | 4 +-- src/dobjgc.cpp | 4 +-- src/g_shared/a_skies.cpp | 12 ++++----- src/p_saveg.cpp | 2 +- src/p_sectors.cpp | 12 ++------- src/p_spec.cpp | 53 ++++++++-------------------------------- src/r_defs.h | 4 +-- 7 files changed, 25 insertions(+), 66 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 191fa3c43..9d674d226 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -517,8 +517,8 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) #define SECTOR_CHECK(f,t) \ if (sectors[i].f.p == static_cast(old)) { sectors[i].f = static_cast(notOld); changed++; } SECTOR_CHECK( SoundTarget, AActor ); - SECTOR_CHECK( CeilingSkyBox, ASkyViewpoint ); - SECTOR_CHECK( FloorSkyBox, ASkyViewpoint ); + SECTOR_CHECK( SkyBoxes[sector_t::ceiling], ASkyViewpoint ); + SECTOR_CHECK( SkyBoxes[sector_t::floor], ASkyViewpoint ); SECTOR_CHECK( SecActTarget, ASectorAction ); SECTOR_CHECK( floordata, DSectorEffect ); SECTOR_CHECK( ceilingdata, DSectorEffect ); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index d52962f11..3812c0b08 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -640,8 +640,8 @@ size_t DSectorMarker::PropagateMark() { sector_t *sec = §ors[SecNum + i]; GC::Mark(sec->SoundTarget); - GC::Mark(sec->CeilingSkyBox); - GC::Mark(sec->FloorSkyBox); + GC::Mark(sec->SkyBoxes[sector_t::ceiling]); + GC::Mark(sec->SkyBoxes[sector_t::floor]); GC::Mark(sec->SecActTarget); GC::Mark(sec->floordata); GC::Mark(sec->ceilingdata); diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index ef5623746..a8c8ebd55 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -67,13 +67,13 @@ void ASkyViewpoint::Destroy () // remove all sector references to ourselves. for (int i = 0; i CeilingSkyBox = box; + Sector->SkyBoxes[sector_t::ceiling] = box; if (box == NULL) Sector->MoreFlags |= SECF_NOCEILINGSKYBOX; // sector should ignore the level's default skybox } if (0 == (args[1] & 1)) { - Sector->FloorSkyBox = box; + Sector->SkyBoxes[sector_t::floor] = box; if (box == NULL) Sector->MoreFlags |= SECF_NOFLOORSKYBOX; // sector should ignore the level's default skybox } } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index db14aeb90..7623104d7 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -418,7 +418,7 @@ void P_SerializeWorld (FArchive &arc) << sec->sky << sec->MoreFlags << sec->Flags - << sec->FloorSkyBox << sec->CeilingSkyBox + << sec->SkyBoxes[sector_t::floor] << sec->SkyBoxes[sector_t::ceiling] << sec->ZoneNumber; if (SaveVersion < 4529) { diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 6c5c08a56..83adc438f 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -805,16 +805,8 @@ int sector_t::GetCeilingLight () const ASkyViewpoint *sector_t::GetSkyBox(int which) { - if (which == floor) - { - if (FloorSkyBox != NULL) return FloorSkyBox; - if (MoreFlags & SECF_NOFLOORSKYBOX) return NULL; - } - else - { - if (CeilingSkyBox != NULL) return CeilingSkyBox; - if (MoreFlags & SECF_NOCEILINGSKYBOX) return NULL; - } + if (SkyBoxes[which] != NULL) return SkyBoxes[which]; + if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL; return level.DefaultSkybox; } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 08a43fe2a..36d5f3bab 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -909,10 +909,10 @@ static void SetupFloorPortal (AStackPoint *point) { NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->FloorSkyBox = static_cast(it.Next()); - if (Sector->FloorSkyBox != NULL && Sector->FloorSkyBox->bAlways) + Sector->SkyBoxes[sector_t::floor] = static_cast(it.Next()); + if (Sector->SkyBoxes[sector_t::floor] != NULL && Sector->SkyBoxes[sector_t::floor]->bAlways) { - Sector->FloorSkyBox->Mate = point; + Sector->SkyBoxes[sector_t::floor]->Mate = point; if (Sector->GetAlpha(sector_t::floor) == OPAQUE) Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); } @@ -922,48 +922,15 @@ static void SetupCeilingPortal (AStackPoint *point) { NActorIterator it (NAME_UpperStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->CeilingSkyBox = static_cast(it.Next()); - if (Sector->CeilingSkyBox != NULL && Sector->CeilingSkyBox->bAlways) + Sector->SkyBoxes[sector_t::ceiling] = static_cast(it.Next()); + if (Sector->SkyBoxes[sector_t::ceiling] != NULL && Sector->SkyBoxes[sector_t::ceiling]->bAlways) { - Sector->CeilingSkyBox->Mate = point; + Sector->SkyBoxes[sector_t::ceiling]->Mate = point; if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) Sector->SetAlpha(sector_t::ceiling, Scale (point->args[0], OPAQUE, 255)); } } -static bool SpreadCeilingPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector) -{ - bool fail = false; - sector->validcount = validcount; - for(int i=0; ilinecount; i++) - { - line_t *line = sector->lines[i]; - sector_t *backsector = sector == line->frontsector? line->backsector : line->frontsector; - if (line->backsector == line->frontsector) continue; - if (backsector == NULL) { fail = true; continue; } - if (backsector->validcount == validcount) continue; - if (backsector->CeilingSkyBox == pt) continue; - - // Check if the backside would map to the same visplane - if (backsector->CeilingSkyBox != NULL) { fail = true; continue; } - if (backsector->ceilingplane != sector->ceilingplane) { fail = true; continue; } - if (backsector->lightlevel != sector->lightlevel) { fail = true; continue; } - if (backsector->GetTexture(sector_t::ceiling) != sector->GetTexture(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetXOffset(sector_t::ceiling) != sector->GetXOffset(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetYOffset(sector_t::ceiling) != sector->GetYOffset(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetXScale(sector_t::ceiling) != sector->GetXScale(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetYScale(sector_t::ceiling) != sector->GetYScale(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetAngle(sector_t::ceiling) != sector->GetAngle(sector_t::ceiling)) { fail = true; continue; } - if (SpreadCeilingPortal(pt, alpha, backsector)) { fail = true; continue; } - } - if (!fail) - { - sector->CeilingSkyBox = pt; - sector->SetAlpha(sector_t::ceiling, alpha); - } - return fail; -} - void P_SetupPortals() { TThinkerIterator it; @@ -991,9 +958,9 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_ // plane: 0=floor, 1=ceiling, 2=both if (plane > 0) { - if (sector->CeilingSkyBox == NULL || !sector->CeilingSkyBox->bAlways) + if (sector->SkyBoxes[sector_t::ceiling] == NULL || !sector->SkyBoxes[sector_t::ceiling]->bAlways) { - sector->CeilingSkyBox = portal; + sector->SkyBoxes[sector_t::ceiling] = portal; if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) sector->SetAlpha(sector_t::ceiling, alpha); @@ -1002,9 +969,9 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_ } if (plane == 2 || plane == 0) { - if (sector->FloorSkyBox == NULL || !sector->FloorSkyBox->bAlways) + if (sector->SkyBoxes[sector_t::floor] == NULL || !sector->SkyBoxes[sector_t::floor]->bAlways) { - sector->FloorSkyBox = portal; + sector->SkyBoxes[sector_t::floor] = portal; } if (sector->GetAlpha(sector_t::floor) == OPAQUE) sector->SetAlpha(sector_t::floor, alpha); diff --git a/src/r_defs.h b/src/r_defs.h index a7e37f369..05fd7bd03 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -346,7 +346,7 @@ enum SECF_DRAWN = 128, // sector has been drawn at least once SECF_HIDDEN = 256, // Do not draw on textured automap SECF_NOFLOORSKYBOX = 512, // force use of regular sky - SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky + SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!) }; enum @@ -790,7 +790,7 @@ struct sector_t // [RH] The sky box to render for this sector. NULL means use a // regular sky. - TObjPtr FloorSkyBox, CeilingSkyBox; + TObjPtr SkyBoxes[2]; int sectornum; // for comparing sector copies From f9574a98fde94b2c7e32145a142a048d351d0a2c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 13 Jan 2016 17:25:24 -0600 Subject: [PATCH 307/335] Fix Timidity's DLS instrument loading: - Envelope data needed to be converted to SF2 values. - Fine tuning was ignored which made pretty much every instrument off tune. - Despite this, it still sounds like shit compared to FMOD or Microsoft's wavetable synth. There are lots of missing notes and some instruments are still off tune. I'm not sure it's worth trying to salvage it. It'd probably be better to scrap it, since Timidity is very much oriented toward GF1 patches, which it handles perfectly fine. --- src/timidity/instrum_dls.cpp | 35 ++++++++++++++++------------------- src/timidity/mix.cpp | 29 +++++++++++++++++++++++------ src/timidity/timidity.cpp | 12 ++++++++++++ src/timidity/timidity.h | 3 +-- 4 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp index 286fcb1a3..02b8e59c0 100644 --- a/src/timidity/instrum_dls.cpp +++ b/src/timidity/instrum_dls.cpp @@ -1126,7 +1126,7 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, sample->key_group = (SBYTE)rgn->header->usKeyGroup; sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow); sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh); - sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote); + sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote + rgn->wsmp->sFineTune * .01f); sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow; sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh; @@ -1137,15 +1137,17 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, convert_sample_data(sample, wave->data); if (rgn->wsmp->cSampleLoops) { - sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN); + sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN/* | PATCH_NO_SRELEASE*/); sample->loop_start = rgn->wsmp_loop->ulStart / 2; sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); } + sample->scale_factor = 1024; + sample->scale_note = rgn->wsmp->usUnityNote; if (sample->modes & PATCH_SUSTAIN) { int value; - double attack, hold, decay, release; int sustain; + int attack, hold, decay, release; int sustain; CONNECTIONLIST *art = NULL; CONNECTION *artList = NULL; @@ -1157,16 +1159,11 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, artList = rgn->artList; } - value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); - attack = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); - hold = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); - decay = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); - release = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); - sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0); + attack = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); + hold = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); + decay = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); + release = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); + sustain = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); value = load_connection(art->cConnections, artList, CONN_DST_PAN); sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f); @@ -1174,12 +1171,12 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); */ - sample->envelope.sf2.decay_vol = 0; - sample->envelope.sf2.attack_vol = (short)attack; - sample->envelope.sf2.hold_vol = (short)hold; - sample->envelope.sf2.decay_vol = (short)decay; - sample->envelope.sf2.release_vol = (short)release; - sample->envelope.sf2.sustain_vol = (short)sustain; + sample->envelope.sf2.delay_vol = -32768; + sample->envelope.sf2.attack_vol = (short)(attack >> 16); + sample->envelope.sf2.hold_vol = (short)(hold >> 16); + sample->envelope.sf2.decay_vol = (short)(decay >> 16); + sample->envelope.sf2.release_vol = (short)(release >> 16); + sample->envelope.sf2.sustain_vol = (short)(sustain >> 16); } sample->data_length <<= FRACTION_BITS; diff --git a/src/timidity/mix.cpp b/src/timidity/mix.cpp index f97710326..beda91e16 100644 --- a/src/timidity/mix.cpp +++ b/src/timidity/mix.cpp @@ -231,6 +231,10 @@ bool SF2Envelope::Update(Voice *v) double sec; double newvolume = 0; + // NOTE! The volume scale is different for different stages of the + // envelope generator: + // Attack stage goes from 0.0 -> 1.0, multiplied directly to the output. + // The following stages go from 0 -> -1000 cB (but recorded positively) switch (stage) { case SF2_DELAY: @@ -333,6 +337,11 @@ bool SF2Envelope::Update(Voice *v) #define FLUID_ATTEN_POWER_FACTOR (-531.509) #define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR) +static double cb_to_amp(double x) // centibels to amp +{ + return pow(10, x / -200.f); +} + void SF2Envelope::ApplyToAmp(Voice *v) { double amp; @@ -343,13 +352,21 @@ void SF2Envelope::ApplyToAmp(Voice *v) v->right_mix = 0; return; } - else if (stage == SF2_ATTACK) + + amp = v->sample->type == INST_SF2 ? atten2amp(v->attenuation) : cb_to_amp(v->attenuation); + + switch (stage) { - amp = atten2amp(v->attenuation) * volume; - } - else - { - amp = atten2amp(v->attenuation) * cb_to_amp(volume); + case SF2_ATTACK: + amp *= volume; + break; + + case SF2_HOLD: + break; + + default: + amp *= cb_to_amp(volume); + break; } amp *= FINAL_MIX_SCALE * 0.5; v->left_mix = float(amp * v->left_offset); diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 440db9211..267edbb7e 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -678,6 +678,9 @@ int LoadDMXGUS() return 0; } +DLS_Data *LoadDLS(FILE *src); +void FreeDLS(DLS_Data *data); + Renderer::Renderer(float sample_rate, const char *args) { // 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first @@ -701,6 +704,11 @@ Renderer::Renderer(float sample_rate, const char *args) voices = MAX(*midi_voices, 16); voice = new Voice[voices]; drumchannels = DEFAULT_DRUMCHANNELS; +#if 0 + FILE *f = fopen("c:\\windows\\system32\\drivers\\gm.dls", "rb"); + patches = LoadDLS(f); + fclose(f); +#endif } Renderer::~Renderer() @@ -713,6 +721,10 @@ Renderer::~Renderer() { delete[] voice; } + if (patches != NULL) + { + FreeDLS(patches); + } } void Renderer::ComputeOutput(float *buffer, int count) diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 45e23a9f9..ac423c1e2 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -445,7 +445,7 @@ struct Channel struct MinEnvelope { - int stage; + BYTE stage; BYTE bUpdating; }; @@ -599,7 +599,6 @@ const double log_of_2 = 0.69314718055994529; #define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2)) #define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation -#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp /* timidity.h From 629eaa35a32c10ff77a046cabde88a9edd152d51 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 13 Jan 2016 20:26:15 -0600 Subject: [PATCH 308/335] - Fixed: A_Fade* could destroy live player bodies because it was calling the Destroy() function directly instead of going through P_RemoveThing. --- src/thingdef/thingdef_codeptr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index b6575ee19..8343b79b8 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2439,7 +2439,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) if (flags & FTF_CLAMP) self->alpha = (FRACUNIT * 1); if (flags & FTF_REMOVE) - self->Destroy(); + P_RemoveThing(self); } } @@ -2467,7 +2467,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) if (flags & FTF_CLAMP) self->alpha = 0; if (flags & FTF_REMOVE) - self->Destroy(); + P_RemoveThing(self); } } @@ -2515,7 +2515,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) } if (self->alpha == target && (flags & FTF_REMOVE)) { - self->Destroy(); + P_RemoveThing(self); } } From 6a87c6cd19051ef3a3d454f2ab808feb028ba343 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 14 Jan 2016 00:49:57 -0500 Subject: [PATCH 309/335] - Fixed usage of uninitialized value in skybox rendering. --- src/r_plane.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 8cab34230..96a77930a 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1280,6 +1280,7 @@ void R_DrawSkyBoxes () ds_p->sprtopclip = R_NewOpening (pl->maxx - pl->minx + 1); ds_p->maskedtexturecol = ds_p->swall = -1; ds_p->bFogBoundary = false; + ds_p->fake = 0; memcpy (openings + ds_p->sprbottomclip, floorclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short)); memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short)); From dd9e7560c4b16b26c8f7bbf2ba72a51c867f46ba Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 14 Jan 2016 11:21:08 -0600 Subject: [PATCH 310/335] Added support for puffs to spawn on floors and ceilings if ALWAYSPUFF is used. --- src/p_map.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index 3381f763f..30cec2ad2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4297,6 +4297,14 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i SpawnShootDecal(source, trace); } + if (trace.HitType == TRACE_HitFloor || trace.HitType == TRACE_HitCeiling) + { + AActor* puff = NULL; + if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) + { + puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + } + } if (thepuff != NULL) { if (trace.HitType == TRACE_HitFloor && From 16781e47aea55d46abe022a9ccb7134923d80351 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 14 Jan 2016 20:41:09 -0600 Subject: [PATCH 311/335] Use a 64k stream buffer for all streams, not just net streams - FLACs need a larger buffer than the default to run without starving on later versions of FMOD. --- src/sound/fmodsound.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 4042ca421..e7a617f5a 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -462,14 +462,12 @@ public: Stream->release(); Channel = NULL; Stream = NULL; - Owner->Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); // Open the stream asynchronously, so we don't hang the game while trying to reconnect. // (It would be nice to do the initial open asynchronously as well, but I'd need to rethink // the music system design to pull that off.) result = Owner->Sys->createSound(URL, (Loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM | FMOD_NONBLOCKING, NULL, &Stream); JustStarted = true; - Owner->Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); return result != FMOD_OK; } if (JustStarted && openstate == FMOD_OPENSTATE_PLAYING) @@ -1170,6 +1168,9 @@ bool FMODSoundRenderer::Init() } Sys->set3DSettings(0.5f, 96.f, 1.f); Sys->set3DRolloffCallback(RolloffCallback); + // The default is 16k, which periodically starves later FMOD versions + // when streaming FLAC files. + Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); snd_sfxvolume.Callback (); return true; } @@ -1733,10 +1734,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags) exinfo.dlsname = patches; } - // Use a larger buffer for URLs so that it's less likely to be effected - // by hiccups in the data rate from the remote server. - Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); - result = Sys->createSound(url, mode, &exinfo, &stream); if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) { @@ -1748,9 +1745,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags) } } - // Restore standard buffer size. - Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); - if(result != FMOD_OK) return NULL; From 867b7767ef78f8553fdb0afa7378601562c18d3c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Jan 2016 12:56:27 +0100 Subject: [PATCH 312/335] - ignore COMPAT_POINTONSIDE in a few places where the side effects of the old P_PointOn*Side functions are either not needed or problematic: * the sight checking code needs to be as precise as possible and should not depend on some old semi-broken routines. (This is more a precision issue of these routines - P_PointOnDivlineSide removes the lower 8 bits of each value - than having an issue with returning the wrong side in some cases.) * for slope creations it is flat out wrong to use the old routines at all. * also ignore this in the modern (box-shaped) case of FPathTraverse::AddLineIntercepts. This functionality is new to ZDoom and therefore not subject to compatibility concerns. * the line-to-line teleporter. It seems the hideous fudging code was just there to work around the design issues of these functions, so let's better not ever call them here in the first place. * A_PainShootSkull: Its usage here does not depend on these issues. * P_ExplodeMissile: New code exclusive to ZDoom. * FPolyObj::CheckMobjBlocking All occurences in p_map.cpp have been left alone although most of them probably won't need the compatibility option either. --- src/g_doom/a_painelemental.cpp | 2 +- src/p_local.h | 12 ++++++++++++ src/p_maputl.cpp | 6 +++--- src/p_mobj.cpp | 2 +- src/p_sight.cpp | 10 +++++----- src/p_slopes.cpp | 4 ++-- src/p_teleport.cpp | 2 +- src/po_man.cpp | 2 +- 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index b52224c0c..f361fb78d 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -103,7 +103,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int box.Top() < ld->bbox[BOXBOTTOM] || box.Bottom() > ld->bbox[BOXTOP])) { - if (P_PointOnLineSide(self->x,self->y,ld) != P_PointOnLineSide(x,y,ld)) + if (P_PointOnLineSidePrecise(self->x,self->y,ld) != P_PointOnLineSidePrecise(x,y,ld)) return; // line blocks trajectory // ^ } } diff --git a/src/p_local.h b/src/p_local.h index fd5064f3c..e8cc5fde0 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -249,6 +249,12 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; } +inline int P_PointOnLineSidePrecise (fixed_t x, fixed_t y, const line_t *line) +{ + return DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; +} + + //========================================================================== // // P_PointOnDivlineSide @@ -267,6 +273,12 @@ inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); } +inline int P_PointOnDivlineSidePrecise (fixed_t x, fixed_t y, const divline_t *line) +{ + return DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0; +} + + //========================================================================== // // P_MakeDivline diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index e6d5a99e6..1d806d044 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1056,13 +1056,13 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it break; } // Check if this side is facing the trace origin - if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) + if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &line) == 0) { numfronts++; // If it is, see if the trace crosses it - if (P_PointOnDivlineSide (line.x, line.y, &trace) != - P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + if (P_PointOnDivlineSidePrecise (line.x, line.y, &trace) != + P_PointOnDivlineSidePrecise (line.x + line.dx, line.y + line.dy, &trace)) { // It's a hit fixed_t frac = P_InterceptVector (&trace, &line); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 750cc18fb..bcaa77855 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1284,7 +1284,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) if (line != NULL && cl_missiledecals) { - int side = P_PointOnLineSide (mo->x, mo->y, line); + int side = P_PointOnLineSidePrecise (mo->x, mo->y, line); if (line->sidedef[side] == NULL) side ^= 1; if (line->sidedef[side] != NULL) diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 135698b8b..2d465aab5 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -132,7 +132,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) { int frontflag; - frontflag = P_PointOnLineSide(sightthing->x, sightthing->y, li); + frontflag = P_PointOnLineSidePrecise(sightthing->x, sightthing->y, li); //Check 3D FLOORS! for(int i=1;i<=2;i++) @@ -241,14 +241,14 @@ bool SightCheck::P_SightCheckLine (line_t *ld) return true; } ld->validcount = validcount; - if (P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace) == - P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace)) + if (P_PointOnDivlineSidePrecise (ld->v1->x, ld->v1->y, &trace) == + P_PointOnDivlineSidePrecise (ld->v2->x, ld->v2->y, &trace)) { return true; // line isn't crossed } P_MakeDivline (ld, &dl); - if (P_PointOnDivlineSide (trace.x, trace.y, &dl) == - P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl)) + if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &dl) == + P_PointOnDivlineSidePrecise (trace.x+trace.dx, trace.y+trace.dy, &dl)) { return true; // line isn't crossed } diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index c0b9b5ef0..a3db26526 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -54,7 +54,7 @@ static void P_SlopeLineToPoint (int lineid, fixed_t x, fixed_t y, fixed_t z, boo sector_t *sec; secplane_t *plane; - if (P_PointOnLineSide (x, y, line) == 0) + if (P_PointOnLineSidePrecise (x, y, line) == 0) { sec = line->frontsector; } @@ -363,7 +363,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt, z3 = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); vt3.Z = FIXED2FLOAT(z3); - if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0) + if (P_PointOnLineSidePrecise(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0) { vec1 = vt2 - vt3; vec2 = vt1 - vt3; diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 040aca9f4..380f5572d 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -530,7 +530,7 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO int fudge = FUDGEFACTOR; // Make sure we are on correct side of exit linedef. - while (P_PointOnLineSide(x, y, l) != side && --fudge >= 0) + while (P_PointOnLineSidePrecise(x, y, l) != side && --fudge >= 0) { if (abs(l->dx) > abs(l->dy)) y -= (l->dx < 0) != side ? -1 : 1; diff --git a/src/po_man.cpp b/src/po_man.cpp index 727591bd5..98fbbcbcb 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1231,7 +1231,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) // Best use the one facing the player and ignore the back side. if (ld->sidedef[1] != NULL) { - int side = P_PointOnLineSide(mobj->x, mobj->y, ld); + int side = P_PointOnLineSidePrecise(mobj->x, mobj->y, ld); if (ld->sidedef[side] != sd) { continue; From e405fb4624861ef01b7b3bf342e0f8a47f4ef8b9 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 15 Jan 2016 15:54:35 +0200 Subject: [PATCH 313/335] Set compatibility for Return to Hadron Updated version of Return to Hadron (dated 2016.01.03) has new version of E1M9: Prototype This map requires vanilla's P_PointOnLineSide() function to avoid issue with sleepy shotgun guys http://forum.zdoom.org/viewtopic.php?t=49544 --- wadsrc/static/compatibility.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 1bd031ed8..13f0d22a7 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -403,6 +403,7 @@ D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29 } D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 +19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { pointonline } From ef8dc22f7d2698b8c5c705d328819c0fe2eda4f4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Jan 2016 15:36:21 +0100 Subject: [PATCH 314/335] - looks I missed one file when I member-fied P_AproxDistance and R_PointToAngle2 calls. --- src/g_strife/a_spectral.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 6e2e6488e..6f80fe42c 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -95,7 +95,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) return; // change angle - exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); + exact = self->AngleTo(dest); if (exact != self->angle) { @@ -120,8 +120,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // change slope - dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); - dist /= self->Speed; + dist = self->AproxDistance (dest) / self->Speed; if (dist < 1) { From 90e2dc5f5aad3a173bf020c3fc21e7338d75fb4f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Jan 2016 16:40:50 +0100 Subject: [PATCH 315/335] - some minor optimizations to FPathTraverse: * since we can trivially decide whether a line crosses the trace behind the end point from checking the return value of P_InterceptVector, there is no need to add those to the list of intercepts as they get discarded anyway in t * maxfrac is always FRACUNIT so there's no need to waste some variable for a constant value. --- src/p_local.h | 1 - src/p_maputl.cpp | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index e8cc5fde0..859722912 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -380,7 +380,6 @@ class FPathTraverse divline_t trace; unsigned int intercept_index; unsigned int intercept_count; - fixed_t maxfrac; unsigned int count; void AddLineIntercepts(int bx, int by); diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 1d806d044..85e9183c5 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -985,7 +985,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by) P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); - if (frac < 0) continue; // behind source + if (frac < 0 || frac > 1) continue; // behind source or beyond end point intercept_t newintercept; @@ -1170,7 +1170,7 @@ intercept_t *FPathTraverse::Next() } } - if (dist > maxfrac || in == NULL) return NULL; // checked everything in range + if (dist > FRACUNIT || in == NULL) return NULL; // checked everything in range in->done = true; return in; } @@ -1388,7 +1388,6 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in break; } } - maxfrac = FRACUNIT; } FPathTraverse::~FPathTraverse() From a8e5b90667392072eac633bc1f74f935aab8c37b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 15 Jan 2016 18:32:49 +0200 Subject: [PATCH 316/335] Fixed stuck Strife dialogs See http://forum.zdoom.org/viewtopic.php?t=50451 and http://forum.zdoom.org/viewtopic.php?t=48470 --- src/p_conversation.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index db5fd400c..a74b9bd18 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1345,12 +1345,14 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (reply->NextNode != 0) { int rootnode = npc->ConversationRoot; - if (reply->NextNode < 0) + unsigned next = (unsigned)(rootnode + (reply->NextNode < 0 ? -1 : 1) * reply->NextNode - 1); + + if (next < StrifeDialogues.Size()) { - unsigned next = (unsigned)(rootnode - reply->NextNode - 1); - if (gameaction != ga_slideshow && next < StrifeDialogues.Size()) + npc->Conversation = StrifeDialogues[next]; + + if (gameaction != ga_slideshow) { - npc->Conversation = StrifeDialogues[next]; P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); return; } @@ -1359,10 +1361,6 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply S_StopSound (npc, CHAN_VOICE); } } - else - { - npc->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1]; - } } npc->angle = player->ConversationNPCAngle; From 8f31af3ff955dabba0d7d68916291cf015606535 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 16 Jan 2016 00:51:17 -0500 Subject: [PATCH 317/335] - Work around issue with tree-loop-vectorize in p_acs.cpp. --- src/p_acs.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 87641efe2..6f136d98b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1954,11 +1954,14 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) int arraynum = MapVarStore[LittleLong(chunk[2])]; if ((unsigned)arraynum < (unsigned)NumArrays) { - int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); + // Use unsigned iterator here to avoid issue with GCC 4.9/5.x + // optimizer. Might be some undefined behavior in this code, + // but I don't know what it is. + unsigned int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); SDWORD *elems = ArrayStore[arraynum].Elements; - for (i = 0; i < initsize; ++i) + for (unsigned int j = 0; j < initsize; ++j) { - elems[i] = LittleLong(chunk[3+i]); + elems[j] = LittleLong(chunk[3+j]); } } chunk = (DWORD *)NextChunk((BYTE *)chunk); From 5a8062abba7b5746d8c0ef8cb4160ce95a663ce2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 16 Jan 2016 09:05:46 +0100 Subject: [PATCH 318/335] - fixed copy/paste error in secmovefac. (It returned friction instead of movefactor...) --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 30cec2ad2..4132e90b5 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -545,7 +545,7 @@ inline fixed_t secfriction(const sector_t *sec, int plane = sector_t::floor) inline fixed_t secmovefac(const sector_t *sec, int plane = sector_t::floor) { - if (sec->Flags & SECF_FRICTION) return sec->friction; + if (sec->Flags & SECF_FRICTION) return sec->movefactor; fixed_t movefactor = Terrains[sec->GetTerrain(plane)].MoveFactor; return movefactor != 0 ? movefactor : ORIG_FRICTION_FACTOR; } From afed5e62ebe7b91970d6805a779ffdd77433fbdc Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 16 Jan 2016 13:21:15 +0200 Subject: [PATCH 319/335] Fixed intercept check in FPathTraverse Because frac variable has fixed_t type it must be compared with fixed one Test case: try to break stained glass windows or open door at the beginning of Hexen's MAP01 --- src/p_maputl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 85e9183c5..82907d10a 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -985,7 +985,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by) P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); - if (frac < 0 || frac > 1) continue; // behind source or beyond end point + if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point intercept_t newintercept; From 0e645ad173e21d2a7dbe109af66d98dfd2ca20ff Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 16 Jan 2016 16:30:53 +0100 Subject: [PATCH 320/335] - added a 'non-modify' mode to P_TeleportMove and let A_Respawn use that, rather than letting P_TeleportMove muck around with the actor properties and then have A_Respawn only partially and haphazardly restoring them afterward. --- src/p_local.h | 2 +- src/p_map.cpp | 59 ++++++++++++++++--------------- src/thingdef/thingdef_codeptr.cpp | 13 +------ 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 859722912..7e00276bd 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -464,7 +464,7 @@ bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); void P_ApplyTorque(AActor *mo); -bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters +bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor = true); // [RH] Added z and telefrag parameters void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); bool P_BounceWall (AActor *mo); diff --git a/src/p_map.cpp b/src/p_map.cpp index 4132e90b5..ce20c8430 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -376,7 +376,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) // //========================================================================== -bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag) +bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor) { FCheckPosition tmf; sector_t *oldsec = thing->Sector; @@ -455,37 +455,40 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra return false; } - // the move is ok, so link the thing into its new position - thing->SetOrigin(x, y, z); - thing->floorz = tmf.floorz; - thing->ceilingz = tmf.ceilingz; - thing->floorsector = tmf.floorsector; - thing->floorpic = tmf.floorpic; - thing->floorterrain = tmf.floorterrain; - thing->ceilingsector = tmf.ceilingsector; - thing->ceilingpic = tmf.ceilingpic; - thing->dropoffz = tmf.dropoffz; // killough 11/98 - thing->BlockingLine = NULL; - - if (thing->flags2 & MF2_FLOORCLIP) + if (modifyactor) { - thing->AdjustFloorClip(); - } + // the move is ok, so link the thing into its new position + thing->SetOrigin(x, y, z); + thing->floorz = tmf.floorz; + thing->ceilingz = tmf.ceilingz; + thing->floorsector = tmf.floorsector; + thing->floorpic = tmf.floorpic; + thing->floorterrain = tmf.floorterrain; + thing->ceilingsector = tmf.ceilingsector; + thing->ceilingpic = tmf.ceilingpic; + thing->dropoffz = tmf.dropoffz; // killough 11/98 + thing->BlockingLine = NULL; - if (thing == players[consoleplayer].camera) - { - R_ResetViewInterpolation(); - } + if (thing->flags2 & MF2_FLOORCLIP) + { + thing->AdjustFloorClip(); + } - thing->PrevX = x; - thing->PrevY = y; - thing->PrevZ = z; + if (thing == players[consoleplayer].camera) + { + R_ResetViewInterpolation(); + } - // If this teleport was caused by a move, P_TryMove() will handle the - // sector transition messages better than we can here. - if (!(thing->flags6 & MF6_INTRYMOVE)) - { - thing->CheckSectorTransition(oldsec); + thing->PrevX = x; + thing->PrevY = y; + thing->PrevZ = z; + + // If this teleport was caused by a move, P_TryMove() will handle the + // sector transition messages better than we can here. + if (!(thing->flags6 & MF6_INTRYMOVE)) + { + thing->CheckSectorTransition(oldsec); + } } return true; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 8343b79b8..5fcc69f4b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3023,18 +3023,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_TELEFRAG) { // [KS] DIE DIE DIE DIE erm *ahem* =) - oktorespawn = P_TeleportMove(self, self->x, self->y, self->z, true); - if (oktorespawn) - { // Need to do this over again, since P_TeleportMove() will redo - // it with the proper point-on-side calculation. - self->UnlinkFromWorld(); - self->LinkToWorld(true); - sector_t *sec = self->Sector; - self->dropoffz = - self->floorz = sec->floorplane.ZatPoint(self->x, self->y); - self->ceilingz = sec->ceilingplane.ZatPoint(self->x, self->y); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS); - } + oktorespawn = P_TeleportMove(self, self->x, self->y, self->z, true, false); } else { From e4a74e91fcd34f9ad0baf59e43d228529d2ddd48 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 16 Jan 2016 16:33:19 -0600 Subject: [PATCH 321/335] - Puffs should not spawn on floors or ceilings with sky flats without the SKYEXPLODE flag. - Added line horizon check for puffs as well. --- src/p_map.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index ce20c8430..b61c130ac 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -52,6 +52,7 @@ #include "p_conversation.h" #include "r_data/r_translate.h" #include "g_level.h" +#include "r_sky.h" CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO) @@ -4293,6 +4294,8 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + if (puff && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) + puff->Destroy(); } if (puff != NULL && puffDefaults->flags7 & MF7_FORCEDECAL && puff->DecalGenerator) SpawnShootDecal(puff, trace); @@ -4306,6 +4309,12 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + if (puff && !(puff->flags3 & MF3_SKYEXPLODE) && + (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) || + ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum)))) + { + puff->Destroy(); + } } } if (thepuff != NULL) From 421dcacb94a95f3f5468d6f54e11f1829a88953a Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Sat, 16 Jan 2016 16:36:42 -0600 Subject: [PATCH 322/335] Added NULL check to lines. --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b61c130ac..5feff237e 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4294,7 +4294,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); - if (puff && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) + if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) puff->Destroy(); } if (puff != NULL && puffDefaults->flags7 & MF7_FORCEDECAL && puff->DecalGenerator) From bfc116b2a4a64662b8c07eaf0053d1b3c7f9ae8b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 17 Jan 2016 11:51:46 +0200 Subject: [PATCH 323/335] Fixed exit crash on legacy OS X There is no need to close (and thus deallocate) console window explicitly This will be done by autorelease pool in application controller event loop OS X with GC and/or ARC was not affected by this issue Older versions like 10.4 or 10.5 crashed because of double deallocation --- src/posix/cocoa/st_console.h | 1 - src/posix/cocoa/st_console.mm | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h index 49b6e0547..6b6f01820 100644 --- a/src/posix/cocoa/st_console.h +++ b/src/posix/cocoa/st_console.h @@ -85,7 +85,6 @@ private: int m_netMaxPos; FConsoleWindow(); - ~FConsoleWindow(); void ExpandTextView(float height); diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index 342e251a3..e952d22d6 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -118,11 +118,6 @@ FConsoleWindow::FConsoleWindow() [m_window makeKeyAndOrderFront:nil]; } -FConsoleWindow::~FConsoleWindow() -{ - [m_window close]; -} - static FConsoleWindow* s_instance; From 24501dbc93ba866e48416ce9e1d7f918fbf66a8d Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 17 Jan 2016 11:58:44 +0200 Subject: [PATCH 324/335] Fixed copy to pasteboard on legacy OS X Copy/paste is now implemented using the method available on all supported versions This fixes 'unrecognized selector' exception on OS X 10.4 and 10.5 --- src/posix/cocoa/i_system.mm | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index f12ef18eb..498498d94 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -338,23 +338,17 @@ int I_FindAttr(findstate_t* const fileinfo) } -static NSString* GetPasteboardStringType() -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - return NSStringPboardType; -#else // 10.6 or higher - return NSAppKitVersionNumber < AppKit10_6 - ? NSStringPboardType - : NSPasteboardTypeString; -#endif // before 10.6 -} - void I_PutInClipboard(const char* const string) { NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; - [pasteBoard clearContents]; - [pasteBoard setString:[NSString stringWithUTF8String:string] - forType:GetPasteboardStringType()]; + NSString* const stringType = NSStringPboardType; + NSArray* const types = [NSArray arrayWithObjects:stringType, nil]; + NSString* const content = [NSString stringWithUTF8String:string]; + + [pasteBoard declareTypes:types + owner:nil]; + [pasteBoard setString:content + forType:stringType]; } FString I_GetFromClipboard(bool returnNothing) @@ -365,7 +359,7 @@ FString I_GetFromClipboard(bool returnNothing) } NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; - NSString* const value = [pasteBoard stringForType:GetPasteboardStringType()]; + NSString* const value = [pasteBoard stringForType:NSStringPboardType]; return FString([value UTF8String]); } From bf5ee5e54252838963441db6c35dffcd9284ba38 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 12:23:49 +0100 Subject: [PATCH 325/335] - added X(), Y(), Z() access functions to AActor. This commit is just preparation for upcoming changes to completely encapsulate the coordinate info in AActor because I'm going to have to work with an altered version of actor.h that cannot be committed without breaking the engine. With this file present in the repo before work is started the changes can be committed piece by piece. --- src/actor.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/actor.h b/src/actor.h index 114dd1179..846d1f0d9 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1155,6 +1155,20 @@ public: } bool HasSpecialDeathStates () const; + + fixed_t X() const + { + return x; + } + fixed_t Y() const + { + return y; + } + fixed_t Z() const + { + return z; + } + }; class FActorIterator From 552c440afa904174cb11796ba61f5628b9179e35 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 17 Jan 2016 13:29:44 +0200 Subject: [PATCH 326/335] Fixed another issue with Hexen Mac Hopefully there will be no more bugs with Hexen Mac IWADs (demo or full) as all extra lumps are now discarded --- src/w_wad.cpp | 59 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 552228557..42e5c17b9 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -961,8 +961,10 @@ void FWadCollection::RenameNerve () // // FixMacHexen // -// Rename unused high resolution font lumps because they are incorrectly -// treated as extended characters +// Discard all extra lumps in Mac version of Hexen IWAD (demo or full) +// to avoid any issues caused by names of these lumps, including: +// * Wrong height of small font +// * Broken life bar of mage class // //========================================================================== @@ -973,22 +975,51 @@ void FWadCollection::FixMacHexen() return; } - for (int i = GetFirstLump(IWAD_FILENUM), last = GetLastLump(IWAD_FILENUM); i <= last; ++i) + FileReader* const reader = GetFileReader(IWAD_FILENUM); + const long iwadSize = reader->GetLength(); + + static const long DEMO_SIZE = 13596228; + static const long FULL_SIZE = 21078584; + + if ( DEMO_SIZE != iwadSize + && FULL_SIZE != iwadSize) { - assert(IWAD_FILENUM == LumpInfo[i].wadnum); + return; + } - FResourceLump* const lump = LumpInfo[i].lump; - char* const name = lump->Name; + reader->Seek(0, SEEK_SET); - // Unwanted lumps are named like FONTA??1 + BYTE checksum[16]; + MD5Context md5; + md5.Update(reader, iwadSize); + md5.Final(checksum); - if (8 == strlen(name) - && MAKE_ID('F', 'O', 'N', 'T') == lump->dwName - && 'A' == name[4] && '1' == name[7] - && isdigit(name[5]) && isdigit(name[6])) - { - name[0] = '\0'; - } + static const BYTE HEXEN_DEMO_MD5[16] = + { + 0x92, 0x5f, 0x9f, 0x50, 0x00, 0xe1, 0x7d, 0xc8, + 0x4b, 0x0a, 0x6a, 0x3b, 0xed, 0x3a, 0x6f, 0x31 + }; + + static const BYTE HEXEN_FULL_MD5[16] = + { + 0xb6, 0x81, 0x40, 0xa7, 0x96, 0xf6, 0xfd, 0x7f, + 0x3a, 0x5d, 0x32, 0x26, 0xa3, 0x2b, 0x93, 0xbe + }; + + if ( 0 != memcmp(HEXEN_DEMO_MD5, checksum, sizeof checksum) + && 0 != memcmp(HEXEN_FULL_MD5, checksum, sizeof checksum)) + { + return; + } + + static const int EXTRA_LUMPS = 299; + + const int lastLump = GetLastLump(IWAD_FILENUM); + assert(GetFirstLump(IWAD_FILENUM) + 299 < lastLump); + + for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i) + { + LumpInfo[i].lump->Name[0] = '\0'; } } From 3e446ea04d35f8a9afb1b634a94143c9c0db69fa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 13:48:16 +0100 Subject: [PATCH 327/335] - replaced access to AActor's coordinate members with access functions (first 200 compile errors down...) --- src/am_map.cpp | 42 +++++++++++++++++----------------- src/b_func.cpp | 26 +++++++++++----------- src/b_move.cpp | 10 ++++----- src/b_think.cpp | 4 ++-- src/c_cmds.cpp | 4 ++-- src/d_dehacked.cpp | 2 +- src/d_net.cpp | 4 ++-- src/g_game.cpp | 6 ++--- src/m_cheat.cpp | 2 +- src/p_3dfloors.cpp | 14 ++++++------ src/p_3dmidtex.cpp | 6 ++--- src/p_acs.cpp | 20 ++++++++--------- src/p_effect.cpp | 6 ++--- src/p_enemy.cpp | 52 +++++++++++++++++++++---------------------- src/p_interaction.cpp | 6 ++--- src/p_lnspec.cpp | 4 ++-- src/p_things.cpp | 6 ++--- src/r_defs.h | 5 +++++ 18 files changed, 112 insertions(+), 107 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 606a65ae8..64d5420b0 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -998,8 +998,8 @@ void AM_restoreScaleAndLoc () } else { - m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS)- m_h/2; + m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS)- m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; @@ -1249,8 +1249,8 @@ void AM_initVariables () if (playeringame[pnum]) break; assert(pnum >= 0 && pnum < MAXPLAYERS); - m_x = (players[pnum].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[pnum].camera->y >> FRACTOMAPBITS) - m_h/2; + m_x = (players[pnum].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[pnum].camera->Y() >> FRACTOMAPBITS) - m_h/2; AM_changeWindowLoc(); // for saving & restoring @@ -1571,25 +1571,25 @@ void AM_doFollowPlayer () fixed_t sx, sy; if (players[consoleplayer].camera != NULL && - (f_oldloc.x != players[consoleplayer].camera->x || - f_oldloc.y != players[consoleplayer].camera->y)) + (f_oldloc.x != players[consoleplayer].camera->X() || + f_oldloc.y != players[consoleplayer].camera->Y())) { - m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS) - m_h/2; + m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; // do the parallax parchment scrolling. - sx = (players[consoleplayer].camera->x - f_oldloc.x) >> FRACTOMAPBITS; - sy = (f_oldloc.y - players[consoleplayer].camera->y) >> FRACTOMAPBITS; + sx = (players[consoleplayer].camera->X() - f_oldloc.x) >> FRACTOMAPBITS; + sy = (f_oldloc.y - players[consoleplayer].camera->Y()) >> FRACTOMAPBITS; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { AM_rotate (&sx, &sy, players[consoleplayer].camera->angle - ANG90); } AM_ScrollParchment (sx, sy); - f_oldloc.x = players[consoleplayer].camera->x; - f_oldloc.y = players[consoleplayer].camera->y; + f_oldloc.x = players[consoleplayer].camera->X(); + f_oldloc.y = players[consoleplayer].camera->Y(); } } @@ -2612,8 +2612,8 @@ void AM_drawPlayers () mline_t *arrow; int numarrowlines; - pt.x = players[consoleplayer].camera->x >> FRACTOMAPBITS; - pt.y = players[consoleplayer].camera->y >> FRACTOMAPBITS; + pt.x = players[consoleplayer].camera->X() >> FRACTOMAPBITS; + pt.y = players[consoleplayer].camera->Y() >> FRACTOMAPBITS; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { angle = ANG90; @@ -2675,8 +2675,8 @@ void AM_drawPlayers () if (p->mo != NULL) { - pt.x = p->mo->x >> FRACTOMAPBITS; - pt.y = p->mo->y >> FRACTOMAPBITS; + pt.x = p->mo->X() >> FRACTOMAPBITS; + pt.y = p->mo->Y() >> FRACTOMAPBITS; angle = p->mo->angle; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) @@ -2707,8 +2707,8 @@ void AM_drawKeys () while ((key = it.Next()) != NULL) { - p.x = key->x >> FRACTOMAPBITS; - p.y = key->y >> FRACTOMAPBITS; + p.x = key->X() >> FRACTOMAPBITS; + p.y = key->Y() >> FRACTOMAPBITS; angle = key->angle; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) @@ -2752,8 +2752,8 @@ void AM_drawThings () { if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP)) { - p.x = t->x >> FRACTOMAPBITS; - p.y = t->y >> FRACTOMAPBITS; + p.x = t->X() >> FRACTOMAPBITS; + p.y = t->Y() >> FRACTOMAPBITS; if (am_showthingsprites > 0 && t->sprite > 0) { @@ -2979,7 +2979,7 @@ void AM_drawAuthorMarkers () marked->subsector->flags & SSECF_DRAWN : marked->Sector->MoreFlags & SECF_DRAWN))) { - DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, + DrawMarker (tex, marked->X() >> FRACTOMAPBITS, marked->Y() >> FRACTOMAPBITS, 0, flip, mark->scaleX, mark->scaleY, mark->Translation, mark->alpha, mark->fillcolor, mark->RenderStyle); } diff --git a/src/b_func.cpp b/src/b_func.cpp index 9594d29d8..79518e82f 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -30,17 +30,17 @@ bool DBot::Reachable (AActor *rtarget) if (player->mo == rtarget) return false; - if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) - - rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y)) + if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget) - + rtarget->Sector->floorplane.ZatPoint (rtarget)) < player->mo->height) //Where rtarget is, player->mo can't be. return false; sector_t *last_s = player->mo->Sector; - fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y); + fixed_t last_z = last_s->floorplane.ZatPoint (player->mo); fixed_t estimated_dist = player->mo->AproxDistance(rtarget); bool reachable = true; - FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); + FPathTraverse it(player->mo->X()+player->mo->velx, player->mo->Y()+player->mo->vely, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS); intercept_t *in; while ((in = it.Next())) { @@ -96,7 +96,7 @@ bool DBot::Reachable (AActor *rtarget) thing = in->d.thing; if (thing == player->mo) //Can't reach self in this case. continue; - if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT))) + if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget) <= (last_z+MAXMOVEHEIGHT))) { return true; } @@ -219,7 +219,7 @@ void DBot::Dofire (ticcmd_t *cmd) shootmissile: dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; - bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); + bglobal.SetBodyAt (enemy->X() + enemy->velx*m*2, enemy->Y() + enemy->vely*m*2, enemy->Z(), 1); angle = player->mo->AngleTo(bglobal.body1); if (Check_LOS (enemy, SHOOTFOV)) no_fire = false; @@ -459,7 +459,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) //Emulates missile travel. Returns distance travelled. fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) { - AActor *th = Spawn ("CajunTrace", source->x, source->y, source->z + 4*8*FRACUNIT, NO_REPLACE); + AActor *th = Spawn ("CajunTrace", source->X(), source->Y(), source->Z() + 4*8*FRACUNIT, NO_REPLACE); th->target = source; // where it came from @@ -494,9 +494,9 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) AActor *actor; int m; - bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT), - player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT), - player->mo->z + (player->mo->height / 2), 2); + bglobal.SetBodyAt (player->mo->X() + FixedMul(player->mo->velx, 5*FRACUNIT), + player->mo->Y() + FixedMul(player->mo->vely, 5*FRACUNIT), + player->mo->Z() + (player->mo->height / 2), 2); actor = bglobal.body2; @@ -506,14 +506,14 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) //Predict. m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed); - bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)), - enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); + bglobal.SetBodyAt (enemy->X() + FixedMul(enemy->velx, (m+2*FRACUNIT)), + enemy->Y() + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); //try the predicted location if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile { FCheckPosition tm; - if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm)) + if (bglobal.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm)) { if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { diff --git a/src/b_move.cpp b/src/b_move.cpp index 5cacd5664..e0c49159e 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -67,8 +67,8 @@ bool DBot::Move (ticcmd_t *cmd) if ((unsigned)player->mo->movedir >= 8) I_Error ("Weird bot movedir!"); - tryx = player->mo->x + 8*xspeed[player->mo->movedir]; - tryy = player->mo->y + 8*yspeed[player->mo->movedir]; + tryx = player->mo->X() + 8*xspeed[player->mo->movedir]; + tryy = player->mo->Y() + 8*yspeed[player->mo->movedir]; try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd); @@ -282,7 +282,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm if ( !(thing->flags & MF_TELEPORT) && - tm.ceilingz - thing->z < thing->height) + tm.ceilingz - thing->Z() < thing->height) return false; // mobj must lower itself to fit // jump out of water @@ -290,7 +290,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm // maxstep=37*FRACUNIT; if ( !(thing->flags & MF_TELEPORT) && - (tm.floorz - thing->z > maxstep ) ) + (tm.floorz - thing->Z() > maxstep ) ) return false; // too big a step up @@ -346,7 +346,7 @@ void DBot::Pitch (AActor *target) double aim; double diff; - diff = target->z - player->mo->z; + diff = target->Z() - player->mo->Z(); aim = atan(diff / (double)player->mo->AproxDistance(target)); player->mo->pitch = -(int)(aim * ANGLE_180/M_PI); } diff --git a/src/b_think.cpp b/src/b_think.cpp index ced5b4b4e..de74c04db 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -303,8 +303,8 @@ void DBot::ThinkForMove (ticcmd_t *cmd) if (t_fight<(AFTERTICS/2)) player->mo->flags |= MF_DROPOFF; - oldx = player->mo->x; - oldy = player->mo->y; + oldx = player->mo->X(); + oldy = player->mo->Y(); } //BOT_WhatToGet diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 57290a98a..3cfbf1c65 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -944,7 +944,7 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { Printf ("%s at (%d,%d,%d)\n", mo->GetClass()->TypeName.GetChars(), - mo->x >> FRACBITS, mo->y >> FRACBITS, mo->z >> FRACBITS); + mo->X() >> FRACBITS, mo->Y() >> FRACBITS, mo->Z() >> FRACBITS); } } } @@ -1084,7 +1084,7 @@ CCMD(currentpos) { AActor *mo = players[consoleplayer].mo; Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n", - FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); + FIXED2FLOAT(mo->X()), FIXED2FLOAT(mo->Y()), FIXED2FLOAT(mo->Z()), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); } //----------------------------------------------------------------------------- diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index bc0acc666..31ff05b64 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3056,7 +3056,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher) { return false; } - RealPickup = static_cast(Spawn (type, x, y, z, NO_REPLACE)); + RealPickup = static_cast(Spawn (type, X(), Y(), Z(), NO_REPLACE)); if (RealPickup != NULL) { // The internally spawned item should never count towards statistics. diff --git a/src/d_net.cpp b/src/d_net.cpp index 780b89382..2b7a2d3d9 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2373,8 +2373,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) s = ReadString (stream); - if (Trace (players[player].mo->x, players[player].mo->y, - players[player].mo->z + players[player].mo->height - (players[player].mo->height>>2), + if (Trace (players[player].mo->X(), players[player].mo->Y(), + players[player].mo->Z() + players[player].mo->height - (players[player].mo->height>>2), players[player].mo->Sector, vx, vy, vz, 172*FRACUNIT, 0, ML_BLOCKEVERYTHING, players[player].mo, trace, TRACE_NoSky)) diff --git a/src/g_game.cpp b/src/g_game.cpp index b7d10251b..aa2ba0ab8 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1176,7 +1176,7 @@ void G_Ticker () } if (players[i].mo) { - DWORD sum = rngsum + players[i].mo->x + players[i].mo->y + players[i].mo->z + DWORD sum = rngsum + players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z() + players[i].mo->angle + players[i].mo->pitch; sum ^= players[i].health; consistancy[i][buf] = sum; @@ -1435,12 +1435,12 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) if (!players[playernum].mo) { // first spawn of level, before corpses for (i = 0; i < playernum; i++) - if (players[i].mo && players[i].mo->x == x && players[i].mo->y == y) + if (players[i].mo && players[i].mo->X() == x && players[i].mo->Y() == y) return false; return true; } - oldz = players[playernum].mo->z; // [RH] Need to save corpse's z-height + oldz = players[playernum].mo->Z(); // [RH] Need to save corpse's z-height players[playernum].mo->z = z; // [RH] Checks are now full 3-D // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index ab9c0aee7..3bab8f7e5 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -580,7 +580,7 @@ void GiveSpawner (player_t *player, const PClass *type, int amount) } AInventory *item = static_cast - (Spawn (type, player->mo->x, player->mo->y, player->mo->z, NO_REPLACE)); + (Spawn (type, player->mo->X(), player->mo->Y(), player->mo->Z(), NO_REPLACE)); if (item != NULL) { if (amount > 0) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 496809fac..a9af52724 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -331,13 +331,13 @@ void P_PlayerOnSpecial3DFloor(player_t* player) if(rover->flags & FF_SOLID) { // Player must be on top of the floor to be affected... - if(player->mo->z != rover->top.plane->ZatPoint(player->mo->x, player->mo->y)) continue; + if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue; } else { //Water and DEATH FOG!!! heh - if (player->mo->z > rover->top.plane->ZatPoint(player->mo->x, player->mo->y) || - (player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y)) + if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || + (player->mo->Z() + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo)) continue; } @@ -372,7 +372,7 @@ bool P_CheckFor3DFloorHit(AActor * mo) if(rover->flags & FF_SOLID && rover->model->SecActTarget) { - if(mo->floorz == rover->top.plane->ZatPoint(mo->x, mo->y)) + if(mo->floorz == rover->top.plane->ZatPoint(mo)) { rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); return true; @@ -402,7 +402,7 @@ bool P_CheckFor3DCeilingHit(AActor * mo) if(rover->flags & FF_SOLID && rover->model->SecActTarget) { - if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo)) { rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); return true; @@ -748,7 +748,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { fixed_t thingbot, thingtop; - thingbot = thing->z; + thingbot = thing->Z(); thingtop = thingbot + (thing->height==0? 1:thing->height); extsector_t::xfloor *xf[2] = {&linedef->frontsector->e->XFloor, &linedef->backsector->e->XFloor}; @@ -789,7 +789,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li lowestceilingpic = *rover->bottom.texture; } - if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->z >= ff_top)) + if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->Z() >= ff_top)) { highestfloor = ff_top; highestfloorpic = *rover->top.texture; diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index dbca50d10..3338956f3 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -276,7 +276,7 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & open.abovemidtex = false; if (P_GetMidTexturePosition(linedef, 0, &tt, &tb)) { - if (thing->z + (thing->height/2) < (tt + tb)/2) + if (thing->Z() + (thing->height/2) < (tt + tb)/2) { if (tb < open.top) { @@ -286,7 +286,7 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & } else { - if (tt > open.bottom && (!restrict || thing->z >= tt)) + if (tt > open.bottom && (!restrict || thing->Z() >= tt)) { open.bottom = tt; open.abovemidtex = true; @@ -295,7 +295,7 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & } // returns true if it touches the midtexture - return (abs(thing->z - tt) <= thing->MaxStepHeight); + return (abs(thing->Z() - tt) <= thing->MaxStepHeight); } } return false; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6f136d98b..8c8c0a5f1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3441,12 +3441,12 @@ int DLevelScript::DoSpawnSpot (int type, int spot, int tid, int angle, bool forc while ( (aspot = iterator.Next ()) ) { - spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, angle, force); + spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, angle, force); } } else if (activator != NULL) { - spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, angle, force); + spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, angle, force); } return spawned; } @@ -3462,12 +3462,12 @@ int DLevelScript::DoSpawnSpotFacing (int type, int spot, int tid, bool force) while ( (aspot = iterator.Next ()) ) { - spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, aspot->angle >> 24, force); + spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, aspot->angle >> 24, force); } } else if (activator != NULL) { - spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, activator->angle >> 24, force); + spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, activator->angle >> 24, force); } return spawned; } @@ -4145,7 +4145,7 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b F3DFloor *ff = sec->e->XFloor.ffloors[i]; if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - actor->z >= ff->top.plane->ZatPoint(actor->x, actor->y)) + actor->Z() >= ff->top.plane->ZatPoint(actor)) { // This floor is beneath our feet. secpic = *ff->top.texture; break; @@ -4158,14 +4158,14 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b } else { - fixed_t z = actor->z + actor->height; + fixed_t z = actor->Z() + actor->height; // Looking through planes from bottom to top for (i = numff-1; i >= 0; --i) { F3DFloor *ff = sec->e->XFloor.ffloors[i]; if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - z <= ff->bottom.plane->ZatPoint(actor->x, actor->y)) + z <= ff->bottom.plane->ZatPoint(actor)) { // This floor is above our eyes. secpic = *ff->bottom.texture; break; @@ -4728,8 +4728,8 @@ static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, an { angle += actor->angle; } - return NULL != ShootDecal(tpl, actor, actor->Sector, actor->x, actor->y, - actor->z + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, + return NULL != ShootDecal(tpl, actor, actor->Sector, actor->X(), actor->Y(), + actor->Z() + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, angle, distance, !!(flags & SDF_PERMANENT)); } @@ -8598,7 +8598,7 @@ scriptwait: } else if (pcd == PCD_GETACTORZ) { - STACK(1) = actor->z + actor->GetBobOffset(); + STACK(1) = actor->Z() + actor->GetBobOffset(); } else { diff --git a/src/p_effect.cpp b/src/p_effect.cpp index db3129521..0f04de8eb 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -619,8 +619,8 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto double r; double dirz; - if (abs(mo->x - FLOAT2FIXED(start.X)) < 20 * FRACUNIT - && (mo->y - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT) + if (abs(mo->X() - FLOAT2FIXED(start.X)) < 20 * FRACUNIT + && (mo->Y() - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT) { // This player (probably) fired the railgun S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM); } @@ -630,7 +630,7 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto // Only consider sound in 2D (for now, anyway) // [BB] You have to divide by lengthsquared here, not multiply with it. - r = ((start.Y - FIXED2DBL(mo->y)) * (-dir.Y) - (start.X - FIXED2DBL(mo->x)) * (dir.X)) / lengthsquared; + r = ((start.Y - FIXED2DBL(mo->Y())) * (-dir.Y) - (start.X - FIXED2DBL(mo->X())) * (dir.X)) / lengthsquared; r = clamp(r, 0., 1.); dirz = dir.Z; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 7b7e27b2e..165ac35a1 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -243,9 +243,9 @@ bool AActor::CheckMeleeRange () // [RH] Don't melee things too far above or below actor. if (!(flags5 & MF5_NOVERTICALMELEERANGE)) { - if (pl->z > z + height) + if (pl->Z() > z + height) return false; - if (pl->z + pl->height < z) + if (pl->Z() + pl->height < z) return false; } @@ -280,11 +280,11 @@ bool P_CheckMeleeRange2 (AActor *actor) { return false; } - if (mo->z > actor->z+actor->height) + if (mo->Z() > actor->Z()+actor->height) { // Target is higher than the attacker return false; } - else if (actor->z > mo->z+mo->height) + else if (actor->Z() > mo->Z()+mo->height) { // Attacker is higher return false; } @@ -434,7 +434,7 @@ bool P_Move (AActor *actor) // it difficult to thrust them vertically in a reasonable manner. // [GZ] Let jumping actors jump. if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) - && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) + && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { return false; } @@ -538,11 +538,11 @@ bool P_Move (AActor *actor) // actually walking down a step. if (try_ok && !((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) - && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) + && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { - if (actor->z <= actor->floorz + actor->MaxStepHeight) + if (actor->Y() <= actor->floorz + actor->MaxStepHeight) { - fixed_t savedz = actor->z; + fixed_t savedz = actor->Z(); actor->z = actor->floorz; // Make sure that there isn't some other actor between us and // the floor we could get stuck in. The old code did not do this. @@ -553,7 +553,7 @@ bool P_Move (AActor *actor) else { // The monster just hit the floor, so trigger any actions. if (actor->floorsector->SecActTarget != NULL && - actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->x, actor->y)) + actor->floorz == actor->floorsector->floorplane.ZatPoint(actor)) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } @@ -566,7 +566,7 @@ bool P_Move (AActor *actor) { if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok) { // must adjust height - fixed_t savedz = actor->z; + fixed_t savedz = actor->Z(); if (actor->z < tm.floorz) actor->z += actor->FloatSpeed; @@ -847,11 +847,11 @@ void P_NewChaseDir(AActor * actor) // Try to move away from a dropoff if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight && - actor->z <= actor->floorz && !(actor->flags & MF_DROPOFF) && + actor->Z() <= actor->floorz && !(actor->flags & MF_DROPOFF) && !(actor->flags2 & MF2_ONMOBJ) && !(actor->flags & MF_FLOAT) && !(i_compatflags & COMPATF_DROPOFF)) { - FBoundingBox box(actor->x, actor->y, actor->radius); + FBoundingBox box(actor->X(), actor->Y(), actor->radius); FBlockLinesIterator it(box); line_t *line; @@ -866,14 +866,14 @@ void P_NewChaseDir(AActor * actor) box.Bottom() < line->bbox[BOXTOP] && box.BoxOnLineSide(line) == -1) { - fixed_t front = line->frontsector->floorplane.ZatPoint(actor->x,actor->y); - fixed_t back = line->backsector->floorplane.ZatPoint(actor->x,actor->y); + fixed_t front = line->frontsector->floorplane.ZatPoint(actor); + fixed_t back = line->backsector->floorplane.ZatPoint(actor); angle_t angle; // The monster must contact one of the two floors, // and the other must be a tall dropoff. - if (back == actor->z && front < actor->z - actor->MaxDropOffHeight) + if (back == actor->Z() && front < actor->Z() - actor->MaxDropOffHeight) { angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff } @@ -2551,11 +2551,11 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if (testsec) { fixed_t zdist1, zdist2; - if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) - != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + if (P_Find3DFloor(testsec, corpsehit->X(), corpsehit->Y(), corpsehit->Z(), false, true, zdist1) + != P_Find3DFloor(testsec, self->X(), self->Y(), self->Z(), false, true, zdist2)) { // Not on same floor - if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) + if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height) continue; } } @@ -2569,7 +2569,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) corpsehit->flags |= MF_SOLID; corpsehit->height = corpsehit->GetDefault()->height; - bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y); + bool check = P_CheckPosition(corpsehit, corpsehit->X(), corpsehit->Y()); corpsehit->flags = oldflags; corpsehit->radius = oldradius; corpsehit->height = oldheight; @@ -2792,19 +2792,19 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a // If the target z is above the target's head, reposition to the middle of // its body. - if (target_z >= other->z + other->height) + if (target_z >= other->Z() + other->height) { - target_z = other->z + (other->height / 2); + target_z = other->Z() + (other->height / 2); } //Note there is no +32*FRACUNIT on purpose. This is for customization sake. //If one doesn't want this behavior, just don't use FAF_BOTTOM. if (flags & FAF_BOTTOM) - target_z = other->z + other->GetBobOffset(); + target_z = other->Z() + other->GetBobOffset(); if (flags & FAF_MIDDLE) - target_z = other->z + (other->height / 2) + other->GetBobOffset(); + target_z = other->Z() + (other->height / 2) + other->GetBobOffset(); if (flags & FAF_TOP) - target_z = other->z + (other->height) + other->GetBobOffset(); + target_z = other->Z() + (other->height) + other->GetBobOffset(); if (!(flags & FAF_NODISTFACTOR)) target_z += pitch_offset; @@ -3072,7 +3072,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int AActor *mo; fixed_t spawnz; - spawnz = source->z; + spawnz = source->Z(); if (!(i_compatflags & COMPATF_NOTOSSDROPS)) { int style = sv_dropstyle; @@ -3087,7 +3087,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int spawnz += source->height / 2; } } - mo = Spawn (type, source->x, source->y, spawnz, ALLOW_REPLACE); + mo = Spawn (type, source->X(), source->Y(), spawnz, ALLOW_REPLACE); if (mo != NULL) { mo->flags |= MF_DROPPED; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 5534fb14a..0c61b2d7d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -84,7 +84,7 @@ FName MeansOfDeath; // void P_TouchSpecialThing (AActor *special, AActor *toucher) { - fixed_t delta = special->z - toucher->z; + fixed_t delta = special->Z() - toucher->Z(); // The pickup is at or above the toucher's feet OR // The pickup is below the toucher. @@ -1158,7 +1158,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // If the origin and target are in exactly the same spot, choose a random direction. // (Most likely cause is from telefragging somebody during spawning because they // haven't moved from their spawn spot at all.) - if (origin->x == target->x && origin->y == target->y) + if (origin->X() == target->X() && origin->Y() == target->Y()) { ang = pr_kickbackdir.GenRand32(); } @@ -1184,7 +1184,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // make fall forwards sometimes if ((damage < 40) && (damage > target->health) - && (target->z - origin->z > 64*FRACUNIT) + && (target->Z() - origin->Z() > 64*FRACUNIT) && (pr_damagemobj()&1) // [RH] But only if not too fast and not flying && thrust < 10*FRACUNIT diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 53090ef18..22e901c73 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -148,7 +148,7 @@ FUNC(LS_Polyobj_MoveToSpot) FActorIterator iterator (arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, false); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), false); } FUNC(LS_Polyobj_DoorSwing) @@ -199,7 +199,7 @@ FUNC(LS_Polyobj_OR_MoveToSpot) FActorIterator iterator (arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, true); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), true); } FUNC(LS_Polyobj_Stop) diff --git a/src/p_things.cpp b/src/p_things.cpp index 631f1be5e..e8f9d6011 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -82,7 +82,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, } while (spot != NULL) { - mobj = Spawn (kind, spot->x, spot->y, spot->z, ALLOW_REPLACE); + mobj = Spawn (kind, spot->X(), spot->Y(), spot->Z(), ALLOW_REPLACE); if (mobj != NULL) { @@ -94,7 +94,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, mobj->angle = (angle != ANGLE_MAX ? angle : spot->angle); if (fog) { - P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false, true); + P_SpawnTeleportFog(mobj, spot->X(), spot->Y(), spot->Z() + TELEFOGHEIGHT, false, true); } if (mobj->flags & MF_SPECIAL) mobj->flags |= MF_DROPPED; // Don't respawn @@ -165,7 +165,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog) if (source != NULL && target != NULL) { - return P_MoveThing(source, target->x, target->y, target->z, fog); + return P_MoveThing(source, target->X(), target->Y(), target->Z(), fog); } return false; } diff --git a/src/r_defs.h b/src/r_defs.h index 05fd7bd03..6f69a26a0 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -248,6 +248,11 @@ struct secplane_t return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y)); } + fixed_t ZatPoint (const AActor *ac) const + { + return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y())); + } + // Returns the value of z at (x,y) if d is equal to dist fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const { From 87689d3ba69e884e142602fba3ce210749daca6d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 14:08:20 +0100 Subject: [PATCH 328/335] - global search&replace of ZatPoint calls with commonly named actor variables. --- src/g_heretic/a_hereticweaps.cpp | 2 +- src/g_strife/a_strifestuff.cpp | 2 +- src/p_map.cpp | 36 ++++++++++++++++---------------- src/p_mobj.cpp | 16 +++++++------- src/p_spec.cpp | 12 +++++------ src/po_man.cpp | 4 ++-- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 711bbd960..247ccb03f 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -1099,7 +1099,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) F3DFloor * rover = self->Sector->e->XFloor.ffloors[i]; if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height)) + if ((foo = rover->bottom.plane->ZatPoint(self)) >= (self->z + self->height)) { self->z = foo + 4*FRACUNIT; self->bouncecount = i; diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 05f6367dc..9f3ebb272 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -628,7 +628,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { sector_t *sec = self->Sector; - if (self->z == sec->floorplane.ZatPoint (self->x, self->y)) + if (self->z == sec->floorplane.ZatPoint(self)) { if (sec->special == Damage_InstantDeath) { diff --git a/src/p_map.cpp b/src/p_map.cpp index 5feff237e..78a17df10 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -593,8 +593,8 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_SWIMMABLE)) continue; - if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || - mo->z < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if (mo->z > rover->top.plane->ZatPoint(mo) || + mo->z < rover->bottom.plane->ZatPoint(mo)) continue; newfriction = secfriction(rover->model, rover->top.isceiling); @@ -623,13 +623,13 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) if (rover->flags & FF_SOLID) { // Must be standing on a solid floor - if (mo->z != rover->top.plane->ZatPoint(mo->x, mo->y)) continue; + if (mo->z != rover->top.plane->ZatPoint(mo)) continue; } else if (rover->flags & FF_SWIMMABLE) { // Or on or inside a swimmable floor (e.g. in shallow water) - if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || - (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if (mo->z > rover->top.plane->ZatPoint(mo) || + (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo)) continue; } else @@ -650,9 +650,9 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) } newfriction = secfriction(sec); if ((newfriction < friction || friction == ORIG_FRICTION) && - (mo->z <= sec->floorplane.ZatPoint(mo->x, mo->y) || + (mo->z <= sec->floorplane.ZatPoint(mo) || (sec->GetHeightSec() != NULL && - mo->z <= sec->heightsec->floorplane.ZatPoint(mo->x, mo->y)))) + mo->z <= sec->heightsec->floorplane.ZatPoint(mo)))) { friction = newfriction; movefactor = secmovefac(sec); @@ -1798,10 +1798,10 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. - fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj->x, mobj->y); - fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj->x, mobj->y); - fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj->x, mobj->y); - fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj->x, mobj->y); + fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj); + fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj); + fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj); + fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj); if (fzt >= mobj->z + mobj->height && bzt >= mobj->z + mobj->height && fzb <= mobj->z && bzb <= mobj->z) { @@ -1812,8 +1812,8 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj->x, mobj->y); - fixed_t ff_top = rover->top.plane->ZatPoint(mobj->x, mobj->y); + fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj); + fixed_t ff_top = rover->top.plane->ZatPoint(mobj); if (ff_bottom < mobj->z + mobj->height && ff_top > mobj->z) { @@ -2083,8 +2083,8 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, { fixed_t eyez = oldz + viewheight; - oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing->x, thing->y); - oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing->x, thing->y); + oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing); + oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing); } // Borrowed from MBF: @@ -2743,14 +2743,14 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov } const secplane_t *plane = &actor->floorsector->floorplane; - fixed_t planezhere = plane->ZatPoint(actor->x, actor->y); + fixed_t planezhere = plane->ZatPoint(actor); for (unsigned int i = 0; ifloorsector->e->XFloor.ffloors.Size(); i++) { F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i]; if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y); + fixed_t thisplanez = rover->top.plane->ZatPoint(actor); if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight) { @@ -2768,7 +2768,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov F3DFloor * rover = actor->Sector->e->XFloor.ffloors[i]; if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y); + fixed_t thisplanez = rover->top.plane->ZatPoint(actor); if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bcaa77855..1c5105235 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2077,7 +2077,7 @@ explode: if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - mo->z >= tm.ceilingline->backsector->ceilingplane.ZatPoint (mo->x, mo->y)) + mo->z >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo)) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. @@ -2161,7 +2161,7 @@ explode: { // Don't stop sliding if halfway off a step with some velocity if (mo->velx > FRACUNIT/4 || mo->velx < -FRACUNIT/4 || mo->vely > FRACUNIT/4 || mo->vely < -FRACUNIT/4) { - if (mo->floorz > mo->Sector->floorplane.ZatPoint (mo->x, mo->y)) + if (mo->floorz > mo->Sector->floorplane.ZatPoint(mo)) { if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded { @@ -2407,7 +2407,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // Hit the floor if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) && mo->Sector->SecActTarget != NULL && - mo->Sector->floorplane.ZatPoint (mo->x, mo->y) == mo->floorz) + mo->Sector->floorplane.ZatPoint(mo) == mo->floorz) { // [RH] Let the sector do something to the actor mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); } @@ -2509,7 +2509,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // hit the ceiling if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) && mo->Sector->SecActTarget != NULL && - mo->Sector->ceilingplane.ZatPoint (mo->x, mo->y) == mo->ceilingz) + mo->Sector->ceilingplane.ZatPoint(mo) == mo->ceilingz) { // [RH] Let the sector do something to the actor mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); } @@ -2564,7 +2564,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh if (sec->heightsec != NULL && sec->SecActTarget != NULL) { sector_t *hs = sec->heightsec; - fixed_t waterz = hs->floorplane.ZatPoint (mo->x, mo->y); + fixed_t waterz = hs->floorplane.ZatPoint(mo); fixed_t newz; fixed_t viewheight; @@ -2599,7 +2599,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh if (!(hs->MoreFlags & SECF_FAKEFLOORONLY)) { - waterz = hs->ceilingplane.ZatPoint (mo->x, mo->y); + waterz = hs->ceilingplane.ZatPoint(mo); if (oldz <= waterz && newz > waterz) { // View went above fake ceiling sec->SecActTarget->TriggerAction (mo, SECSPAC_EyesAboveC); @@ -5493,7 +5493,7 @@ bool P_HitFloor (AActor *thing) // don't splash if landing on the edge above water/lava/etc.... for (m = thing->touching_sectorlist; m; m = m->m_tnext) { - if (thing->z == m->m_sector->floorplane.ZatPoint (thing->x, thing->y)) + if (thing->z == m->m_sector->floorplane.ZatPoint(thing)) { break; } @@ -5505,7 +5505,7 @@ bool P_HitFloor (AActor *thing) if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & (FF_SOLID|FF_SWIMMABLE)) { - if (rover->top.plane->ZatPoint(thing->x, thing->y) == thing->z) + if (rover->top.plane->ZatPoint(thing) == thing->z) { return P_HitWater (thing, m->m_sector); } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 36d5f3bab..baec6d9e1 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -430,7 +430,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { // Falling, not all the way down yet? sector = player->mo->Sector; - if (player->mo->z != sector->floorplane.ZatPoint (player->mo->x, player->mo->y) + if (player->mo->z != sector->floorplane.ZatPoint(player->mo) && !player->mo->waterlevel) { return; @@ -507,7 +507,7 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL) return; - if (!(flags & DAMAGE_IN_AIR) && actor->z != sec->floorplane.ZatPoint(actor->x, actor->y) && !actor->waterlevel) + if (!(flags & DAMAGE_IN_AIR) && actor->z != sec->floorplane.ZatPoint(actor) && !actor->waterlevel) return; if (protectClass != NULL) @@ -544,8 +544,8 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, { next = actor->snext; // Only affect actors touching the 3D floor - fixed_t z1 = sec->floorplane.ZatPoint(actor->x, actor->y); - fixed_t z2 = sec->ceilingplane.ZatPoint(actor->x, actor->y); + fixed_t z1 = sec->floorplane.ZatPoint(actor); + fixed_t z2 = sec->ceilingplane.ZatPoint(actor); if (z2 < z1) { // Account for Vavoom-style 3D floors @@ -2281,7 +2281,7 @@ void DPusher::Tick () } else // special water sector { - ht = hsec->floorplane.ZatPoint (thing->x, thing->y); + ht = hsec->floorplane.ZatPoint(thing); if (thing->z > ht) // above ground { xspeed = m_Xmag; // full force @@ -2310,7 +2310,7 @@ void DPusher::Tick () { // special water sector floor = &hsec->floorplane; } - if (thing->z > floor->ZatPoint (thing->x, thing->y)) + if (thing->z > floor->ZatPoint(thing)) { // above ground xspeed = yspeed = 0; // no force } diff --git a/src/po_man.cpp b/src/po_man.cpp index 98fbbcbcb..fb1d12519 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1238,8 +1238,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) } // [BL] See if we hit below the floor/ceiling of the poly. else if(!performBlockingThrust && ( - mobj->z < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj->x, mobj->y) || - mobj->z + mobj->height > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj->x, mobj->y) + mobj->z < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj) || + mobj->z + mobj->height > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj) )) { performBlockingThrust = true; From 5b610390e1d58fd8d026aed6d0978a041fa2ec0f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 16:49:15 +0100 Subject: [PATCH 329/335] - some more inline functions. --- src/actor.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/actor.h b/src/actor.h index 846d1f0d9..137687e66 100644 --- a/src/actor.h +++ b/src/actor.h @@ -588,6 +588,36 @@ enum AMETA_BloodType3, // AxeBlood replacement type }; +struct fixedvec3 +{ + fixed_t x, y, z; + + operator FVector3() + { + return FVector3(FIXED2FLOAT(x), FIXED2FLOAT(y), FIXED2FLOAT(z)); + } + + operator TVector3() + { + return TVector3(FIXED2DBL(x), FIXED2DBL(y), FIXED2DBL(z)); + } +}; + +struct fixedvec2 +{ + fixed_t x, y; + + operator FVector2() + { + return FVector2(FIXED2FLOAT(x), FIXED2FLOAT(y)); + } + + operator TVector2() + { + return TVector2(FIXED2DBL(x), FIXED2DBL(y)); + } +}; + struct FDropItem { FName Name; @@ -909,6 +939,18 @@ public: return R_PointToAngle2(myx, myy, other->x, other->y); } + fixedvec2 Vec2To(AActor *other) const + { + fixedvec2 ret = { other->x - x, other->y - y }; + return ret; + } + + fixedvec3 Vec3To(AActor *other) const + { + fixedvec3 ret = { other->x - x, other->y - y, other->z - z }; + return ret; + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; From c6114563974e8bdcfbf2de471d90112b646fbf0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 18:36:14 +0100 Subject: [PATCH 330/335] - more refactoring of AActor coordinate access. --- src/actor.h | 44 ++++++++++++++++++++++++++++++++- src/b_func.cpp | 13 ++++------ src/b_move.cpp | 18 ++++++-------- src/d_net.cpp | 10 +++++--- src/g_game.cpp | 4 +-- src/p_3dfloors.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_effect.cpp | 61 +++++++++++++++++++++++++++++----------------- src/p_maputl.cpp | 2 +- 9 files changed, 105 insertions(+), 51 deletions(-) diff --git a/src/actor.h b/src/actor.h index 137687e66..22bea9e08 100644 --- a/src/actor.h +++ b/src/actor.h @@ -951,6 +951,23 @@ public: return ret; } + fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy) const + { + fixedvec2 ret = { x + dx, y + dy }; + return ret; + } + + fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz) const + { + fixedvec3 ret = { x + dx, y + dy, z + dz }; + return ret; + } + + void Move(fixed_t dx, fixed_t dy, fixed_t dz) + { + SetOrigin(x + dx, y + dy, z + dz, true); + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; @@ -1168,7 +1185,7 @@ public: void LinkToWorld (sector_t *sector); void UnlinkFromWorld (); void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false); bool InStateSequence(FState * newstate, FState * basestate); int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); @@ -1210,6 +1227,10 @@ public: { return z; } + void SetZ(fixed_t newz) + { + z = newz; + } }; @@ -1284,15 +1305,36 @@ inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, repla return AActor::StaticSpawn (type, x, y, z, allowreplacement); } +inline AActor *Spawn (const PClass *type, const fixedvec3 &pos, replace_t allowreplacement) +{ + return AActor::StaticSpawn (type, pos.x, pos.y, pos.z, allowreplacement); +} + AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); +inline AActor *Spawn (const char *type, const fixedvec3 &pos, replace_t allowreplacement) +{ + return Spawn (type, pos.x, pos.y, pos.z, allowreplacement); +} + +inline AActor *Spawn (FName classname, const fixedvec3 &pos, replace_t allowreplacement) +{ + return Spawn (classname, pos.x, pos.y, pos.z, allowreplacement); +} + + template inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); } +template +inline T *Spawn (const fixedvec3 &pos, replace_t allowreplacement) +{ + return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), pos.x, pos.y, pos.z, allowreplacement)); +} void PrintMiscActorInfo(AActor * query); diff --git a/src/b_func.cpp b/src/b_func.cpp index 79518e82f..cc8d9808a 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -427,7 +427,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) { if (body1) { - body1->SetOrigin (x, y, z); + body1->SetOrigin (x, y, z, false); } else { @@ -438,7 +438,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) { if (body2) { - body2->SetOrigin (x, y, z); + body2->SetOrigin (x, y, z, false); } else { @@ -465,10 +465,7 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) float speed = (float)th->Speed; - FVector3 velocity; - velocity[0] = FIXED2FLOAT(dest->x - source->x); - velocity[1] = FIXED2FLOAT(dest->y - source->y); - velocity[2] = FIXED2FLOAT(dest->z - source->z); + TVector3 velocity = source->Vec3To(dest); velocity.MakeUnit(); th->velx = FLOAT2FIXED(velocity[0] * speed); th->vely = FLOAT2FIXED(velocity[1] * speed); @@ -479,8 +476,8 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) while (dist < SAFE_SELF_MISDIST) { dist += th->Speed; - th->SetOrigin (th->x + th->velx, th->y + th->vely, th->z + th->velz); - if (!CleanAhead (th, th->x, th->y, cmd)) + th->Move(th->velx, th->vely, th->velz); + if (!CleanAhead (th, th->X(), th->Y(), cmd)) break; } th->Destroy (); diff --git a/src/b_move.cpp b/src/b_move.cpp index e0c49159e..cee409265 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -124,9 +124,6 @@ bool DBot::TryWalk (ticcmd_t *cmd) void DBot::NewChaseDir (ticcmd_t *cmd) { - fixed_t deltax; - fixed_t deltay; - dirtype_t d[3]; int tdir; @@ -145,19 +142,18 @@ void DBot::NewChaseDir (ticcmd_t *cmd) olddir = (dirtype_t)player->mo->movedir; turnaround = opposite[olddir]; - deltax = dest->x - player->mo->x; - deltay = dest->y - player->mo->y; + fixedvec2 delta = player->mo->Vec2To(dest); - if (deltax > 10*FRACUNIT) + if (delta.x > 10*FRACUNIT) d[1] = DI_EAST; - else if (deltax < -10*FRACUNIT) + else if (delta.x < -10*FRACUNIT) d[1] = DI_WEST; else d[1] = DI_NODIR; - if (deltay < -10*FRACUNIT) + if (delta.y < -10*FRACUNIT) d[2] = DI_SOUTH; - else if (deltay > 10*FRACUNIT) + else if (delta.y > 10*FRACUNIT) d[2] = DI_NORTH; else d[2] = DI_NODIR; @@ -165,14 +161,14 @@ void DBot::NewChaseDir (ticcmd_t *cmd) // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)]; + player->mo->movedir = diags[((delta.y<0)<<1)+(delta.x>0)]; if (player->mo->movedir != turnaround && TryWalk(cmd)) return; } // try other directions if (pr_botnewchasedir() > 200 - || abs(deltay)>abs(deltax)) + || abs(delta.y)>abs(delta.x)) { tdir=d[1]; d[1]=d[2]; diff --git a/src/d_net.cpp b/src/d_net.cpp index 2b7a2d3d9..95061d0e1 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2319,10 +2319,12 @@ void Net_DoCommand (int type, BYTE **stream, int player) else { const AActor *def = GetDefaultByType (typeinfo); - AActor *spawned = Spawn (typeinfo, - source->x + FixedMul (def->radius * 2 + source->radius, finecosine[source->angle>>ANGLETOFINESHIFT]), - source->y + FixedMul (def->radius * 2 + source->radius, finesine[source->angle>>ANGLETOFINESHIFT]), - source->z + 8 * FRACUNIT, ALLOW_REPLACE); + fixedvec3 spawnpos = source->Vec3Offset( + FixedMul (def->radius * 2 + source->radius, finecosine[source->angle>>ANGLETOFINESHIFT]), + FixedMul (def->radius * 2 + source->radius, finesine[source->angle>>ANGLETOFINESHIFT]), + 8 * FRACUNIT); + + AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE); if (spawned != NULL) { if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF) diff --git a/src/g_game.cpp b/src/g_game.cpp index aa2ba0ab8..ca2233cdb 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1441,7 +1441,7 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) } oldz = players[playernum].mo->Z(); // [RH] Need to save corpse's z-height - players[playernum].mo->z = z; // [RH] Checks are now full 3-D + players[playernum].mo->SetZ(z); // [RH] Checks are now full 3-D // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid // corpse to detect collisions with other players in DM starts @@ -1453,7 +1453,7 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) players[playernum].mo->flags |= MF_SOLID; i = P_CheckPosition(players[playernum].mo, x, y); players[playernum].mo->flags &= ~MF_SOLID; - players[playernum].mo->z = oldz; // [RH] Restore corpse's height + players[playernum].mo->SetZ(oldz); // [RH] Restore corpse's height if (!i) return false; diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index a9af52724..abc4d5c59 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -795,7 +795,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li highestfloorpic = *rover->top.texture; highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); } - if(ff_top > lowestfloor[j] && ff_top <= thing->z + thing->MaxStepHeight) lowestfloor[j] = ff_top; + if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8c8c0a5f1..6ce1cfd55 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -8602,7 +8602,7 @@ scriptwait: } else { - STACK(1) = (&actor->x)[pcd - PCD_GETACTORX]; + STACK(1) = pcd == PCD_GETACTORX ? actor->X() : pcd == PCD_GETACTORY ? actor->Y() : actor->Z(); } } break; diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 0f04de8eb..fa1fd5413 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -356,9 +356,10 @@ static void MakeFountain (AActor *actor, int color1, int color2) angle_t an = M_Random()<<(24-ANGLETOFINESHIFT); fixed_t out = FixedMul (actor->radius, M_Random()<<8); - particle->x = actor->x + FixedMul (out, finecosine[an]); - particle->y = actor->y + FixedMul (out, finesine[an]); - particle->z = actor->z + actor->height + FRACUNIT; + fixedvec3 pos = actor->Vec3Offset(FixedMul(out, finecosine[an]), FixedMul(out, finesine[an]), actor->height + FRACUNIT); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; if (out < actor->radius/8) particle->velz += FRACUNIT*10/3; else @@ -395,9 +396,10 @@ void P_RunEffect (AActor *actor, int effects) { // Rocket trail - fixed_t backx = actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); - fixed_t backy = actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); - fixed_t backz = actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3; + + fixed_t backx = - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); + fixed_t backy = - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); + fixed_t backz = - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3; angle_t an = (moveangle + ANG90) >> ANGLETOFINESHIFT; int speed; @@ -405,9 +407,13 @@ void P_RunEffect (AActor *actor, int effects) particle = JitterParticle (3 + (M_Random() & 31)); if (particle) { fixed_t pathdist = M_Random()<<8; - particle->x = backx - FixedMul(actor->velx, pathdist); - particle->y = backy - FixedMul(actor->vely, pathdist); - particle->z = backz - FixedMul(actor->velz, pathdist); + fixedvec3 pos = actor->Vec3Offset( + backx - FixedMul(actor->velx, pathdist), + backy - FixedMul(actor->vely, pathdist), + backz - FixedMul(actor->velz, pathdist)); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; speed = (M_Random () - 128) * (FRACUNIT/200); particle->velx += FixedMul (speed, finecosine[an]); particle->vely += FixedMul (speed, finesine[an]); @@ -420,9 +426,13 @@ void P_RunEffect (AActor *actor, int effects) particle_t *particle = JitterParticle (3 + (M_Random() & 31)); if (particle) { fixed_t pathdist = M_Random()<<8; - particle->x = backx - FixedMul(actor->velx, pathdist); - particle->y = backy - FixedMul(actor->vely, pathdist); - particle->z = backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10); + fixedvec3 pos = actor->Vec3Offset( + backx - FixedMul(actor->velx, pathdist), + backy - FixedMul(actor->vely, pathdist), + backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; speed = (M_Random () - 128) * (FRACUNIT/200); particle->velx += FixedMul (speed, finecosine[an]); particle->vely += FixedMul (speed, finesine[an]); @@ -441,10 +451,12 @@ void P_RunEffect (AActor *actor, int effects) { // Grenade trail - P_DrawSplash2 (6, - actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2), - actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2), - actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3, + fixedvec3 pos = actor->Vec3Offset( + -FixedMul(finecosine[(moveangle) >> ANGLETOFINESHIFT], actor->radius * 2), + -FixedMul(finesine[(moveangle) >> ANGLETOFINESHIFT], actor->radius * 2), + -(actor->height >> 3) * (actor->velz >> 16) + (2 * actor->height) / 3); + + P_DrawSplash2 (6, pos.x, pos.y, pos.z, moveangle + ANG180, 2, 2); } if (effects & FX_FOUNTAINMASK) @@ -476,10 +488,11 @@ void P_RunEffect (AActor *actor, int effects) if (particle != NULL) { angle_t ang = M_Random () << (32-ANGLETOFINESHIFT-8); - particle->x = actor->x + FixedMul (actor->radius, finecosine[ang]); - particle->y = actor->y + FixedMul (actor->radius, finesine[ang]); + fixedvec3 pos = actor->Vec3Offset(FixedMul (actor->radius, finecosine[ang]), FixedMul (actor->radius, finesine[ang]), 0); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; particle->color = *protectColors[M_Random() & 1]; - particle->z = actor->z; particle->velz = FRACUNIT; particle->accz = M_Random () << 7; particle->size = 1; @@ -832,9 +845,13 @@ void P_DisconnectEffect (AActor *actor) if (!p) break; - p->x = actor->x + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS); - p->y = actor->y + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS); - p->z = actor->z + (M_Random()<<8) * (actor->height>>FRACBITS); + fixedvec3 pos = actor->Vec3Offset( + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS), + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS), + (M_Random()<<8) * (actor->height>>FRACBITS)); + p->x = pos.x; + p->y = pos.y; + p->z = pos.z; p->accz -= FRACUNIT/4096; p->color = M_Random() < 128 ? maroon1 : maroon2; p->size = 4; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 82907d10a..1c7a205a1 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -585,7 +585,7 @@ sector_t *AActor::LinkToWorldForMapThing () return ssec->sector; } -void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz) +void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving) { UnlinkFromWorld (); x = ix; From a65ff3987238aa8e3da63e707ffb8eb7bb750c37 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 22:13:17 +0100 Subject: [PATCH 331/335] - more coordinate refactoring in p_enemy.cpp. --- src/p_effect.cpp | 2 +- src/p_enemy.cpp | 97 +++++++++++++++++++++++------------------------- src/p_lnspec.cpp | 2 +- 3 files changed, 48 insertions(+), 53 deletions(-) diff --git a/src/p_effect.cpp b/src/p_effect.cpp index fa1fd5413..0cd6d5c51 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -429,7 +429,7 @@ void P_RunEffect (AActor *actor, int effects) fixedvec3 pos = actor->Vec3Offset( backx - FixedMul(actor->velx, pathdist), backy - FixedMul(actor->vely, pathdist), - backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10); + backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10)); particle->x = pos.x; particle->y = pos.y; particle->z = pos.z; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 165ac35a1..77999c06e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -243,9 +243,9 @@ bool AActor::CheckMeleeRange () // [RH] Don't melee things too far above or below actor. if (!(flags5 & MF5_NOVERTICALMELEERANGE)) { - if (pl->Z() > z + height) + if (pl->Z() > Z() + height) return false; - if (pl->Z() + pl->height < z) + if (pl->Z() + pl->height < Z()) return false; } @@ -473,8 +473,8 @@ bool P_Move (AActor *actor) } } - tryx = (origx = actor->x) + (deltax = FixedMul (speed, xspeed[actor->movedir])); - tryy = (origy = actor->y) + (deltay = FixedMul (speed, yspeed[actor->movedir])); + tryx = (origx = actor->X()) + (deltax = FixedMul (speed, xspeed[actor->movedir])); + tryy = (origy = actor->Y()) + (deltay = FixedMul (speed, yspeed[actor->movedir])); // Like P_XYMovement this should do multiple moves if the step size is too large @@ -519,15 +519,14 @@ bool P_Move (AActor *actor) // so make it switchable if (nomonsterinterpolation) { - actor->PrevX = actor->x; - actor->PrevY = actor->y; - actor->PrevZ = actor->z; + actor->PrevX = actor->X(); + actor->PrevY = actor->Y(); + actor->PrevZ = actor->Z(); } if (try_ok && friction > ORIG_FRICTION) { - actor->x = origx; - actor->y = origy; + actor->SetOrigin(origx, origy, actor->Z(), false); movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4; actor->velx += FixedMul (deltax, movefactor); actor->vely += FixedMul (deltay, movefactor); @@ -543,12 +542,12 @@ bool P_Move (AActor *actor) if (actor->Y() <= actor->floorz + actor->MaxStepHeight) { fixed_t savedz = actor->Z(); - actor->z = actor->floorz; + actor->SetZ(actor->floorz); // Make sure that there isn't some other actor between us and // the floor we could get stuck in. The old code did not do this. if (!P_TestMobjZ(actor)) { - actor->z = savedz; + actor->SetZ(savedz); } else { // The monster just hit the floor, so trigger any actions. @@ -568,10 +567,10 @@ bool P_Move (AActor *actor) { // must adjust height fixed_t savedz = actor->Z(); - if (actor->z < tm.floorz) - actor->z += actor->FloatSpeed; + if (actor->Z() < tm.floorz) + actor->SetZ(actor->Z() + actor->FloatSpeed); else - actor->z -= actor->FloatSpeed; + actor->SetZ(actor->Z() - actor->FloatSpeed); // [RH] Check to make sure there's nothing in the way of the float @@ -580,7 +579,7 @@ bool P_Move (AActor *actor) actor->flags |= MF_INFLOAT; return true; } - actor->z = savedz; + actor->SetZ(savedz); } if (!spechit.Size ()) @@ -812,28 +811,25 @@ void P_DoNewChaseDir (AActor *actor, fixed_t deltax, fixed_t deltay) void P_NewChaseDir(AActor * actor) { - fixed_t deltax; - fixed_t deltay; + fixedvec2 delta; actor->strafecount = 0; if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL) { - deltax = actor->goal->x - actor->x; - deltay = actor->goal->y - actor->y; + delta = actor->Vec2To(actor->goal); } else if (actor->target != NULL) { - deltax = actor->target->x - actor->x; - deltay = actor->target->y - actor->y; + delta = actor->Vec2To(actor->target); if (!(actor->flags6 & MF6_NOFEAR)) { if ((actor->target->player != NULL && (actor->target->player->cheats & CF_FRIGHTENING)) || (actor->flags4 & MF4_FRIGHTENED)) { - deltax = -deltax; - deltay = -deltay; + delta.x = -delta.x; + delta.y = -delta.y; } } } @@ -877,7 +873,7 @@ void P_NewChaseDir(AActor * actor) { angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff } - else if (front == actor->z && back < actor->z - actor->MaxDropOffHeight) + else if (front == actor->Z() && back < actor->Z() - actor->MaxDropOffHeight) { angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff } @@ -946,12 +942,12 @@ void P_NewChaseDir(AActor * actor) if (ismeleeattacker) { actor->strafecount = pr_enemystrafe() & 15; - deltax = -deltax, deltay = -deltay; + delta.x = -delta.x, delta.y = -delta.y; } } } - P_DoNewChaseDir(actor, deltax, deltay); + P_DoNewChaseDir(actor, delta.x, delta.y); // If strafing, set movecount to strafecount so that old Doom // logic still works the same, except in the strafing part @@ -983,7 +979,7 @@ void P_RandomChaseDir (AActor *actor) if (actor->flags & MF_FRIENDLY) { AActor *player; - fixed_t deltax, deltay; + fixedvec2 delta; dirtype_t d[3]; if (actor->FriendPlayer != 0) @@ -1005,19 +1001,18 @@ void P_RandomChaseDir (AActor *actor) { if (pr_newchasedir() & 1 || !P_CheckSight (actor, player)) { - deltax = player->x - actor->x; - deltay = player->y - actor->y; + delta = actor->Vec2To(player); - if (deltax>128*FRACUNIT) + if (delta.x>128*FRACUNIT) d[1]= DI_EAST; - else if (deltax<-128*FRACUNIT) + else if (delta.x<-128*FRACUNIT) d[1]= DI_WEST; else d[1]=DI_NODIR; - if (deltay<-128*FRACUNIT) + if (delta.y<-128*FRACUNIT) d[2]= DI_SOUTH; - else if (deltay>128*FRACUNIT) + else if (delta.y>128*FRACUNIT) d[2]= DI_NORTH; else d[2]=DI_NODIR; @@ -1025,13 +1020,13 @@ void P_RandomChaseDir (AActor *actor) // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - actor->movedir = diags[((deltay<0)<<1) + (deltax>0)]; + actor->movedir = diags[((delta.y<0)<<1) + (delta.x>0)]; if (actor->movedir != turnaround && P_TryWalk(actor)) return; } // try other directions - if (pr_newchasedir() > 200 || abs(deltay) > abs(deltax)) + if (pr_newchasedir() > 200 || abs(delta.y) > abs(delta.x)) { swapvalues (d[1], d[2]); } @@ -2474,8 +2469,8 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi if ((!fastchase || !actor->FastChaseStrafeCount) && !dontmove) { // CANTLEAVEFLOORPIC handling was completely missing in the non-serpent functions. - fixed_t oldX = actor->x; - fixed_t oldY = actor->y; + fixed_t oldX = actor->X(); + fixed_t oldY = actor->Y(); FTextureID oldFloor = actor->floorpic; // chase towards player @@ -2526,11 +2521,12 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if (self->movedir != DI_NODIR) { const fixed_t absSpeed = abs (self->Speed); - fixed_t viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]); - fixed_t viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]); + fixedvec2 viletry = self->Vec2Offset( + FixedMul (absSpeed, xspeed[self->movedir]), + FixedMul (absSpeed, yspeed[self->movedir]), true); AActor *corpsehit; - FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); + FBlockThingsIterator it(FBoundingBox(viletry.x, viletry.y, 32*FRACUNIT)); while ((corpsehit = it.Next())) { FState *raisestate = corpsehit->GetRaiseState(); @@ -2539,8 +2535,8 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) // use the current actor's radius instead of the Arch Vile's default. fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - if (abs(corpsehit->x - viletryx) > maxdist || - abs(corpsehit->y - viletryy) > maxdist) + if (abs(corpsehit->X() - viletry.x) > maxdist || + abs(corpsehit->Y() - viletry.y) > maxdist) continue; // not actually touching // Let's check if there are floors in between the archvile and its target sector_t *vilesec = self->Sector; @@ -2783,12 +2779,11 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a { // [DH] Don't need to do proper fixed->double conversion, since the // result is only used in a ratio. - double dist_x = other->x - self->x; - double dist_y = other->y - self->y; + fixedvec2 dist = self->Vec2To(other); // Positioning ala missile spawning, 32 units above foot level - fixed_t source_z = self->z + 32*FRACUNIT + self->GetBobOffset(); - fixed_t target_z = other->z + 32*FRACUNIT + other->GetBobOffset(); + fixed_t source_z = self->Z() + 32*FRACUNIT + self->GetBobOffset(); + fixed_t target_z = other->Z() + 32*FRACUNIT + other->GetBobOffset(); // If the target z is above the target's head, reposition to the middle of // its body. @@ -2809,8 +2804,8 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a target_z += pitch_offset; double dist_z = target_z - source_z; - double dist = sqrt(dist_x*dist_x + dist_y*dist_y + dist_z*dist_z); - int other_pitch = (int)rad2bam(asin(dist_z / dist)); + double ddist = sqrt(dist.x*dist.x + dist.y*dist.y + dist_z*dist_z); + int other_pitch = (int)rad2bam(asin(dist_z / ddist)); if (max_pitch != 0) { @@ -2922,9 +2917,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) if (linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. - TVector2 xydiff(self->target->x - self->x, self->target->y - self->y); - double zdiff = (self->target->z + (self->target->height>>1)) - - (self->z + (self->height>>1) - self->floorclip); + TVector2 xydiff = self->Vec2To(self->target); + double zdiff = (self->target->Z() + (self->target->height>>1)) - + (self->Z() + (self->height>>1) - self->floorclip); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 22e901c73..2592c930f 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3107,7 +3107,7 @@ FUNC(LS_GlassBreak) { glass = Spawn("GlassJunk", x, y, ONFLOORZ, ALLOW_REPLACE); - glass->z += 24 * FRACUNIT; + glass->SetZ(glass->z + 24 * FRACUNIT); glass->SetState (glass->SpawnState + (pr_glass() % glass->health)); an = pr_glass() << (32-8); glass->angle = an; From b735138332bbbb09db4a81ff243bd550362e0b9c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 17 Jan 2016 22:56:16 +0100 Subject: [PATCH 332/335] - forgot the changes to actor.h. --- src/actor.h | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/actor.h b/src/actor.h index 22bea9e08..f58d48f9a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -847,7 +847,7 @@ public: bool intersects(AActor *other) const { fixed_t blockdist = radius + other->radius; - return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); + return ( abs(pos.x - other->pos.x) < blockdist && abs(pos.y - other->pos.y) < blockdist); } PalEntry GetBloodColor() const @@ -888,84 +888,84 @@ public: // to distinguish between portal-aware and portal-unaware distance calculation. fixed_t AproxDistance(AActor *other, bool absolute = false) { - return P_AproxDistance(x - other->x, y - other->y); + return P_AproxDistance(pos.x - other->pos.x, pos.y - other->pos.y); } // same with 'ref' here. fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) { - return P_AproxDistance(x - otherx, y - othery); + return P_AproxDistance(pos.x - otherx, pos.y - othery); } fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) { - return P_AproxDistance(x - other->x + xadd, y - other->y + yadd); + return P_AproxDistance(pos.x - other->pos.x + xadd, pos.y - other->pos.y + yadd); } fixed_t AproxDistance3D(AActor *other, bool absolute = false) { - return P_AproxDistance(AproxDistance(other), z - other->z); + return P_AproxDistance(AproxDistance(other), pos.z - other->pos.z); } // more precise, but slower version, being used in a few places fixed_t Distance2D(AActor *other, bool absolute = false) { - return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length()); + return xs_RoundToInt(FVector2(pos.x - other->pos.x, pos.y - other->pos.y).Length()); } // a full 3D version of the above fixed_t Distance3D(AActor *other, bool absolute = false) { - return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); + return xs_RoundToInt(FVector3(pos.x - other->pos.x, pos.y - other->pos.y, pos.z - other->pos.z).Length()); } angle_t AngleTo(AActor *other, bool absolute = false) const { - return R_PointToAngle2(x, y, other->x, other->y); + return R_PointToAngle2(pos.x, pos.y, other->pos.x, other->pos.y); } angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const { - return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs); + return R_PointToAngle2(pos.x, pos.y, other->pos.x + oxofs, other->pos.y + oyofs); } fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) { - return R_PointToAngle2(x, y, otherx, othery); + return R_PointToAngle2(pos.x, pos.y, otherx, othery); } fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) { - return R_PointToAngle2(myx, myy, other->x, other->y); + return R_PointToAngle2(myx, myy, other->pos.x, other->pos.y); } fixedvec2 Vec2To(AActor *other) const { - fixedvec2 ret = { other->x - x, other->y - y }; + fixedvec2 ret = { other->pos.x - pos.x, other->pos.y - pos.y }; return ret; } fixedvec3 Vec3To(AActor *other) const { - fixedvec3 ret = { other->x - x, other->y - y, other->z - z }; + fixedvec3 ret = { other->pos.x - pos.x, other->pos.y - pos.y, other->pos.z - pos.z }; return ret; } - fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy) const + fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const { - fixedvec2 ret = { x + dx, y + dy }; + fixedvec2 ret = { pos.x + dx, pos.y + dy }; return ret; } - fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz) const + fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const { - fixedvec3 ret = { x + dx, y + dy, z + dz }; + fixedvec3 ret = { pos.x + dx, pos.y + dy, pos.z + dz }; return ret; } void Move(fixed_t dx, fixed_t dy, fixed_t dz) { - SetOrigin(x + dx, y + dy, z + dz, true); + SetOrigin(pos.x + dx, pos.y + dy, pos.z + dz, true); } inline void SetFriendPlayer(player_t *player); @@ -987,7 +987,10 @@ public: // info for drawing // NOTE: The first member variable *must* be x. - fixed_t x,y,z; +private: + fixedvec3 pos; +public: + //fixed_t x,y,z; AActor *snext, **sprev; // links in sector (if needed) angle_t angle; WORD sprite; // used to find patch_t and flip value @@ -1185,7 +1188,7 @@ public: void LinkToWorld (sector_t *sector); void UnlinkFromWorld (); void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving); bool InStateSequence(FState * newstate, FState * basestate); int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); @@ -1217,19 +1220,19 @@ public: fixed_t X() const { - return x; + return pos.x; } fixed_t Y() const { - return y; + return pos.y; } fixed_t Z() const { - return z; + return pos.z; } void SetZ(fixed_t newz) { - z = newz; + pos.z = newz; } }; From 43314f0c0df262f3063455b24a500b67f231f68b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 18 Jan 2016 00:59:16 +0100 Subject: [PATCH 333/335] - started refactoring p_map.cpp - added AActor::Top function to replace the frequent occurences of actor->z + actor->height. --- src/actor.h | 53 +++++++++++++++++++++++----------------------- src/d_net.cpp | 2 +- src/p_3dfloors.cpp | 2 +- src/p_acs.cpp | 2 +- src/p_enemy.cpp | 10 ++++----- src/p_lnspec.cpp | 2 +- src/p_map.cpp | 30 +++++++++++++------------- 7 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/actor.h b/src/actor.h index f58d48f9a..f17af7bc2 100644 --- a/src/actor.h +++ b/src/actor.h @@ -847,7 +847,7 @@ public: bool intersects(AActor *other) const { fixed_t blockdist = radius + other->radius; - return ( abs(pos.x - other->pos.x) < blockdist && abs(pos.y - other->pos.y) < blockdist); + return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); } PalEntry GetBloodColor() const @@ -888,84 +888,84 @@ public: // to distinguish between portal-aware and portal-unaware distance calculation. fixed_t AproxDistance(AActor *other, bool absolute = false) { - return P_AproxDistance(pos.x - other->pos.x, pos.y - other->pos.y); + return P_AproxDistance(x - other->x, y - other->y); } // same with 'ref' here. fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) { - return P_AproxDistance(pos.x - otherx, pos.y - othery); + return P_AproxDistance(x - otherx, y - othery); } fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) { - return P_AproxDistance(pos.x - other->pos.x + xadd, pos.y - other->pos.y + yadd); + return P_AproxDistance(x - other->x + xadd, y - other->y + yadd); } fixed_t AproxDistance3D(AActor *other, bool absolute = false) { - return P_AproxDistance(AproxDistance(other), pos.z - other->pos.z); + return P_AproxDistance(AproxDistance(other), z - other->z); } // more precise, but slower version, being used in a few places fixed_t Distance2D(AActor *other, bool absolute = false) { - return xs_RoundToInt(FVector2(pos.x - other->pos.x, pos.y - other->pos.y).Length()); + return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length()); } // a full 3D version of the above fixed_t Distance3D(AActor *other, bool absolute = false) { - return xs_RoundToInt(FVector3(pos.x - other->pos.x, pos.y - other->pos.y, pos.z - other->pos.z).Length()); + return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length()); } angle_t AngleTo(AActor *other, bool absolute = false) const { - return R_PointToAngle2(pos.x, pos.y, other->pos.x, other->pos.y); + return R_PointToAngle2(x, y, other->x, other->y); } angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const { - return R_PointToAngle2(pos.x, pos.y, other->pos.x + oxofs, other->pos.y + oyofs); + return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs); } fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) { - return R_PointToAngle2(pos.x, pos.y, otherx, othery); + return R_PointToAngle2(x, y, otherx, othery); } fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) { - return R_PointToAngle2(myx, myy, other->pos.x, other->pos.y); + return R_PointToAngle2(myx, myy, other->x, other->y); } fixedvec2 Vec2To(AActor *other) const { - fixedvec2 ret = { other->pos.x - pos.x, other->pos.y - pos.y }; + fixedvec2 ret = { other->x - x, other->y - y }; return ret; } fixedvec3 Vec3To(AActor *other) const { - fixedvec3 ret = { other->pos.x - pos.x, other->pos.y - pos.y, other->pos.z - pos.z }; + fixedvec3 ret = { other->x - x, other->y - y, other->z - z }; return ret; } fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const { - fixedvec2 ret = { pos.x + dx, pos.y + dy }; + fixedvec2 ret = { x + dx, y + dy }; return ret; } fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const { - fixedvec3 ret = { pos.x + dx, pos.y + dy, pos.z + dz }; + fixedvec3 ret = { x + dx, y + dy, z + dz }; return ret; } void Move(fixed_t dx, fixed_t dy, fixed_t dz) { - SetOrigin(pos.x + dx, pos.y + dy, pos.z + dz, true); + SetOrigin(x + dx, y + dy, z + dz, true); } inline void SetFriendPlayer(player_t *player); @@ -987,10 +987,7 @@ public: // info for drawing // NOTE: The first member variable *must* be x. -private: - fixedvec3 pos; -public: - //fixed_t x,y,z; + fixed_t x,y,z; AActor *snext, **sprev; // links in sector (if needed) angle_t angle; WORD sprite; // used to find patch_t and flip value @@ -1188,7 +1185,7 @@ public: void LinkToWorld (sector_t *sector); void UnlinkFromWorld (); void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false); bool InStateSequence(FState * newstate, FState * basestate); int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); @@ -1220,19 +1217,23 @@ public: fixed_t X() const { - return pos.x; + return x; } fixed_t Y() const { - return pos.y; + return y; } fixed_t Z() const { - return pos.z; + return z; } - void SetZ(fixed_t newz) + fixed_t Top() const { - pos.z = newz; + return z + height; + } + void SetZ(fixed_t newz, bool moving = true) + { + z = newz; } }; diff --git a/src/d_net.cpp b/src/d_net.cpp index 95061d0e1..29303fa04 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2376,7 +2376,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) s = ReadString (stream); if (Trace (players[player].mo->X(), players[player].mo->Y(), - players[player].mo->Z() + players[player].mo->height - (players[player].mo->height>>2), + players[player].mo->Top() - (players[player].mo->height>>2), players[player].mo->Sector, vx, vy, vz, 172*FRACUNIT, 0, ML_BLOCKEVERYTHING, players[player].mo, trace, TRACE_NoSky)) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index abc4d5c59..e294dec69 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -337,7 +337,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) { //Water and DEATH FOG!!! heh if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || - (player->mo->Z() + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo)) + player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo)) continue; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6ce1cfd55..81420b73a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4158,7 +4158,7 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b } else { - fixed_t z = actor->Z() + actor->height; + fixed_t z = actor->Top(); // Looking through planes from bottom to top for (i = numff-1; i >= 0; --i) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 77999c06e..15861f79e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -243,9 +243,9 @@ bool AActor::CheckMeleeRange () // [RH] Don't melee things too far above or below actor. if (!(flags5 & MF5_NOVERTICALMELEERANGE)) { - if (pl->Z() > Z() + height) + if (pl->Z() > Top()) return false; - if (pl->Z() + pl->height < Z()) + if (pl->Top() < Z()) return false; } @@ -280,11 +280,11 @@ bool P_CheckMeleeRange2 (AActor *actor) { return false; } - if (mo->Z() > actor->Z()+actor->height) + if (mo->Z() > actor->Top()) { // Target is higher than the attacker return false; } - else if (actor->Z() > mo->Z()+mo->height) + else if (actor->Z() > mo->Top()) { // Attacker is higher return false; } @@ -2787,7 +2787,7 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a // If the target z is above the target's head, reposition to the middle of // its body. - if (target_z >= other->Z() + other->height) + if (target_z >= other->Top()) { target_z = other->Z() + (other->height / 2); } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 2592c930f..06e2f5f21 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3107,7 +3107,7 @@ FUNC(LS_GlassBreak) { glass = Spawn("GlassJunk", x, y, ONFLOORZ, ALLOW_REPLACE); - glass->SetZ(glass->z + 24 * FRACUNIT); + glass->SetZ(glass->Z() + 24 * FRACUNIT); glass->SetState (glass->SpawnState + (pr_glass() % glass->health)); an = pr_glass() << (32-8); glass->angle = an; diff --git a/src/p_map.cpp b/src/p_map.cpp index 78a17df10..69f8b6c5b 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -190,7 +190,7 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi } else if (r >= (1 << 24)) { - P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->x, tmf.thing->y, flags); + P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->X(), tmf.thing->Y(), flags); } else { @@ -288,9 +288,9 @@ void P_FindFloorCeiling(AActor *actor, int flags) FCheckPosition tmf; tmf.thing = actor; - tmf.x = actor->x; - tmf.y = actor->y; - tmf.z = actor->z; + tmf.x = actor->X(); + tmf.y = actor->Y(); + tmf.z = actor->Z(); if (flags & FFCF_ONLYSPAWNPOS) { @@ -336,7 +336,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; - if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->z))) + if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z()))) { actor->floorz = tmf.floorz; actor->dropoffz = tmf.dropoffz; @@ -404,13 +404,13 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra line_t *ld; // P_LineOpening requires the thing's z to be the destination z in order to work. - fixed_t savedz = thing->z; - thing->z = z; + fixed_t savedz = thing->Z(); + thing->SetZ(z); while ((ld = it.Next())) { PIT_FindFloorCeiling(ld, box, tmf, 0); } - thing->z = savedz; + thing->SetZ(savedz); if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; @@ -427,7 +427,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra continue; fixed_t blockdist = th->radius + tmf.thing->radius; - if (abs(th->x - tmf.x) >= blockdist || abs(th->y - tmf.y) >= blockdist) + if (abs(th->X() - tmf.x) >= blockdist || abs(th->Y() - tmf.y) >= blockdist) continue; // [RH] Z-Check @@ -437,8 +437,8 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra { if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP)) { - if (z > th->z + th->height || // overhead - z + thing->height < th->z) // underneath + if (z > th->Top() || // overhead + z + thing->height < th->Z()) // underneath continue; } } @@ -459,7 +459,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra if (modifyactor) { // the move is ok, so link the thing into its new position - thing->SetOrigin(x, y, z); + thing->SetOrigin(x, y, z, false); thing->floorz = tmf.floorz; thing->ceilingz = tmf.ceilingz; thing->floorsector = tmf.floorsector; @@ -507,7 +507,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra void P_PlayerStartStomp(AActor *actor) { AActor *th; - FBlockThingsIterator it(FBoundingBox(actor->x, actor->y, actor->radius)); + FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); while ((th = it.Next())) { @@ -525,9 +525,9 @@ void P_PlayerStartStomp(AActor *actor) if (th->player == NULL && !(th->flags3 & MF3_ISMONSTER)) continue; - if (actor->z > th->z + th->height) + if (actor->Z() > th->Top()) continue; // overhead - if (actor->z + actor->height < th->z) + if (actor->Top() < th->Z()) continue; // underneath P_DamageMobj(th, actor, actor, TELEFRAG_DAMAGE, NAME_Telefrag); From e8ee8c5c976c3d9cb964f959d0c697af9575ae08 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 18 Jan 2016 01:21:20 +0100 Subject: [PATCH 334/335] - fixed: secspecial_t was left uninitialized, causing its damage type being an invalid name. --- src/r_defs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/r_defs.h b/src/r_defs.h index 6f69a26a0..dd8496e4d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -455,6 +455,11 @@ struct secspecial_t short leakydamage; // chance of leaking through radiation suit int Flags; + secspecial_t() + { + Clear(); + } + void Clear() { memset(this, 0, sizeof(*this)); From b63eb391f763acfa65931a58472c081f6bec2c56 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 18 Jan 2016 12:37:39 +0100 Subject: [PATCH 335/335] - refactored two mire files. - fixed: FraggleScript's SetObjPosition function did not properly set the moved actor's properties. Better use SetOrigin for changing the position. --- src/actor.h | 20 +++++++++++++++ src/fragglescript/t_func.cpp | 50 +++++++++++++++++------------------- src/g_doom/a_archvile.cpp | 19 +++++--------- src/p_enemy.cpp | 3 +-- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/actor.h b/src/actor.h index f17af7bc2..4deb349a7 100644 --- a/src/actor.h +++ b/src/actor.h @@ -957,17 +957,37 @@ public: return ret; } + + fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false) const + { + fixedvec2 ret = { x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), + y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; + return ret; + } + fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const { fixedvec3 ret = { x + dx, y + dy, z + dz }; return ret; } + fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false) const + { + fixedvec3 ret = { x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), + y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), z + dz }; + return ret; + } + void Move(fixed_t dx, fixed_t dy, fixed_t dz) { SetOrigin(x + dx, y + dy, z + dz, true); } + void SetOrigin(const fixedvec3 & npos, bool moving) + { + SetOrigin(npos.x, npos.y, npos.z, moving); + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index ceabc9ce5..2381ad381 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -982,7 +982,7 @@ void FParser::SF_ObjX(void) } t_return.type = svt_fixed; // haleyjd: SoM's fixed-point fix - t_return.value.f = mo ? mo->x : 0; // null ptr check + t_return.value.f = mo ? mo->X() : 0; // null ptr check } //========================================================================== @@ -1005,7 +1005,7 @@ void FParser::SF_ObjY(void) } t_return.type = svt_fixed; // haleyjd - t_return.value.f = mo ? mo->y : 0; // null ptr check + t_return.value.f = mo ? mo->Y() : 0; // null ptr check } //========================================================================== @@ -1028,7 +1028,7 @@ void FParser::SF_ObjZ(void) } t_return.type = svt_fixed; // haleyjd - t_return.value.f = mo ? mo->z : 0; // null ptr check + t_return.value.f = mo ? mo->Z() : 0; // null ptr check } @@ -1466,8 +1466,8 @@ void FParser::SF_SetCamera(void) angle = t_argc < 2 ? newcamera->angle : (fixed_t)FixedToAngle(fixedvalue(t_argv[1])); newcamera->special1=newcamera->angle; - newcamera->special2=newcamera->z; - newcamera->z = t_argc < 3 ? (newcamera->z + (41 << FRACBITS)) : (intvalue(t_argv[2]) << FRACBITS); + newcamera->special2=newcamera->Z(); + newcamera->SetZ(t_argc < 3 ? (newcamera->Z() + (41 << FRACBITS)) : (intvalue(t_argv[2]) << FRACBITS)); newcamera->angle = angle; if(t_argc < 4) newcamera->pitch = 0; else @@ -1498,7 +1498,7 @@ void FParser::SF_ClearCamera(void) { player->camera=player->mo; cam->angle=cam->special1; - cam->z=cam->special2; + cam->SetZ(cam->special2); } } @@ -3065,7 +3065,7 @@ void FParser::SF_SetWeapon() void FParser::SF_MoveCamera(void) { fixed_t x, y, z; - fixed_t xdist, ydist, zdist, xydist, movespeed; + fixed_t zdist, xydist, movespeed; fixed_t xstep, ystep, zstep, targetheight; angle_t anglespeed, anglestep, angledist, targetangle, mobjangle, bigangle, smallangle; @@ -3097,9 +3097,8 @@ void FParser::SF_MoveCamera(void) anglespeed = (angle_t)FixedToAngle(fixedvalue(t_argv[5])); // figure out how big one step will be - xdist = target->x - cam->x; - ydist = target->y - cam->y; - zdist = targetheight - cam->z; + fixedvec2 dist = cam->Vec2To(target); + zdist = targetheight - cam->Z(); // Angle checking... // 90 @@ -3170,19 +3169,19 @@ void FParser::SF_MoveCamera(void) else anglestep = anglespeed; - if(abs(xstep) >= (abs(xdist) - 1)) - x = target->x; + if(abs(xstep) >= (abs(dist.x) - 1)) + x = cam->X() + dist.x; else { - x = cam->x + xstep; + x = cam->X() + xstep; moved = 1; } - if(abs(ystep) >= (abs(ydist) - 1)) - y = target->y; + if(abs(ystep) >= (abs(dist.y) - 1)) + y = cam->Y() + dist.y; else { - y = cam->y + ystep; + y = cam->Y() + ystep; moved = 1; } @@ -3190,7 +3189,7 @@ void FParser::SF_MoveCamera(void) z = targetheight; else { - z = cam->z + zstep; + z = cam->Z() + zstep; moved = 1; } @@ -3212,12 +3211,12 @@ void FParser::SF_MoveCamera(void) cam->radius=8; cam->height=8; - if ((x != cam->x || y != cam->y) && !P_TryMove(cam, x, y, true)) + if ((x != cam->X() || y != cam->Y()) && !P_TryMove(cam, x, y, true)) { Printf("Illegal camera move to (%f, %f)\n", x/65536.f, y/65536.f); return; } - cam->z = z; + cam->SetZ(z); t_return.type = svt_int; t_return.value.i = moved; @@ -3410,13 +3409,10 @@ void FParser::SF_SetObjPosition() if (!mobj) return; - mobj->UnlinkFromWorld(); - - mobj->x = intvalue(t_argv[1]) << FRACBITS; - if(t_argc >= 3) mobj->y = intvalue(t_argv[2]) << FRACBITS; - if(t_argc == 4) mobj->z = intvalue(t_argv[3]) << FRACBITS; - - mobj->LinkToWorld(); + mobj->SetOrigin( + fixedvalue(t_argv[1]), + (t_argc >= 3)? fixedvalue(t_argv[2]) : mobj->Y(), + (t_argc >= 4)? fixedvalue(t_argv[3]) : mobj->Z(), false); } } @@ -4285,7 +4281,7 @@ void FParser::SF_SpawnShot2(void) t_return.type = svt_mobj; - AActor *mo = Spawn (PClass, source->x, source->y, source->z+z, ALLOW_REPLACE); + AActor *mo = Spawn (PClass, source->X(), source->Y(), source->Z()+z, ALLOW_REPLACE); if (mo) { S_Sound (mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM); diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index f24ff146e..9d2e5db0c 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -52,7 +52,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Fire) void A_Fire(AActor *self, int height) { AActor *dest; - angle_t an; dest = self->tracer; if (dest == NULL || self->target == NULL) @@ -62,11 +61,8 @@ void A_Fire(AActor *self, int height) if (!P_CheckSight (self->target, dest, 0) ) return; - an = dest->angle >> ANGLETOFINESHIFT; - - self->SetOrigin (dest->x + FixedMul (24*FRACUNIT, finecosine[an]), - dest->y + FixedMul (24*FRACUNIT, finesine[an]), - dest->z + height); + fixedvec3 newpos = dest->Vec3Angle(24 * FRACUNIT, dest->angle, height); + self->SetOrigin(newpos, true); } @@ -86,8 +82,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) A_FaceTarget (self); - fog = Spawn (fire, self->target->x, self->target->y, - self->target->z, ALLOW_REPLACE); + fog = Spawn (fire, self->target->X(), self->target->Y(), + self->target->Z(), ALLOW_REPLACE); self->tracer = fog; fog->target = self; @@ -117,7 +113,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) ACTION_PARAM_INT(flags,6); AActor *fire, *target; - angle_t an; if (NULL == (target = self->target)) return; @@ -139,15 +134,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) P_TraceBleed (newdam > 0 ? newdam : dmg, target); - an = self->angle >> ANGLETOFINESHIFT; fire = self->tracer; if (fire != NULL) { // move the fire between the vile and the player - fire->SetOrigin (target->x - FixedMul (24*FRACUNIT, finecosine[an]), - target->y - FixedMul (24*FRACUNIT, finesine[an]), - target->z); + fixedvec3 pos = target->Vec3Angle(-24 * FRACUNIT, self->angle, target->Z()); + fire->SetOrigin (pos, true); P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0); } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 15861f79e..d8230a031 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2918,8 +2918,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. TVector2 xydiff = self->Vec2To(self->target); - double zdiff = (self->target->Z() + (self->target->height>>1)) - - (self->Z() + (self->height>>1) - self->floorclip); + double zdiff = FIXED2DBL((self->target->Z() + (self->target->height>>1)) - (self->Z() + (self->height>>1) - self->floorclip)); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); }