From c76431414a967731c5f951efc9f2cfbe52c49304 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 21 Oct 2016 06:54:45 -0400 Subject: [PATCH 001/101] - Implemented r_fullbrightignoresectorcolor from QZDoom --- src/r_bsp.cpp | 5 +++-- src/r_data/colormaps.cpp | 4 ++++ src/r_data/colormaps.h | 1 + src/r_main.cpp | 7 +++++++ src/r_segs.cpp | 11 ++++++----- src/r_things.cpp | 21 ++++++++++++++------- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.txt | 1 + 8 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 934d2d3e54..8d423b3b31 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -105,6 +105,7 @@ TArray WallPortals(1000); // note: this array needs to go away as subsector_t *InSubsector; CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? +EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); void R_StoreWallRange (int start, int stop); @@ -1108,7 +1109,7 @@ void R_Subsector (subsector_t *sub) } else { - basecolormap = frontsector->ColorMap; + basecolormap = (r_fullbrightignoresectorcolor && fixedlightlev >= 0) ? &FullNormalLight : frontsector->ColorMap; } portal = frontsector->ValidatePortal(sector_t::ceiling); @@ -1142,7 +1143,7 @@ void R_Subsector (subsector_t *sub) } else { - basecolormap = frontsector->ColorMap; + basecolormap = (r_fullbrightignoresectorcolor && fixedlightlev >= 0) ? &FullNormalLight : frontsector->ColorMap; } // killough 3/7/98: Add (x,y) offsets to flats, add deep water check diff --git a/src/r_data/colormaps.cpp b/src/r_data/colormaps.cpp index b463424634..73265b20ee 100644 --- a/src/r_data/colormaps.cpp +++ b/src/r_data/colormaps.cpp @@ -59,6 +59,7 @@ static bool R_CheckForFixedLights(const BYTE *colormaps); extern "C" { FDynamicColormap NormalLight; +FDynamicColormap FullNormalLight; //[SP] Emulate GZDoom brightness } bool NormalLightHasFixedLights; @@ -551,6 +552,9 @@ void R_InitColormaps () NormalLight.Color = PalEntry (255, 255, 255); NormalLight.Fade = 0; NormalLight.Maps = realcolormaps; + FullNormalLight.Color = PalEntry (255, 255, 255); + FullNormalLight.Fade = 0; + FullNormalLight.Maps = realcolormaps; NormalLightHasFixedLights = R_CheckForFixedLights(realcolormaps); numfakecmaps = fakecmaps.Size(); diff --git a/src/r_data/colormaps.h b/src/r_data/colormaps.h index 0764191a3c..09006fc1e9 100644 --- a/src/r_data/colormaps.h +++ b/src/r_data/colormaps.h @@ -80,6 +80,7 @@ extern BYTE DesaturateColormap[31][256]; extern "C" { extern FDynamicColormap NormalLight; +extern FDynamicColormap FullNormalLight; } extern bool NormalLightHasFixedLights; diff --git a/src/r_main.cpp b/src/r_main.cpp index 1e0de7ecc7..6f0ebcb3cc 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -455,6 +455,8 @@ void R_CopyStackedViewParameters() // //========================================================================== +EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) + void R_SetupColormap(player_t *player) { realfixedcolormap = NULL; @@ -481,6 +483,11 @@ void R_SetupColormap(player_t *player) else if (player->fixedlightlevel >= 0 && player->fixedlightlevel < NUMCOLORMAPS) { fixedlightlev = player->fixedlightlevel * 256; + // [SP] Emulate GZDoom's light-amp goggles. + if (r_fullbrightignoresectorcolor && fixedlightlev >= 0) + { + fixedcolormap = &FullNormalLight; + } } } // [RH] Inverse light for shooting the Sigil diff --git a/src/r_segs.cpp b/src/r_segs.cpp index edb1949b62..d265d626f8 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -57,6 +57,7 @@ CVAR(Bool, r_np2, true, 0) +EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); //CVAR (Int, ty, 8, 0) //CVAR (Int, tx, 8, 0) @@ -313,7 +314,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) rw_scalestep = ds->iscalestep; if (fixedlightlev >= 0) - dc_colormap = basecolormap->Maps + fixedlightlev; + dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -630,7 +631,7 @@ void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover) } if (fixedlightlev >= 0) - dc_colormap = basecolormap->Maps + fixedlightlev; + dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -1788,7 +1789,7 @@ void R_RenderSegLoop () fixed_t xoffset = rw_offset; if (fixedlightlev >= 0) - dc_colormap = basecolormap->Maps + fixedlightlev; + dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -3187,11 +3188,11 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, rw_light = rw_lightleft + (x1 - WallC.sx1) * rw_lightstep; if (fixedlightlev >= 0) - dc_colormap = usecolormap->Maps + fixedlightlev; + dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (usecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT)) - dc_colormap = usecolormap->Maps; + dc_colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : usecolormap->Maps; else calclighting = true; diff --git a/src/r_things.cpp b/src/r_things.cpp index 99ca68b601..047ee9295c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -99,6 +99,7 @@ EXTERN_CVAR (Bool, st_scale) EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Int, r_drawfuzz) EXTERN_CVAR(Bool, r_deathcamera); +CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); // // Sprite rotation 0 is facing the viewer, @@ -548,7 +549,7 @@ void R_DrawWallSprite(vissprite_t *spr) else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) - dc_colormap = usecolormap->Maps; + dc_colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : usecolormap->Maps; else calclighting = true; @@ -1066,7 +1067,8 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->deltax = float(pos.X - ViewPos.X); vis->deltay = float(pos.Y - ViewPos.Y); vis->renderflags = renderflags; - if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D + if(thing->flags5 & MF5_BRIGHT) + vis->renderflags |= RF_FULLBRIGHT; // kg3D vis->Style.RenderStyle = thing->RenderStyle; vis->FillColor = thing->fillcolor; vis->Translation = thing->Translation; // [RH] thing translation table @@ -1140,7 +1142,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor } else if (!foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT))) { // full bright - vis->Style.colormap = mybasecolormap->Maps; + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; } else { // diminished light @@ -1462,11 +1464,11 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } if (fixedlightlev >= 0) { - vis->Style.colormap = mybasecolormap->Maps + fixedlightlev; + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev); } else if (!foggy && pspr->GetState()->GetFullbright()) { // full bright - vis->Style.colormap = mybasecolormap->Maps; // [RH] use basecolormap + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; // [RH] use basecolormap } else { // local light @@ -1516,6 +1518,11 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double { noaccel = true; } + // [SP] If emulating GZDoom fullbright, disable acceleration + if (r_fullbrightignoresectorcolor && fixedlightlev >= 0) + mybasecolormap = &FullNormalLight; + if (r_fullbrightignoresectorcolor && !foggy && pspr->GetState()->GetFullbright()) + mybasecolormap = &FullNormalLight; colormap_to_use = mybasecolormap; } else @@ -2057,7 +2064,7 @@ void R_DrawSprite (vissprite_t *spr) } else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) { // full bright - spr->Style.colormap = mybasecolormap->Maps; + spr->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; } else { // diminished light @@ -2615,7 +2622,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade, } else if (particle->bright) { - vis->Style.colormap = map; + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : map; } else { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 096d0832c0..18ff6ce048 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1787,6 +1787,7 @@ DSPLYMNU_PICKUPFADE = "Pickup Flash Intensity"; DSPLYMNU_PALLETEHACK = "DirectDraw palette hack"; // Not used DSPLYMNU_ATTACHEDSURFACES = "Use attached surfaces"; // Not used DSPLYMNU_SKYMODE = "Sky render mode"; +DSPLYMNU_GZDFULLBRIGHT = "Emulate GZDoom FullBright"; DSPLYMNU_DRAWFUZZ = "Use fuzz effect"; DSPLYMNU_TRANSSOUL = "Lost Soul translucency"; DSPLYMNU_FAKECONTRAST = "Use fake contrast"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 7b06a7e7fd..765fe66744 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -682,6 +682,7 @@ OptionMenu "VideoOptions" } Option "$DSPLYMNU_SKYMODE", "r_skymode", "SkyModes" + Option "$DSPLYMNU_GZDFULLBRIGHT", "r_fullbrightignoresectorcolor", "OnOff" Option "$DSPLYMNU_DRAWFUZZ", "r_drawfuzz", "Fuzziness" Slider "$DSPLYMNU_TRANSSOUL", "transsouls", 0.25, 1.0, 0.05, 2 Option "$DSPLYMNU_FAKECONTRAST", "r_fakecontrast", "Contrast" From df6214b142cb61dda7604da4c3bf97543248d1af Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 21 Oct 2016 07:21:56 -0400 Subject: [PATCH 002/101] - Fixes --- src/r_main.cpp | 2 +- src/r_segs.cpp | 10 +++++----- src/r_things.cpp | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index 6f0ebcb3cc..4252f4155a 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -486,7 +486,7 @@ void R_SetupColormap(player_t *player) // [SP] Emulate GZDoom's light-amp goggles. if (r_fullbrightignoresectorcolor && fixedlightlev >= 0) { - fixedcolormap = &FullNormalLight; + fixedcolormap = FullNormalLight.Maps; } } } diff --git a/src/r_segs.cpp b/src/r_segs.cpp index d265d626f8..d1ec04f6d4 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -314,7 +314,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) rw_scalestep = ds->iscalestep; if (fixedlightlev >= 0) - dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); + dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -631,7 +631,7 @@ void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover) } if (fixedlightlev >= 0) - dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); + dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -1789,7 +1789,7 @@ void R_RenderSegLoop () fixed_t xoffset = rw_offset; if (fixedlightlev >= 0) - dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); + dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; @@ -3188,11 +3188,11 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, rw_light = rw_lightleft + (x1 - WallC.sx1) * rw_lightstep; if (fixedlightlev >= 0) - dc_colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (usecolormap->Maps + fixedlightlev); + dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (usecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT)) - dc_colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : usecolormap->Maps; + dc_colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : usecolormap->Maps; else calclighting = true; diff --git a/src/r_things.cpp b/src/r_things.cpp index 047ee9295c..a886244431 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -549,7 +549,7 @@ void R_DrawWallSprite(vissprite_t *spr) else if (fixedcolormap != NULL) dc_colormap = fixedcolormap; else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) - dc_colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : usecolormap->Maps; + dc_colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : usecolormap->Maps; else calclighting = true; @@ -1142,7 +1142,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor } else if (!foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT))) { // full bright - vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; } else { // diminished light @@ -1464,11 +1464,11 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } if (fixedlightlev >= 0) { - vis->Style.colormap = (r_fullbrightignoresectorcolor) ? (&FullNormalLight->Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev); + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev); } else if (!foggy && pspr->GetState()->GetFullbright()) { // full bright - vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; // [RH] use basecolormap + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; // [RH] use basecolormap } else { // local light @@ -2064,7 +2064,7 @@ void R_DrawSprite (vissprite_t *spr) } else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) { // full bright - spr->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : mybasecolormap->Maps; + spr->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; } else { // diminished light @@ -2622,7 +2622,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade, } else if (particle->bright) { - vis->Style.colormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight->Maps : map; + vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : map; } else { From 8678baf6f589a68635939a1063a28231a0aa01a1 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 21 Oct 2016 07:32:18 -0400 Subject: [PATCH 003/101] - Fullbright fixes --- src/r_data/colormaps.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/r_data/colormaps.cpp b/src/r_data/colormaps.cpp index 73265b20ee..2d3c0e49d6 100644 --- a/src/r_data/colormaps.cpp +++ b/src/r_data/colormaps.cpp @@ -73,6 +73,7 @@ struct FakeCmap TArray fakecmaps; BYTE *realcolormaps; +BYTE *realfbcolormaps; //[SP] For fullbright use size_t numfakecmaps; @@ -460,6 +461,11 @@ void R_DeinitColormaps () delete[] realcolormaps; realcolormaps = NULL; } + if (realfbcolormaps != NULL) + { + delete[] realfbcolormaps; + realfbcolormaps = NULL; + } FreeSpecialLights(); } @@ -549,12 +555,20 @@ void R_InitColormaps () } } } + + // [SP] Create a copy of the colormap + if (!realfbcolormaps) + { + realfbcolormaps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()]; + memcpy(realfbcolormaps, realcolormaps, 256*NUMCOLORMAPS*fakecmaps.Size()); + } + NormalLight.Color = PalEntry (255, 255, 255); NormalLight.Fade = 0; NormalLight.Maps = realcolormaps; FullNormalLight.Color = PalEntry (255, 255, 255); FullNormalLight.Fade = 0; - FullNormalLight.Maps = realcolormaps; + FullNormalLight.Maps = realfbcolormaps; NormalLightHasFixedLights = R_CheckForFixedLights(realcolormaps); numfakecmaps = fakecmaps.Size(); From 513f8312b35cc42fd55d73e18ddfae355893c6c8 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Fri, 21 Oct 2016 08:36:20 -0400 Subject: [PATCH 004/101] - Renamed menu option for r_fullbrightignoresectorcolor --- wadsrc/static/language.enu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 18ff6ce048..01eb692b8e 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1787,7 +1787,7 @@ DSPLYMNU_PICKUPFADE = "Pickup Flash Intensity"; DSPLYMNU_PALLETEHACK = "DirectDraw palette hack"; // Not used DSPLYMNU_ATTACHEDSURFACES = "Use attached surfaces"; // Not used DSPLYMNU_SKYMODE = "Sky render mode"; -DSPLYMNU_GZDFULLBRIGHT = "Emulate GZDoom FullBright"; +DSPLYMNU_GZDFULLBRIGHT = "Fullbright overrides sector color"; DSPLYMNU_DRAWFUZZ = "Use fuzz effect"; DSPLYMNU_TRANSSOUL = "Lost Soul translucency"; DSPLYMNU_FAKECONTRAST = "Use fake contrast"; From e0efdd97b378b4a63ebb8c8bc6dce009609e7297 Mon Sep 17 00:00:00 2001 From: raa-eruanna Date: Mon, 26 Sep 2016 07:24:37 -0400 Subject: [PATCH 005/101] - Added: PlayerPawn property "Player.ViewBob" which acts as a MoveBob/StillBob multiplier. --- src/d_player.h | 3 +++ src/p_pspr.cpp | 5 +++-- src/p_user.cpp | 8 +++++--- src/thingdef/thingdef_properties.cpp | 20 ++++++++++++++++++++ wadsrc/static/actors/shared/player.txt | 1 + 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e944d67348..7f57837c70 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -168,6 +168,9 @@ public: // [CW] Fades for when you are being damaged. PalEntry DamageFade; + // [SP] ViewBob Multiplier + double ViewBob; + bool UpdateWaterLevel (bool splash); bool ResetAirSupply (bool playgasp = true); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index e5b076acdc..abbd2284ee 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -582,8 +582,9 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac) if (curbob != 0) { - float bobx = float(player->bob * Rangex); - float boby = float(player->bob * Rangey); + //[SP] Added in decorate player.viewbob checks + float bobx = float(player->bob * Rangex * (float)player->mo->ViewBob); + float boby = float(player->bob * Rangey * (float)player->mo->ViewBob); switch (bobstyle) { case AWeapon::BobNormal: diff --git a/src/p_user.cpp b/src/p_user.cpp index 0f3b6a516d..845cf9a5f4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -651,7 +651,8 @@ void APlayerPawn::Serialize(FSerializer &arc) ("fallingscreammaxn", FallingScreamMaxSpeed, def->FallingScreamMaxSpeed) ("userange", UseRange, def->UseRange) ("aircapacity", AirCapacity, def->AirCapacity) - ("viewheight", ViewHeight, def->ViewHeight); + ("viewheight", ViewHeight, def->ViewHeight) + ("viewbob", ViewBob, def->ViewBob); } //=========================================================================== @@ -1844,11 +1845,12 @@ void P_CalcHeight (player_t *player) return; } + //[SP] Added (x*player->mo->ViewBob) to allow DECORATE changes to view bobbing speed. if (still) { if (player->health > 0) { - angle = level.time / (120 * TICRATE / 35.) * 360.; + angle = level.time / (120 * TICRATE / 35.) * 360. * player->mo->ViewBob; bob = player->userinfo.GetStillBob() * angle.Sin(); } else @@ -1858,7 +1860,7 @@ void P_CalcHeight (player_t *player) } else { - angle = level.time / (20 * TICRATE / 35.) * 360.; + angle = level.time / (20 * TICRATE / 35.) * 360. * player->mo->ViewBob; bob = player->bob * angle.Sin() * (player->mo->waterlevel > 1 ? 0.25f : 0.5f); } diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 80ee6c22fc..6321ebfe99 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2945,6 +2945,26 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss } } +//========================================================================== +// +// [SP] Player.Viewbob +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn) +{ + PROP_DOUBLE_PARM(z, 0); + // [SP] Hard limits. This is to prevent terrywads from making players sick. + // Remember - this messes with a user option who probably has it set a + // certain way for a reason. I think a 1.5 limit is pretty generous, but + // it may be safe to increase it. I really need opinions from people who + // could be affected by this. + if (z < 0.0 || z > 1.5) + { + I_Error("ViewBob must be between 0.0 and 1.5."); + } + defaults->ViewBob = z; +} + //========================================================================== // //========================================================================== diff --git a/wadsrc/static/actors/shared/player.txt b/wadsrc/static/actors/shared/player.txt index ac5ceb0a7a..08d9a252ac 100644 --- a/wadsrc/static/actors/shared/player.txt +++ b/wadsrc/static/actors/shared/player.txt @@ -33,6 +33,7 @@ Actor PlayerPawn : Actor native Player.MugShotMaxHealth 0 Player.FlechetteType "ArtiPoisonBag3" Player.AirCapacity 1 + Player.ViewBob 1 Obituary "$OB_MPDEFAULT" } From 21b690a3c77377e18a3e004d4e556701f93a4ac1 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Thu, 20 Oct 2016 17:52:32 +0800 Subject: [PATCH 006/101] Fixed: Player.ViewBob should be multiplying the bobbing height in P_CalcHeight, not the velocity of the bobbing. This mimics the act of the user altering their movebob CVar to compensate for non-standard player movement speeds. --- src/p_user.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 845cf9a5f4..e487120429 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1845,12 +1845,11 @@ void P_CalcHeight (player_t *player) return; } - //[SP] Added (x*player->mo->ViewBob) to allow DECORATE changes to view bobbing speed. if (still) { if (player->health > 0) { - angle = level.time / (120 * TICRATE / 35.) * 360. * player->mo->ViewBob; + angle = level.time / (120 * TICRATE / 35.) * 360.; bob = player->userinfo.GetStillBob() * angle.Sin(); } else @@ -1860,7 +1859,7 @@ void P_CalcHeight (player_t *player) } else { - angle = level.time / (20 * TICRATE / 35.) * 360. * player->mo->ViewBob; + angle = level.time / (20 * TICRATE / 35.) * 360.; bob = player->bob * angle.Sin() * (player->mo->waterlevel > 1 ? 0.25f : 0.5f); } @@ -1893,7 +1892,7 @@ void P_CalcHeight (player_t *player) { bob = 0; } - player->viewz = player->mo->Z() + player->viewheight + bob; + player->viewz = player->mo->Z() + player->viewheight + (bob * player->mo->ViewBob); // [SP] Allow DECORATE changes to view bobbing speed. if (player->mo->Floorclip && player->playerstate != PST_DEAD && player->mo->Z() <= player->mo->floorz) { From b1289fa783019b9fedb4229be792b5e766d09018 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 21 Oct 2016 18:13:59 +0200 Subject: [PATCH 007/101] - fixed: The serialiter functionfor FDoorAnimation accessed the invalid destination pointer when loading a savegame. --- src/textures/animations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index f46289f073..06c496d9a3 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -1002,7 +1002,7 @@ void FTextureManager::UpdateAnimations (DWORD mstime) template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&p, FDoorAnimation **def) { - FTextureID tex = p->BaseTexture; + FTextureID tex = p? p->BaseTexture : FNullTextureID(); Serialize(arc, key, tex, def ? &(*def)->BaseTexture : nullptr); if (arc.isReading()) { From 5c596d3797fe5a322485f2b865f02314524b45e1 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 21 Oct 2016 22:08:12 -0500 Subject: [PATCH 008/101] Change VM to increment PC after each instruction rather than before - VC++ generated horribly stupid code for x64 when incrementing pc at the beginning of each instruction by storing hundreds of copies of it for every opcode executed. Incrementing pc at the end avoids this madness. - It is possible I messed something up with this change. Hopefully not. --- src/zscript/vmexec.cpp | 22 +++++++++++----------- src/zscript/vmexec.h | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 454f02d03f..7ee89329ad 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -11,21 +11,21 @@ #if COMPGOTO #define OP(x) x -#define NEXTOP do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0) +#define NEXTOP do { pc++; unsigned op = pc->op; a = pc->a; goto *ops[op]; } while(0) #else #define OP(x) case OP_##x -#define NEXTOP break +#define NEXTOP pc++; break #endif #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -#define A (pc[-1].a) -#define B (pc[-1].b) -#define C (pc[-1].c) -#define Cs (pc[-1].cs) -#define BC (pc[-1].i16u) -#define BCs (pc[-1].i16) -#define ABCs (pc[-1].i24) +#define A (pc[0].a) +#define B (pc[0].b) +#define C (pc[0].c) +#define Cs (pc[0].cs) +#define BC (pc[0].i16u) +#define BCs (pc[0].i16) +#define ABCs (pc[0].i24) #define JMPOFS(x) ((x)->i24) #define KC (konstd[C]) @@ -48,8 +48,8 @@ #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ - assert(pc->op == OP_JMP); \ - pc += 1 + JMPOFS(pc); \ + assert(pc[1].op == OP_JMP); \ + pc += 1 + JMPOFS(pc+1); \ } else { \ pc += 1; \ } diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index adf2986c50..3637f2c1cd 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -52,11 +52,17 @@ begin: { #if !COMPGOTO VM_UBYTE op; - for(;;) switch(op = pc->op, a = pc->a, pc++, op) + for(;;) switch(op = pc->op, a = pc->a, op) #else + pc--; NEXTOP; #endif { +#if !COMPGOTO + default: + assert(0 && "Undefined opcode hit"); + NEXTOP; +#endif OP(LI): ASSERTD(a); reg.d[a] = BCs; @@ -367,13 +373,13 @@ begin: } NEXTOP; OP(JMP): - pc += JMPOFS(pc - 1); + pc += JMPOFS(pc); NEXTOP; OP(IJMP): ASSERTD(a); pc += (BCs + reg.d[a]); - assert(pc->op == OP_JMP); - pc += 1 + JMPOFS(pc); + assert(pc[1].op == OP_JMP); + pc += 1 + JMPOFS(pc+1); NEXTOP; OP(PARAMI): assert(f->NumParam < sfunc->MaxParam); @@ -490,7 +496,7 @@ begin: VMReturn returns[MAX_RETURNS]; int numret; - FillReturns(reg, f, returns, pc, C); + FillReturns(reg, f, returns, pc+1, C); if (call->Native) { numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C); @@ -603,8 +609,8 @@ begin: { THROW(X_TOO_MANY_TRIES); } - assert((pc + JMPOFS(pc - 1))->op == OP_CATCH); - exception_frames[try_depth++] = pc + JMPOFS(pc - 1); + assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH); + exception_frames[try_depth++] = pc + JMPOFS(pc) + 1; NEXTOP; OP(UNTRY): assert(a <= try_depth); @@ -704,8 +710,8 @@ begin: } if (cmp == (a & CMP_CHECK)) { - assert(pc->op == OP_JMP); - pc += 1 + JMPOFS(pc); + assert(pc[1].op == OP_JMP); + pc += 1 + JMPOFS(pc+1); } else { From 853e49a0779627873a2d52818edf800fc6804991 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 22 Oct 2016 09:57:26 +0200 Subject: [PATCH 009/101] - fixed: R_InitSkyMap must check for the null texture which cannot be used as a sky because it has no bitmap and will cause an access violation in the sky cap color calculation. --- src/r_sky.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/r_sky.cpp b/src/r_sky.cpp index 37312cbaee..f29929c262 100644 --- a/src/r_sky.cpp +++ b/src/r_sky.cpp @@ -76,10 +76,20 @@ void R_InitSkyMap () int skyheight; FTexture *skytex1, *skytex2; + // Do not allow the null texture which has no bitmap and will crash. + if (sky1texture.isNull()) + { + sky1texture = TexMan.CheckForTexture("-noflat-", FTexture::TEX_Any); + } + if (sky2texture.isNull()) + { + sky2texture = TexMan.CheckForTexture("-noflat-", FTexture::TEX_Any); + } + skytex1 = TexMan(sky1texture, true); skytex2 = TexMan(sky2texture, true); - if (skytex1 == NULL) + if (skytex1 == nullptr) return; if ((level.flags & LEVEL_DOUBLESKY) && skytex1->GetHeight() != skytex2->GetHeight()) From 31f01d076e92afb27ef1ed62476c64d68b239c60 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 22 Oct 2016 20:27:02 -0500 Subject: [PATCH 010/101] Fixed: Decals calculated "lighting" wrong - Instead of calculating lighting based from the left edge of the wall segment the decal was on, it was calculated from the left edge of the wall instead. --- src/r_segs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index d1ec04f6d4..48d8f1651a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -3186,7 +3186,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, rereadcolormap = false; } - rw_light = rw_lightleft + (x1 - WallC.sx1) * rw_lightstep; + rw_light = rw_lightleft + (x1 - savecoord.sx1) * rw_lightstep; if (fixedlightlev >= 0) dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (usecolormap->Maps + fixedlightlev); else if (fixedcolormap != NULL) From 5ba5da0dcc3deb9fbce0da00e9a7d804aeb5aea7 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 22 Oct 2016 20:56:31 -0500 Subject: [PATCH 011/101] Fixed: Loading a savegame momentarily left players with undefined pitch limits - This was only visible when using a screen wipe because the initial frame wiped to would clamp the pitch to whatever undefined pitch range the player had before the proper range was received. --- src/p_saveg.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 46cdd767b4..c2f79a5c64 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -638,6 +638,12 @@ static void ReadOnePlayer(FSerializer &arc, bool skipload) playerTemp.Serialize(arc); if (!skipload) { + // This temp player has undefined pitch limits, so set them to something + // that should leave the pitch stored in the savegame intact when + // rendering. The real pitch limits will be set by P_SerializePlayers() + // via a net command, but that won't be processed in time for a screen + // wipe, so we need something here. + playerTemp.MaxPitch = playerTemp.MinPitch = playerTemp.mo->Angles.Pitch; CopyPlayer(&players[i], &playerTemp, name); } else From fbe2b76705a8e08a1bf6898780bf9e6b2a2e50e0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 23 Oct 2016 19:08:43 +0200 Subject: [PATCH 012/101] - fixed checks in sprite sorting logic. There were some missing parentheses. --- src/gl/scene/gl_drawinfo.cpp | 2 +- src/gl/scene/gl_wall.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index d1dd60c4f1..e4722b3dbe 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -536,7 +536,7 @@ void GLDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort) const bool drawBillboardFacingCamera = gl_billboard_faces_camera; // [Nash] has +ROLLSPRITE - const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE); + const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & (RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE)); // cannot sort them at the moment. This requires more complex splitting. if (drawWithXYBillboard || drawBillboardFacingCamera || rotated) diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 143029ba74..bdee5761fe 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -66,7 +66,7 @@ struct GLSeg // we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim float x = y2 - y1; float y = x1 - x2; - float length = sqrt(x*x + y*y); + float length = sqrtf(x*x + y*y); return FVector3(x / length, 0, y / length); } }; From bea625a42c9aa0d854ae98e55a8a55945709730d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 23 Oct 2016 20:42:48 +0200 Subject: [PATCH 013/101] - added an ATTENUATE flag to dynamic lights, this is set by default for attached lights. For placed lights this is off, because it'd interfere with many existing maps that depend on unattenuated lights. --- src/gl/dynlights/gl_dynlight.cpp | 1 + src/gl/dynlights/gl_dynlight.h | 1 + src/gl/dynlights/gl_dynlight1.cpp | 2 +- wadsrc/static/shaders/glsl/main.fp | 17 ++++++++++------- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index ae19ecf608..40008e3ad5 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -1082,6 +1082,7 @@ void gl_AttachLight(AActor *actor, unsigned int count, const FLightDefaults *lig light->target = actor; light->owned = true; light->ObjectFlags |= OF_Transient; + light->flags4 |= MF4_ATTENUATE; actor->dynamiclights.Push(light); } light->flags2&=~MF2_DORMANT; diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index 84965e3185..c51e0c79d8 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -50,6 +50,7 @@ enum #define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE #define MF4_ADDITIVE MF4_MISSILEMORE #define MF4_DONTLIGHTSELF MF4_SEESDAGGERS +#define MF4_ATTENUATE MF4_INCOMBAT enum ELightType { diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index d20f5c01b1..2f8ef44edc 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -116,7 +116,7 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD data[4] = r; data[5] = g; data[6] = b; - data[7] = 0; + data[7] = !!(light->flags4 & MF4_ATTENUATE); return true; } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index fb1983fc73..36db31f681 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -142,16 +142,19 @@ float diffuseContribution(vec3 lightDirection, vec3 normal) // //=========================================================================== -float pointLightAttenuation(vec4 lightpos) +float pointLightAttenuation(vec4 lightpos, float attenuate) { float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - #if 0 + if (attenuate == 0.0) + { return attenuation; - #else + } + else + { vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); float diffuseAmount = diffuseContribution(lightDirection, normalize(vWorldNormal.xyz)); return attenuation * diffuseAmount; - #endif + } } //=========================================================================== @@ -229,7 +232,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= pointLightAttenuation(lightpos); + lightcolor.rgb *= pointLightAttenuation(lightpos, lightcolor.a); dynlight.rgb += lightcolor.rgb; } // @@ -240,7 +243,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= pointLightAttenuation(lightpos); + lightcolor.rgb *= pointLightAttenuation(lightpos, lightcolor.a); dynlight.rgb -= lightcolor.rgb; } } @@ -322,7 +325,7 @@ void main() vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= pointLightAttenuation(lightpos); + lightcolor.rgb *= pointLightAttenuation(lightpos, lightcolor.a); addlight.rgb += lightcolor.rgb; } frag.rgb = clamp(frag.rgb + desaturate(addlight).rgb, 0.0, 1.0); From 93ec6eb92e4e550ed8b126d6f53acbf933b4f7f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 24 Oct 2016 22:22:47 +0200 Subject: [PATCH 014/101] - fixed DACSThinker did not save its LastScript member. This was probably responsible for some weird behavior recently, but with the addition of the OF_Transient flag this outright crashed because it left NULL pointers on reload in places where they weren't checked for. --- src/p_acs.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index fcbff904a8..f36aaaf69a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2907,7 +2907,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, SavingRunningscript &r void DACSThinker::Serialize(FSerializer &arc) { Super::Serialize(arc); - arc("scripts", Scripts); + arc("scripts", Scripts) + ("lastscript", LastScript); if (arc.isWriting()) { From 4e4fd97950c8b844a235c890f176c9233590bb18 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 24 Oct 2016 23:35:18 +0200 Subject: [PATCH 015/101] - fixed: Multipatch textures may not set up their patch references until all textures have been loaded. If done earlier they will not be able to detect overrides of sprites and graphics which are not part of the PATCHES lump. There was some fudging code to work around this problem but it was only partially working. Now these textures only collect the texture name and use type during setup and resolve them after all textures have been created. --- src/textures/multipatchtexture.cpp | 187 ++++++++++++++++------------- src/textures/texturemanager.cpp | 4 + src/textures/textures.h | 1 + 3 files changed, 110 insertions(+), 82 deletions(-) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index b0db481a89..741f88a31c 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -48,6 +48,7 @@ #include "v_palette.h" #include "v_video.h" #include "v_text.h" +#include "cmdlib.h" #include "m_fixed.h" #include "textures/textures.h" #include "r_data/colormaps.h" @@ -138,7 +139,6 @@ struct strifemaptexture_t struct FPatchLookup { FString Name; - FTexture *Texture; }; @@ -166,6 +166,7 @@ public: int GetSourceLump() { return DefinitionLump; } FTexture *GetRedirect(bool wantwarped); FTexture *GetRawTexture(); + void ResolvePatches(); protected: BYTE *Pixels; @@ -185,8 +186,18 @@ protected: TexPart(); }; + struct TexInit + { + FString TexName; + int UseType = TEX_Null; + bool Silent = false; + bool HasLine = false; + FScriptPosition sc; + }; + int NumParts; TexPart *Parts; + TexInit *Inits; bool bRedirect:1; bool bTranslucentPatches:1; @@ -194,7 +205,7 @@ protected: private: void CheckForHacks (); - void ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype); + void ParsePatch(FScanner &sc, TexPart & part, TexInit &init); }; //========================================================================== @@ -204,7 +215,7 @@ private: //========================================================================== FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum) -: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false) +: Pixels (0), Spans(0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false) { union { @@ -240,7 +251,8 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl } UseType = FTexture::TEX_Wall; - Parts = NumParts > 0 ? new TexPart[NumParts] : NULL; + Parts = NumParts > 0 ? new TexPart[NumParts] : nullptr; + Inits = NumParts > 0 ? new TexInit[NumParts] : nullptr; Width = SAFESHORT(mtexture.d->width); Height = SAFESHORT(mtexture.d->height); Name = (char *)mtexture.d->name; @@ -272,17 +284,9 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl } Parts[i].OriginX = LittleShort(mpatch.d->originx); Parts[i].OriginY = LittleShort(mpatch.d->originy); - Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture; - if (Parts[i].Texture == NULL) - { - Printf(TEXTCOLOR_RED "Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name.GetChars(), Name.GetChars()); - NumParts--; - i--; - } - else - { - Parts[i].Texture->bKeepAround = true; - } + Parts[i].Texture = nullptr; + Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name; + Inits[i].UseType = TEX_WallPatch; if (strife) mpatch.s++; else @@ -295,17 +299,6 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl CheckForHacks (); - // If this texture is just a wrapper around a single patch, we can simply - // forward GetPixels() and GetColumn() calls to that patch. - if (NumParts == 1) - { - if (Parts->OriginX == 0 && Parts->OriginY == 0 && - Parts->Texture->GetWidth() == Width && - Parts->Texture->GetHeight() == Height) - { - bRedirect = true; - } - } DefinitionLump = deflumpnum; } @@ -327,6 +320,11 @@ FMultiPatchTexture::~FMultiPatchTexture () delete[] Parts; Parts = NULL; } + if (Inits != nullptr) + { + delete[] Inits; + Inits = nullptr; + } if (Spans != NULL) { FreeSpans (Spans); @@ -863,19 +861,6 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d pnames.Read(pname, 8); pname[8] = '\0'; patchlookup[i].Name = pname; - FTextureID j = CheckForTexture (patchlookup[i].Name, FTexture::TEX_WallPatch); - if (j.isValid()) - { - patchlookup[i].Texture = Textures[j.GetIndex()].Texture; - } - else - { - // Shareware Doom has the same PNAMES lump as the registered - // Doom, so printing warnings for patches that don't really - // exist isn't such a good idea. - //Printf ("Patch %s not found.\n", patchlookup[i].Name); - patchlookup[i].Texture = NULL; - } } } @@ -996,35 +981,13 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump) // //========================================================================== -void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype) +void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) { FString patchname; + int Mirror = 0; sc.MustGetString(); - FTextureID texno = TexMan.CheckForTexture(sc.String, usetype); - int Mirror = 0; - - if (!texno.isValid()) - { - if (strlen(sc.String) <= 8 && !strpbrk(sc.String, "./")) - { - int lumpnum = Wads.CheckNumForName(sc.String, usetype == TEX_MiscPatch? ns_graphics : ns_patches); - if (lumpnum >= 0) - { - part.Texture = FTexture::CreateTexture(lumpnum, usetype); - TexMan.AddTexture(part.Texture); - } - } - } - else - { - part.Texture = TexMan[texno]; - bComplex |= part.Texture->bComplex; - } - if (part.Texture == NULL) - { - if (!silent) sc.ScriptMessage(TEXTCOLOR_RED "Unknown patch '%s' in texture '%s'\n", sc.String, Name.GetChars()); - } + init.TexName = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); part.OriginX = sc.Number; @@ -1207,6 +1170,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) : Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false) { TArray parts; + TArray inits; bool bSilent = false; bMultiPatch = true; @@ -1267,16 +1231,34 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) else if (sc.Compare("Patch")) { TexPart part; - ParsePatch(sc, part, bSilent, TEX_WallPatch); - if (part.Texture != NULL) parts.Push(part); + TexInit init; + ParsePatch(sc, part, init); + if (init.TexName.IsNotEmpty()) + { + parts.Push(part); + init.UseType = TEX_WallPatch; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + inits.Push(init); + } part.Texture = NULL; part.Translation = NULL; } else if (sc.Compare("Graphic")) { TexPart part; - ParsePatch(sc, part, bSilent, TEX_MiscPatch); - if (part.Texture != NULL) parts.Push(part); + TexInit init; + ParsePatch(sc, part, init); + if (init.TexName.IsNotEmpty()) + { + parts.Push(part); + init.UseType = TEX_MiscPatch; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + inits.Push(init); + } part.Texture = NULL; part.Translation = NULL; } @@ -1297,21 +1279,10 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) NumParts = parts.Size(); Parts = new TexPart[NumParts]; memcpy(Parts, &parts[0], NumParts * sizeof(*Parts)); - - //CalcBitSize (); - - // If this texture is just a wrapper around a single patch, we can simply - // forward GetPixels() and GetColumn() calls to that patch. - if (NumParts == 1) + Inits = new TexInit[NumParts]; + for (int i = 0; i < NumParts; i++) { - if (Parts->OriginX == 0 && Parts->OriginY == 0 && - Parts->Texture->GetWidth() == Width && - Parts->Texture->GetHeight() == Height && - Parts->Rotate == 0 && - !bComplex) - { - bRedirect = true; - } + Inits[i] = inits[i]; } } @@ -1328,6 +1299,58 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) } +void FMultiPatchTexture::ResolvePatches() +{ + if (Inits != nullptr) + { + for (int i = 0; i < NumParts; i++) + { + FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType); + + if (!texno.isValid()) + { + if (!Inits[i].Silent) + { + if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); + else Printf(TEXTCOLOR_YELLOW "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); + } + } + else + { + Parts[i].Texture = TexMan[texno]; + bComplex |= Parts[i].Texture->bComplex; + Parts[i].Texture->bKeepAround = true; + } + } + for (int i = 0; i < NumParts; i++) + { + if (Parts[i].Texture == nullptr) + { + memcpy(&Parts[i], &Parts[i + 1], NumParts - i - 1); + i--; + NumParts--; + } + } + } + delete[] Inits; + Inits = nullptr; + + // If this texture is just a wrapper around a single patch, we can simply + // forward GetPixels() and GetColumn() calls to that patch. + + if (NumParts == 1) + { + if (Parts->OriginX == 0 && Parts->OriginY == 0 && + Parts->Texture->GetWidth() == Width && + Parts->Texture->GetHeight() == Height && + Parts->Rotate == 0 && + !bComplex) + { + bRedirect = true; + } + } +} + void FTextureManager::ParseXTexture(FScanner &sc, int usetype) { diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 3fb01dc6cf..07ed71a3bb 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -981,6 +981,10 @@ void FTextureManager::Init() { AddTexturesForWad(i); } + for (unsigned i = 0; i < Textures.Size(); i++) + { + Textures[i].Texture->ResolvePatches(); + } // Add one marker so that the last WAD is easier to handle and treat // Build tiles as a completely separate block. diff --git a/src/textures/textures.h b/src/textures/textures.h index ad1d9ba8c2..407500f185 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -209,6 +209,7 @@ public: int GetScaledTopOffset () { int foo = int((TopOffset * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } double GetScaledLeftOffsetDouble() { return LeftOffset / Scale.X; } double GetScaledTopOffsetDouble() { return TopOffset / Scale.Y; } + virtual void ResolvePatches() {} virtual void SetFrontSkyLayer(); From 8368272b4d5848d2f6596d5350164b3902194e94 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 24 Oct 2016 23:40:37 +0200 Subject: [PATCH 016/101] - just to be thorough, added a 'sprite' keyword to define a patch to give priority to the TEX_Sprite namespace. --- src/textures/multipatchtexture.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 741f88a31c..340376a25b 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1245,6 +1245,23 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) part.Texture = NULL; part.Translation = NULL; } + else if (sc.Compare("Sprite")) + { + TexPart part; + TexInit init; + ParsePatch(sc, part, init); + if (init.TexName.IsNotEmpty()) + { + parts.Push(part); + init.UseType = TEX_Sprite; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + inits.Push(init); + } + part.Texture = NULL; + part.Translation = NULL; + } else if (sc.Compare("Graphic")) { TexPart part; From dad89b07830f649af1e26cba15990328e517ddf6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Oct 2016 01:03:44 +0200 Subject: [PATCH 017/101] - fixed: Portals with disconnected parts were not grouped correctly. --- src/portal.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/portal.cpp b/src/portal.cpp index cef79820fe..f1454cdc6c 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -1024,7 +1024,8 @@ void P_CreateLinkedPortals() { if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL && sectors[i].PortalGroup == 0) { - CollectSectors(sectors[i].GetOppositePortalGroup(j), §ors[i]); + auto p = sectors[i].GetPortal(j); + CollectSectors(p->mOrigin->PortalGroup, §ors[i]); } } } From 043e761eec6dd8952bbe9b8a3dc65e9b4bc164f4 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sun, 23 Oct 2016 06:06:59 -0400 Subject: [PATCH 018/101] - Implemented sv_singleplayerrespawn --- src/g_game.cpp | 3 ++- src/g_level.cpp | 4 +++- src/p_mobj.cpp | 5 +++-- src/p_user.cpp | 5 ++++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 48bda24f5f..b0c8775fc5 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1655,9 +1655,10 @@ static void G_QueueBody (AActor *body) // // G_DoReborn // +EXTERN_CVAR(Bool, sv_singleplayerrespawn) void G_DoReborn (int playernum, bool freshbot) { - if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN)) + if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN) && !sv_singleplayerrespawn) { if (BackupSaveName.Len() > 0 && FileExists (BackupSaveName.GetChars())) { // Load game from the last point it was saved diff --git a/src/g_level.cpp b/src/g_level.cpp index 119cde378d..d3a8c4015a 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -526,6 +526,8 @@ static bool unloading; // //========================================================================== +EXTERN_CVAR(Bool, sv_singleplayerrespawn) + void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill) { level_info_t *nextinfo = NULL; @@ -634,7 +636,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill // If this is co-op, respawn any dead players now so they can // keep their inventory on the next map. - if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN) && !deathmatch && player->playerstate == PST_DEAD) + if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn) && !deathmatch && player->playerstate == PST_DEAD) { // Copied from the end of P_DeathThink [[ player->cls = NULL; // Force a new class if the player is using a random class diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8f926ea77f..3e20118784 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1,4 +1,4 @@ -// Emacs style mode select -*- C++ -*- +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ @@ -4495,6 +4495,7 @@ void AActor::AdjustFloorClip () // Most of the player structure stays unchanged between levels. // EXTERN_CVAR (Bool, chasedemo) +EXTERN_CVAR(Bool, sv_singleplayerrespawn) extern bool demonew; @@ -4682,7 +4683,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { // Give all cards in death match mode. p->mo->GiveDeathmatchInventory (); } - else if ((multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) && state == PST_REBORN && oldactor != NULL) + else if ((multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN) || sv_singleplayerrespawn) && state == PST_REBORN && oldactor != NULL) { // Special inventory handling for respawning in coop p->mo->FilterCoopRespawnInventory (oldactor); } diff --git a/src/p_user.cpp b/src/p_user.cpp index e487120429..6ac39c2a5c 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -68,6 +68,7 @@ static FRandom pr_skullpop ("SkullPop"); // Variables for prediction CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_LATCH) CUSTOM_CVAR(Float, cl_predict_lerpscale, 0.05f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { @@ -2211,7 +2212,9 @@ void P_DeathThink (player_t *player) if (level.time >= player->respawn_time || ((player->cmd.ucmd.buttons & BT_USE) && player->Bot == NULL)) { player->cls = NULL; // Force a new class if the player is using a random class - player->playerstate = (multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) ? PST_REBORN : PST_ENTER; + player->playerstate = + (multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN) || sv_singleplayerrespawn) + ? PST_REBORN : PST_ENTER; if (player->mo->special1 > 2) { player->mo->special1 = 0; From 623910bd2ae0594479a9e3f1c05ca4c57d52ae5e Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sun, 23 Oct 2016 08:14:54 -0400 Subject: [PATCH 019/101] - Putting the CVAR definition right in the middle of prediction stuff probably wasn't the best idea. --- src/p_user.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 6ac39c2a5c..b7bd4c2ec4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -65,10 +65,12 @@ static FRandom pr_skullpop ("SkullPop"); // [RH] # of ticks to complete a turn180 #define TURN180_TICKS ((TICRATE / 4) + 1) +// [SP] Allows respawn in single player +CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_LATCH) + // Variables for prediction CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_LATCH) CUSTOM_CVAR(Float, cl_predict_lerpscale, 0.05f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { From 81449728d7a6217460e9e451eca20232e86a3316 Mon Sep 17 00:00:00 2001 From: MaxED Date: Mon, 24 Oct 2016 14:13:40 +0300 Subject: [PATCH 020/101] Allows loading directories as IWADs using "-iwad" command line parameter. --- src/d_iwad.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 1fc63e03d3..6fa8604a0c 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -292,6 +292,7 @@ void FIWadManager::ParseIWadInfos(const char *fn) int FIWadManager::ScanIWAD (const char *iwad) { FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true); + if (iwadfile == NULL) iwadfile = FResourceFile::OpenDirectory(iwad, true); //mxd. A directory can also work as an IWAD if (iwadfile != NULL) { @@ -344,7 +345,7 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads) iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars()); FixPathSeperator (iwad); - if (FileExists (iwad)) + if (DirEntryExists(iwad)) { wads[i].Type = ScanIWAD (iwad); if (wads[i].Type != -1) @@ -413,7 +414,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } else { - DefaultExtension (custwad, ".wad"); + if(FileExists(custwad)) DefaultExtension (custwad, ".wad"); //mxd. Don't treat folders as .wads iwadparm = custwad; mIWadNames[0] = custwad; CheckIWAD ("", &wads[0]); From fa8e05d56d908d0eb654770685eb9b904152a99c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Oct 2016 22:40:58 +0200 Subject: [PATCH 021/101] - do not allow a multipatch texture to use itself as patch. Instead, look for an older texture with the same name. --- src/textures/multipatchtexture.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 340376a25b..cb2d5d803d 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1323,6 +1323,24 @@ void FMultiPatchTexture::ResolvePatches() for (int i = 0; i < NumParts; i++) { FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType); + if (texno == id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. + { + TArray list; + TexMan.ListTextures(Inits[i].TexName, list); + for (int i = list.Size() - 1; i >= 0; i--) + { + if (list[i] != id && !TexMan[list[i]]->bMultiPatch) + { + texno = list[i]; + break; + } + } + if (texno == id) + { + if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); + else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); + } + } if (!texno.isValid()) { From 316e3395adec1fea9965317339a4641620979eaa Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 26 Oct 2016 12:08:03 +0300 Subject: [PATCH 022/101] Fixed crash on loading multipatch texture with height of 256 http://forum.zdoom.org/viewtopic.php?t=53953 --- src/textures/multipatchtexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index cb2d5d803d..e1e6faf3e5 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -297,8 +297,6 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl Printf ("Texture %s is left without any patches\n", Name.GetChars()); } - CheckForHacks (); - DefinitionLump = deflumpnum; } @@ -1370,6 +1368,8 @@ void FMultiPatchTexture::ResolvePatches() delete[] Inits; Inits = nullptr; + CheckForHacks(); + // If this texture is just a wrapper around a single patch, we can simply // forward GetPixels() and GetColumn() calls to that patch. From 28fefdabc76efef99d81f53e63552a9e570b6786 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 26 Oct 2016 11:56:15 +0200 Subject: [PATCH 023/101] - added a 'listall' option to FTextureManager::ListTextures, so that the multipatchtexture lookup can find multiple older versions with the same use type. This fixes an issue with DUMP 2 which looked for patches of the same name as the texture currently being defined and where the patches had the same use type as the composite texture. The function as implemented would only find the newly added composite and print an error. --- src/textures/multipatchtexture.cpp | 2 +- src/textures/texturemanager.cpp | 13 ++++++++----- src/textures/textures.h | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index e1e6faf3e5..12cc02ea98 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1324,7 +1324,7 @@ void FMultiPatchTexture::ResolvePatches() if (texno == id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. { TArray list; - TexMan.ListTextures(Inits[i].TexName, list); + TexMan.ListTextures(Inits[i].TexName, list, true); for (int i = list.Size() - 1; i >= 0; i--) { if (list[i] != id && !TexMan[list[i]]->bMultiPatch) diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 07ed71a3bb..aa760c2217 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -267,7 +267,7 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF // //========================================================================== -int FTextureManager::ListTextures (const char *name, TArray &list) +int FTextureManager::ListTextures (const char *name, TArray &list, bool listall) { int i; @@ -293,11 +293,14 @@ int FTextureManager::ListTextures (const char *name, TArray &list) // NULL textures must be ignored. if (tex->UseType!=FTexture::TEX_Null) { - unsigned int j; - for(j = 0; j < list.Size(); j++) + unsigned int j = list.Size(); + if (!listall) { - // Check for overriding definitions from newer WADs - if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break; + for (j = 0; j < list.Size(); j++) + { + // Check for overriding definitions from newer WADs + if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break; + } } if (j==list.Size()) list.Push(FTextureID(i)); } diff --git a/src/textures/textures.h b/src/textures/textures.h index 407500f185..064610f50a 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -350,7 +350,7 @@ public: FTextureID CheckForTexture (const char *name, int usetype, BITFIELD flags=TEXMAN_TryAny); FTextureID GetTexture (const char *name, int usetype, BITFIELD flags=0); - int ListTextures (const char *name, TArray &list); + int ListTextures (const char *name, TArray &list, bool listall = false); void AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup=0, bool texture1=false); void AddTexturesLumps (int lump1, int lump2, int patcheslump); From 5309209039be90040306786a6e0478fcd9389227 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 26 Oct 2016 12:03:28 +0200 Subject: [PATCH 024/101] - print a developer warning if the texture manager had to resolve a circular reference. --- src/textures/multipatchtexture.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 12cc02ea98..860c59b3a9 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1338,6 +1338,11 @@ void FMultiPatchTexture::ResolvePatches() if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); } + else + { + // If it could be resolved, just print a developer warning. + DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s", Inits[i].TexName.GetChars()); + } } if (!texno.isValid()) From 12ce76426e7902238f85b3bd4318a77cd7889f04 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 26 Oct 2016 12:13:57 +0200 Subject: [PATCH 025/101] Revert "Allows loading directories as IWADs using "-iwad" command line parameter." This reverts commit 81449728d7a6217460e9e451eca20232e86a3316. Reverted because it compromises the IWAD file lookup and fixing it properly is not so trivial. The skipping of adding the file name extension was not only broken, but even after fixing the code does not work if the IWADs are located outside the working directory. --- src/d_iwad.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 6fa8604a0c..1fc63e03d3 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -292,7 +292,6 @@ void FIWadManager::ParseIWadInfos(const char *fn) int FIWadManager::ScanIWAD (const char *iwad) { FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true); - if (iwadfile == NULL) iwadfile = FResourceFile::OpenDirectory(iwad, true); //mxd. A directory can also work as an IWAD if (iwadfile != NULL) { @@ -345,7 +344,7 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads) iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars()); FixPathSeperator (iwad); - if (DirEntryExists(iwad)) + if (FileExists (iwad)) { wads[i].Type = ScanIWAD (iwad); if (wads[i].Type != -1) @@ -414,7 +413,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } else { - if(FileExists(custwad)) DefaultExtension (custwad, ".wad"); //mxd. Don't treat folders as .wads + DefaultExtension (custwad, ".wad"); iwadparm = custwad; mIWadNames[0] = custwad; CheckIWAD ("", &wads[0]); From 327d4d85a748d1d149741a5ef4df7838dfdf88f1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 26 Oct 2016 15:02:20 +0200 Subject: [PATCH 026/101] - fixed: UseOffsets can only be handled after the patch is has been set up. --- src/textures/multipatchtexture.cpp | 14 ++++++++------ src/textures/texture.cpp | 2 -- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 860c59b3a9..88d8815a6f 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -192,6 +192,7 @@ protected: int UseType = TEX_Null; bool Silent = false; bool HasLine = false; + bool UseOffsets = false; FScriptPosition sc; }; @@ -1139,11 +1140,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) } else if (sc.Compare("useoffsets")) { - if (part.Texture != NULL) - { - part.OriginX -= part.Texture->LeftOffset; - part.OriginY -= part.Texture->TopOffset; - } + init.UseOffsets = true; } } } @@ -1341,7 +1338,7 @@ void FMultiPatchTexture::ResolvePatches() else { // If it could be resolved, just print a developer warning. - DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s", Inits[i].TexName.GetChars()); + DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s\n", Inits[i].TexName.GetChars()); } } @@ -1358,6 +1355,11 @@ void FMultiPatchTexture::ResolvePatches() Parts[i].Texture = TexMan[texno]; bComplex |= Parts[i].Texture->bComplex; Parts[i].Texture->bKeepAround = true; + if (Inits[i].UseOffsets) + { + Parts[i].OriginX -= Parts[i].Texture->LeftOffset; + Parts[i].OriginY -= Parts[i].Texture->TopOffset; + } } } for (int i = 0; i < NumParts; i++) diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index bc0eaffa35..760437db99 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -615,8 +615,6 @@ namespace PalEntry FTexture::GetSkyCapColor(bool bottom) { PalEntry col; - int w; - int h; if (!bSWSkyColorDone) { From 4c420938c9518e34c38a79e1c533a91d6b581651 Mon Sep 17 00:00:00 2001 From: "Jason A. Yundt" Date: Wed, 12 Oct 2016 15:17:20 -0400 Subject: [PATCH 027/101] - Added install rules so that 'make install' works. --- CMakeLists.txt | 20 ++++++++++++++++++++ src/CMakeLists.txt | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 541347f149..607eb00549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,15 @@ function( add_pk3 PK3_NAME PK3_DIR ) SOURCES ${PK3_SRCS}) # Phase 3: Assign source files to a nice folder structure in the IDE assort_pk3_source_folder("Source Files" ${PK3_DIR}) + # Phase 4: Add the resulting PK3 to the install target. + if( WIN32 ) + set( INSTALL_PK3_PATH . CACHE STRING "Directory where zdoom.pk3 will be placed during install." ) + else() + set( INSTALL_PK3_PATH share/games/doom CACHE STRING "Directory where zdoom.pk3 will be placed during install." ) + endif() + install(FILES "${PROJECT_BINARY_DIR}/${PK3_NAME}" + DESTINATION ${INSTALL_PK3_PATH} + COMPONENT "Game resources") endfunction() # Macro for building libraries without debugging information @@ -252,6 +261,7 @@ if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB ) message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" ) else() message( STATUS "Using internal zlib" ) + set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom add_subdirectory( zlib ) set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib ) set( ZLIB_LIBRARIES z ) @@ -295,6 +305,16 @@ if( NOT CMAKE_CROSSCOMPILING ) endif() endif() +# Install the entire docs directory in the distributed zip package +if( WIN32 ) + set( INSTALL_DOCS_PATH docs CACHE STRING "Directory where the documentation will be placed during install." ) +else() + set( INSTALL_DOCS_PATH share/doc/${ZDOOM_EXE_NAME} CACHE STRING "Directory where the zdoom documentation will be placed during install." ) +endif() +install(DIRECTORY docs/ + DESTINATION ${INSTALL_DOCS_PATH} + COMPONENT "Documentation") + add_subdirectory( lzma ) add_subdirectory( tools ) add_subdirectory( dumb ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ebfac30504..09e2201434 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1419,6 +1419,15 @@ if( APPLE ) endif() endif() +if( WIN32 ) + set( INSTALL_PATH . CACHE STRING "Directory where the zdoom executable will be placed during install." ) +else() + set( INSTALL_PATH bin CACHE STRING "Directory where the zdoom executable will be placed during install." ) +endif() +install(TARGETS zdoom + DESTINATION ${INSTALL_PATH} + COMPONENT "Game executable") + source_group("Assembly Files\\ia32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_ia32/.+") source_group("Assembly Files\\x86_64" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_x86_64/.+") source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+") From 837ed7bd8064b7872bd7884b26025ce3dee89709 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 29 Oct 2016 05:35:41 +0200 Subject: [PATCH 028/101] Fix dancing sprites due to texture coordinate calculations not taking pixel centers into account Merge R_DrawMaskedColumn and R_DrawMaskedColumnHoriz into one function to remove code duplication --- src/r_draw.h | 2 +- src/r_drawt.cpp | 113 +++++++---------------------------------------- src/r_segs.cpp | 24 +++++----- src/r_things.cpp | 93 ++++++++++++-------------------------- src/r_things.h | 4 +- src/v_draw.cpp | 6 +-- 6 files changed, 61 insertions(+), 181 deletions(-) diff --git a/src/r_draw.h b/src/r_draw.h index c45700a212..fa84e5ae91 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -116,7 +116,6 @@ extern void (*R_DrawSpanMaskedAddClamp)(void); // [RH] Span blit into an interleaved intermediate buffer extern void (*R_DrawColumnHoriz)(void); -void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans); // [RH] Initialize the above pointers void R_InitColumnDrawers (); @@ -183,6 +182,7 @@ extern void (*rt_map4cols)(int sx, int yl, int yh); #define rt_addclamp4cols rt_addclamp4cols_c #endif +void rt_flip_posts(); void rt_draw4cols (int sx); // [RH] Preps the temporary horizontal buffer. diff --git a/src/r_drawt.cpp b/src/r_drawt.cpp index e8faff0ceb..cb228cce05 100644 --- a/src/r_drawt.cpp +++ b/src/r_drawt.cpp @@ -838,6 +838,21 @@ void rt_tlaterevsubclamp4cols (int sx, int yl, int yh) rt_revsubclamp4cols(sx, yl, yh); } +// Reorder the posts so that they get drawn top-to-bottom instead of bottom-to-top. +void rt_flip_posts() +{ + unsigned int *front = horizspan[dc_x & 3]; + unsigned int *back = dc_ctspan[dc_x & 3] - 2; + + while (front < back) + { + swapvalues(front[0], back[0]); + swapvalues(front[1], back[1]); + front += 2; + back -= 2; + } +} + // Copies all spans in all four columns to the screen starting at sx. // sx should be dword-aligned. void rt_draw4cols (int sx) @@ -1103,101 +1118,3 @@ void R_FillColumnHorizP (void) dest += 8; } while (--count); } - -// Same as R_DrawMaskedColumn() except that it always uses R_DrawColumnHoriz(). - -void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *span) -{ - const fixed_t texturemid = FLOAT2FIXED(dc_texturemid); - while (span->Length != 0) - { - const int length = span->Length; - const int top = span->TopOffset; - - // calculate unclipped screen coordinates for post - dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top); - dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length) - 1); - - if (sprflipvert) - { - swapvalues (dc_yl, dc_yh); - } - - if (dc_yh >= mfloorclip[dc_x]) - { - dc_yh = mfloorclip[dc_x] - 1; - } - if (dc_yl < mceilingclip[dc_x]) - { - dc_yl = mceilingclip[dc_x]; - } - - if (dc_yl <= dc_yh) - { - if (sprflipvert) - { - dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS) - - fixed_t(CenterY * dc_iscale) - texturemid; - const fixed_t maxfrac = length << FRACBITS; - while (dc_texturefrac >= maxfrac) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - while (endfrac < 0) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - else - { - dc_texturefrac = texturemid - (top << FRACBITS) - + (dc_yl*dc_iscale) - fixed_t((CenterY-1) * dc_iscale); - while (dc_texturefrac < 0) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - const fixed_t maxfrac = length << FRACBITS; - if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale) - { - dc_yh++; - } - else while (endfrac >= maxfrac) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - dc_source = column + top; - dc_dest = ylookup[dc_yl] + dc_x + dc_destorg; - dc_count = dc_yh - dc_yl + 1; - hcolfunc_pre (); - } -nextpost: - span++; - } - - if (sprflipvert) - { - unsigned int *front = horizspan[dc_x&3]; - unsigned int *back = dc_ctspan[dc_x&3] - 2; - - // Reorder the posts so that they get drawn top-to-bottom - // instead of bottom-to-top. - while (front < back) - { - swapvalues (front[0], back[0]); - swapvalues (front[1], back[1]); - front += 2; - back -= 2; - } - } -} diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 48d8f1651a..464fb36449 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -173,7 +173,7 @@ CVAR(Bool, r_drawmirrors, true, 0) float *MaskedSWall; float MaskedScaleY; -static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FTexture::Span *spans), FTexture *tex) +static void BlastMaskedColumn (FTexture *tex, bool useRt) { // calculate lighting if (fixedcolormap == NULL && fixedlightlev < 0) @@ -198,7 +198,7 @@ static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FText // draw the texture const FTexture::Span *spans; const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x] >> FRACBITS, &spans); - blastfunc (pixels, spans); + R_DrawMaskedColumn(pixels, spans, useRt); rw_light += rw_lightstep; spryscale += rw_scalestep; } @@ -441,7 +441,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) { for (dc_x = x1; dc_x < x2; ++dc_x) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); } } else @@ -456,24 +456,24 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) while ((dc_x < stop) && (dc_x & 3)) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); dc_x++; } while (dc_x < stop) { rt_initcols(); - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); rt_draw4cols (dc_x - 3); dc_x++; } while (dc_x < x2) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); dc_x++; } } @@ -3245,7 +3245,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT); } - R_WallSpriteColumn (R_DrawMaskedColumn); + R_WallSpriteColumn (false); dc_x++; } @@ -3258,7 +3258,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, rt_initcols(); for (int zz = 4; zz; --zz) { - R_WallSpriteColumn (R_DrawMaskedColumnHoriz); + R_WallSpriteColumn (true); dc_x++; } rt_draw4cols (dc_x - 4); @@ -3270,7 +3270,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT); } - R_WallSpriteColumn (R_DrawMaskedColumn); + R_WallSpriteColumn (false); dc_x++; } } diff --git a/src/r_things.cpp b/src/r_things.cpp index a886244431..5230047724 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -250,19 +250,17 @@ double sprtopscreen; bool sprflipvert; -void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span) +void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span, bool useRt) { - const fixed_t centeryfrac = FLOAT2FIXED(CenterY); - const fixed_t texturemid = FLOAT2FIXED(dc_texturemid); while (span->Length != 0) { const int length = span->Length; const int top = span->TopOffset; // calculate unclipped screen coordinates for post - dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top); - dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length)) - 1; - + dc_yl = (int)(sprtopscreen + spryscale * top); + dc_yh = (int)(sprtopscreen + spryscale * (top + length)) - 1; + if (sprflipvert) { swapvalues (dc_yl, dc_yh); @@ -279,56 +277,20 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span) if (dc_yl <= dc_yh) { - if (sprflipvert) - { - dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS) - - FixedMul (centeryfrac, dc_iscale) - texturemid; - const fixed_t maxfrac = length << FRACBITS; - while (dc_texturefrac >= maxfrac) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - while (endfrac < 0) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - else - { - dc_texturefrac = texturemid - (top << FRACBITS) - + (dc_yl*dc_iscale) - FixedMul (centeryfrac-FRACUNIT, dc_iscale); - while (dc_texturefrac < 0) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - const fixed_t maxfrac = length << FRACBITS; - if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale) - { - dc_yh++; - } - else while (endfrac >= maxfrac) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - dc_source = column + top; - dc_dest = ylookup[dc_yl] + dc_x + dc_destorg; + dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5 - sprtopscreen) / spryscale); + dc_source = column; + dc_dest = (ylookup[dc_yl] + dc_x) + dc_destorg; dc_count = dc_yh - dc_yl + 1; - colfunc (); + if (useRt) + hcolfunc_pre(); + else + colfunc (); } -nextpost: span++; } + + if (sprflipvert && useRt) + rt_flip_posts(); } // [ZZ] @@ -470,7 +432,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumn (pixels, spans); + R_DrawMaskedColumn (pixels, spans, false); dc_x++; frac += xiscale; } @@ -482,7 +444,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumnHoriz (pixels, spans); + R_DrawMaskedColumn (pixels, spans, true); dc_x++; frac += xiscale; } @@ -493,7 +455,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumn (pixels, spans); + R_DrawMaskedColumn (pixels, spans, false); dc_x++; frac += xiscale; } @@ -603,7 +565,7 @@ void R_DrawWallSprite(vissprite_t *spr) dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumn); + R_WallSpriteColumn(false); dc_x++; } @@ -617,7 +579,7 @@ void R_DrawWallSprite(vissprite_t *spr) for (int zz = 4; zz; --zz) { if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumnHoriz); + R_WallSpriteColumn(true); dc_x++; } rt_draw4cols(dc_x - 4); @@ -630,14 +592,14 @@ void R_DrawWallSprite(vissprite_t *spr) dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumn); + R_WallSpriteColumn(false); dc_x++; } } R_FinishSetPatchStyle(); } -void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans)) +void R_WallSpriteColumn (bool useRt) { float iscale = swall[dc_x] * MaskedScaleY; dc_iscale = FLOAT2FIXED(iscale); @@ -651,7 +613,7 @@ void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Sp const FTexture::Span *spans; column = WallSpriteTile->GetColumn (lwall[dc_x] >> FRACBITS, &spans); dc_texturefrac = 0; - drawfunc (column, spans); + R_DrawMaskedColumn(column, spans, useRt); rw_light += rw_lightstep; } @@ -984,21 +946,23 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor const double thingxscalemul = spriteScale.X / tex->Scale.X; tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul; - x1 = centerx + xs_RoundToInt(tx * xscale); + double dtx1 = tx * xscale; + x1 = centerx + xs_RoundToInt(dtx1); // off the right side? if (x1 >= WindowRight) return; tx += tex->GetWidth() * thingxscalemul; - x2 = centerx + xs_RoundToInt(tx * xscale); + double dtx2 = tx * xscale; + x2 = centerx + xs_RoundToInt(dtx2); // off the left side or too small? if ((x2 < WindowLeft || x2 <= x1)) return; xscale = spriteScale.X * xscale / tex->Scale.X; - iscale = (tex->GetWidth() << FRACBITS) / (x2 - x1); + iscale = (fixed_t)(tex->GetWidth() / (dtx2 - dtx1) * FRACUNIT); double yscale = spriteScale.Y / tex->Scale.Y; @@ -1026,8 +990,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->xiscale = iscale; } - if (vis->x1 > x1) - vis->startfrac += vis->xiscale * (vis->x1 - x1); + vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx - dtx1 + 0.5 * thingxscalemul)); } else { diff --git a/src/r_things.h b/src/r_things.h index 29e69d3a56..53b887b181 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -124,8 +124,8 @@ extern double pspriteyscale; extern FTexture *WallSpriteTile; -void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans); -void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans)); +void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans, bool useRt); +void R_WallSpriteColumn (bool useRt); void R_CacheSprite (spritedef_t *sprite); void R_SortVisSprites (int (*compare)(const void *, const void *), size_t first); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 4677c4b087..20e5311cd2 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -299,7 +299,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) while ((dc_x < stop4) && (dc_x & 3)) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumn(pixels, spans); + R_DrawMaskedColumn(pixels, spans, false); dc_x++; frac += xiscale_i; } @@ -310,7 +310,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) for (int zz = 4; zz; --zz) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumnHoriz(pixels, spans); + R_DrawMaskedColumn(pixels, spans, true); dc_x++; frac += xiscale_i; } @@ -320,7 +320,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) while (dc_x < x2_i) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumn(pixels, spans); + R_DrawMaskedColumn(pixels, spans, false); dc_x++; frac += xiscale_i; } From 87ea75169e1b521d991b203484a44d56f5131eeb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 29 Oct 2016 08:11:12 +0200 Subject: [PATCH 029/101] Fix texturefrac out of bounds bug --- src/r_things.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 5230047724..a15921cbab 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -258,9 +258,9 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span, bool us const int top = span->TopOffset; // calculate unclipped screen coordinates for post - dc_yl = (int)(sprtopscreen + spryscale * top); - dc_yh = (int)(sprtopscreen + spryscale * (top + length)) - 1; - + dc_yl = (int)(sprtopscreen + spryscale * top + 0.5); + dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1; + if (sprflipvert) { swapvalues (dc_yl, dc_yh); From b1880964faad779a8f31656e63ebf10668517841 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Fri, 28 Oct 2016 13:42:37 +0200 Subject: [PATCH 030/101] Added two new sub-blocks for Choice blocks Added two new sub-blocks for Choice blocks: Require and Exclude. The syntax for both is the same as Cost blocks. Require defines what item must be present in your inventory in order to show this choice/reply. Exclude defines what item must not be present in your inventory in order to show this choice/reply. If any Require/Exclude blocks are defined then this choice/reply will be hidden until all blocks of both types are satisfied. --- src/namedef.h | 2 ++ src/p_conversation.cpp | 65 ++++++++++++++++++++++++++++++++++++++---- src/p_conversation.h | 2 ++ src/p_usdf.cpp | 15 +++++++--- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index eab87c503b..8def090fa4 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -585,6 +585,8 @@ xx(Ifitem) xx(Choice) xx(Link) xx(Goodbye) +xx(Require) +xx(Exclude) // Special menus xx(Mainmenu) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index f216d9d78a..0bc2b98a87 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -516,6 +516,8 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); reply->ItemCheck[k].Amount = rsp->Count[k]; } + reply->ItemCheckRequire.Clear(); + reply->ItemCheckExclude.Clear(); // If the first item check has a positive amount required, then // add that to the reply string. Otherwise, use the reply as-is. @@ -656,6 +658,38 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) else if (self > 1.f) self = 1.f; } +//============================================================================ +// +// ShouldSkipReply +// +// Determines whether this reply should be skipped or not. +// +//============================================================================ + +static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) +{ + if (reply->Reply == nullptr) + return true; + + int i; + for (i = 0; i < (int)reply->ItemCheckRequire.Size(); ++i) + { + if (!CheckStrifeItem(player, reply->ItemCheckRequire[i].Item, reply->ItemCheckRequire[i].Amount)) + { + return true; + } + } + + for (i = 0; i < (int)reply->ItemCheckExclude.Size(); ++i) + { + if (CheckStrifeItem(player, reply->ItemCheckExclude[i].Item, reply->ItemCheckExclude[i].Amount)) + { + return true; + } + } + return false; +} + //============================================================================ // // The conversation menu @@ -673,6 +707,7 @@ class DConversationMenu : public DMenu bool mShowGold; FStrifeDialogueNode *mCurNode; int mYpos; + player_t *mPlayer; public: static int mSelection; @@ -683,9 +718,10 @@ public: // //============================================================================= - DConversationMenu(FStrifeDialogueNode *CurNode) + DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player) { mCurNode = CurNode; + mPlayer = player; mDialogueLines = NULL; mShowGold = false; @@ -720,7 +756,7 @@ public: int i,j; for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next) { - if (reply->Reply == NULL) + if (ShouldSkipReply(reply, mPlayer)) { continue; } @@ -778,6 +814,13 @@ public: } ConversationMenuY = mYpos; //ConversationMenu.indent = 50; + + // Because replies can be selectively hidden mResponses.Size() won't be consistent. + // So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork] + if (mSelection >= (int)mResponses.Size()) + { + mSelection = mResponses.Size() - 1; + } } //============================================================================= @@ -839,12 +882,24 @@ public: } else { - // Send dialogue and reply numbers across the wire. assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); + + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + FStrifeDialogueReply *reply = mCurNode->Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) + { + if (ShouldSkipReply(reply, mPlayer)) + replynum++; + else + i++; + } + // Send dialogue and reply numbers across the wire. Net_WriteByte(DEM_CONVREPLY); Net_WriteWord(mCurNode->ThisNodeNum); - Net_WriteByte(mSelection); + Net_WriteByte(replynum); } Close(); return true; @@ -1169,7 +1224,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } - DConversationMenu *cmenu = new DConversationMenu(CurNode); + DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player); if (CurNode != PrevNode) diff --git a/src/p_conversation.h b/src/p_conversation.h index 5b068fb04b..bd674aa101 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -45,6 +45,8 @@ struct FStrifeDialogueReply int ActionSpecial; int Args[5]; TArray ItemCheck; + TArray ItemCheckRequire; + TArray ItemCheckExclude; char *Reply; char *QuickYes; int NextNode; // index into StrifeDialogues diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index dccec7c210..245240273a 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -76,11 +76,11 @@ class USDFParser : public UDMFParserBase //=========================================================================== // - // Parse a cost block + // Parse a cost/require/exclude block // //=========================================================================== - bool ParseCost(FStrifeDialogueReply *response) + bool ParseCostRequireExclude(FStrifeDialogueReply *response, FName type) { FStrifeDialogueItemCheck check; check.Item = NULL; @@ -101,7 +101,12 @@ class USDFParser : public UDMFParserBase } } - response->ItemCheck.Push(check); + switch (type) + { + case NAME_Cost: response->ItemCheck.Push(check); break; + case NAME_Require: response->ItemCheckRequire.Push(check); break; + case NAME_Exclude: response->ItemCheckExclude.Push(check); break; + } return true; } @@ -206,7 +211,9 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Cost: - ParseCost(reply); + case NAME_Require: + case NAME_Exclude: + ParseCostRequireExclude(reply, key); break; default: From f1a80770e1f18af2b3d55700d0edbfdd89f7edf5 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Fri, 28 Oct 2016 13:43:46 +0200 Subject: [PATCH 031/101] Updated the USDF specs Updated the USDF specs about 'require' and 'exclude'. --- specs/usdf.txt | 20 ++++++++++++++++++++ specs/usdf_zdoom.txt | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/specs/usdf.txt b/specs/usdf.txt index 093c9e7d74..2c65f25d06 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -122,6 +122,26 @@ conversation // Starts a dialog. amount = ; // Minimum amount of the item needed. } + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. + require + { + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. + } + + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. + exclude + { + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. + } + displaycost = ; // Whether the cost should be // displayed with the option. // If no cost is specified this should diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index c106cdd1af..8a324c0882 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,6 +50,16 @@ conversation item = ; } + require + { + item = ; + } + + exclude + { + item = ; + } + giveitem = ; } } From c341bc0d3c127cc0a03c2130b1c2ab2e01071a07 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 15:52:29 +0200 Subject: [PATCH 032/101] Added restriction of Require/Exclude to ZSDF Added restriction of Require/Exclude to ZSDF (namespace = "ZDoom";). A warning will be printed if a Require/Exclude block is detected in USDF (namespace = "Strife";). --- src/p_usdf.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 245240273a..e8ce5ca500 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -210,9 +210,17 @@ class USDFParser : public UDMFParserBase { switch(key) { - case NAME_Cost: case NAME_Require: case NAME_Exclude: + // Print a warning if the namespace is not ZDoom otherwise fall-through. [FishyClockwork] + if (namespace_bits != Zd) + { + sc.ScriptMessage("Detected \"%s\" block, ignoring. Require/Exclude are exclusive to namespace ZDoom.", key == NAME_Require ? "Require" : "Exclude"); + while (!sc.CheckToken('}')) sc.MustGetAnyToken(); // Skip this block + break; + } + + case NAME_Cost: ParseCostRequireExclude(reply, key); break; From f450a60f6630ff823c46b8ed151ec85f4ed5f7af Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 15:54:45 +0200 Subject: [PATCH 033/101] Undone changes to usdf.txt, updated usdf_zdoom.txt Undone changes to usdf.txt, updated usdf_zdoom.txt --- specs/usdf.txt | 20 -------------------- specs/usdf_zdoom.txt | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 2c65f25d06..093c9e7d74 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -122,26 +122,6 @@ conversation // Starts a dialog. amount = ; // Minimum amount of the item needed. } - // The amount of an item needed for this option to become available. - // You can have as many as needed. All require blocks must be satisfied - // to show this option. - require - { - item = ; // Item that is required to show this option. - amount = ; // Minimum amount of the item needed. - } - - // The undesired amount of an item. This option will become available - // if you have less than the specified amount. You can have as many - // as needed. All exclude blocks must be satisfied to show this option. - // Note: if both require and exclude are defined then all require - // and all exclude blocks must be satisfied to show this option. - exclude - { - item = ; // Item that is unwanted to show this option. - amount = ; // Unwanted minimum amount of the item. - } - displaycost = ; // Whether the cost should be // displayed with the option. // If no cost is specified this should diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 8a324c0882..588ae6cda1 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,14 +50,24 @@ conversation item = ; } + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. require { - item = ; + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. } + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. exclude { - item = ; + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. } giveitem = ; From 42be7bee935b7509a5979a77f91b6b8983a9284e Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:05:59 +0200 Subject: [PATCH 034/101] For USDF treat Require/Exclude as unknown For USDF treat Require/Exclude as an unknown keyword. --- src/p_usdf.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index e8ce5ca500..a64dc932fe 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -210,19 +210,16 @@ class USDFParser : public UDMFParserBase { switch(key) { + case NAME_Cost: case NAME_Require: case NAME_Exclude: - // Print a warning if the namespace is not ZDoom otherwise fall-through. [FishyClockwork] - if (namespace_bits != Zd) + // Require and Exclude are exclusive to namespace ZDoom. [FishyClockwork] + if (key == NAME_Cost || namespace_bits == Zd) { - sc.ScriptMessage("Detected \"%s\" block, ignoring. Require/Exclude are exclusive to namespace ZDoom.", key == NAME_Require ? "Require" : "Exclude"); - while (!sc.CheckToken('}')) sc.MustGetAnyToken(); // Skip this block + ParseCostRequireExclude(reply, key); break; } - - case NAME_Cost: - ParseCostRequireExclude(reply, key); - break; + // Intentional fall-through default: sc.UnGet(); From 4a56d426c3aedc4dc0593923f3880adcbf98f1f5 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:33:34 +0200 Subject: [PATCH 035/101] Actually put the new info in the proper section Actually put the new info in the proper section in usdf_zdoom.txt --- specs/usdf_zdoom.txt | 46 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 588ae6cda1..8fe1bd7589 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -50,26 +50,6 @@ conversation item = ; } - // The amount of an item needed for this option to become available. - // You can have as many as needed. All require blocks must be satisfied - // to show this option. - require - { - item = ; // Item that is required to show this option. - amount = ; // Minimum amount of the item needed. - } - - // The undesired amount of an item. This option will become available - // if you have less than the specified amount. You can have as many - // as needed. All exclude blocks must be satisfied to show this option. - // Note: if both require and exclude are defined then all require - // and all exclude blocks must be satisfied to show this option. - exclude - { - item = ; // Item that is unwanted to show this option. - amount = ; // Unwanted minimum amount of the item. - } - giveitem = ; } } @@ -106,6 +86,32 @@ conversation // Starts a dialog. // the standard conversation ID ('actor' property) is used instead // for this purpose but since 'ZDoom' namespace requires the actor // to be a class name it needs a separate field for this. + + page + { + choice + { + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. + require + { + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. + } + + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. + exclude + { + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. + } + } + } } =============================================================================== From 8f2e9be70c30ddd3a5c4e70bd843b27afad15f16 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sat, 29 Oct 2016 17:43:20 +0200 Subject: [PATCH 036/101] Changed a description in usdf_zdoom.txt Changed a description in usdf_zdoom.txt to be more truthful. It's not just one new field anymore. (I really should learn to read these things before changing them.) --- specs/usdf_zdoom.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 8fe1bd7589..2b2e6f6da5 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -76,8 +76,8 @@ namespace = "ZDoom"; III.A : Conversations --------------------- -This block only lists the newly added fields. Currently ZDoom only adds one -field to the specification: +This block only lists the newly added fields. Currently ZDoom only adds a few +fields to the specification: conversation // Starts a dialog. { From 1502eae2ac47c85b0e2c95b8aad60e6de435c449 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sat, 29 Oct 2016 21:08:11 -0500 Subject: [PATCH 037/101] Add XPM (X PixMap) version of ZDoom icon --- src/posix/zdoom.xpm | 83 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/posix/zdoom.xpm diff --git a/src/posix/zdoom.xpm b/src/posix/zdoom.xpm new file mode 100644 index 0000000000..eae49eb77f --- /dev/null +++ b/src/posix/zdoom.xpm @@ -0,0 +1,83 @@ +/* XPM */ +static char * zdoom_xpm[] = { +"48 48 32 1", +" c None", +". c #ADA990", +"+ c #999966", +"@ c #666666", +"# c #393939", +"$ c #555555", +"% c #996666", +"& c #777777", +"* c #5F5F5F", +"= c #333333", +"- c #4D4D4D", +"; c #868686", +"> c #969696", +", c #1C1C1C", +"' c #339933", +") c #336633", +"! c #66CC66", +"~ c #66FF66", +"{ c #66CC33", +"] c #222222", +"^ c #333300", +"/ c #292929", +"( c #040404", +"_ c #0C0C0C", +": c #663333", +"< c #996633", +"[ c #CC9966", +"} c #CC6633", +"| c #CC9999", +"1 c #FFCC99", +"2 c #FF9966", +"3 c #FFCCCC", +" ... ", +" ++@##$+ ", +" +...+%&+ ", +" %*=-*&;$=&* ", +" %**=$@;>@=&*% ", +" &**@$*@@$-.+& ", +" %$%@*..$@.. ", +" ,#@+++@@#& ", +" $,#$$@@$#=$'' ", +" )!!!~!{=],,,,]^)'!{') =/, ", +" )){'~!!'')=],=))'{)'')) /=],( ", +" )'!!'!)~'{'),)''''''')) @@/==](( ", +" ^)''')'{{''')'''''),))) $$@$/,( ", +" ,^))),))''''))'')^,__/$$$-#-(( ", +" :<[}<,_)))))))),___,]#@@-/]] ", +" :<|12<:_,,,,,_,#$$-#/,^^=^}}< ", +" :<[1}::,^,,__,#$-==/,,::^:<<< ", +" ::&+@#^,,__/)#-=/,,,,-::^<::= ", +" :*+12[:==_,$-=/,,,,/,#::::=^ ", +" #*}331}-$]-==/,,,,// ##:=^ ", +" /]<13[---],,,,,,,]_] ", +" ,:--/,___]]]]:^___/ ", +" _______,^^,^,__/# ", +" ______:::::/$,,/# ", +" ____^:::=,^^^^,^^ ", +" __,,:=^,,)))^,,= ", +" _,,),,,,,^)^^^,, ", +" ,^,,),__,^))),,^ ", +" ,,,^^,,,,,)))),, ", +" ,,,,,,,)^))))^ ", +" ,,^,,,^^)))))^ ", +" ,^^,,,,)))))), ", +" ,^,,,,))^))), ", +" ],,,,,$&&&*$# ", +" ],,,]#****$# ", +" ]]]]]^####, ", +" ]]]]*,,,,#* ", +" ,_,#@&&@*/ ", +" __$####=# ", +" ,_/$$$$$# ", +" ,,,$*$$$ ", +" ],,,$**$# ", +" ],,,@&&@# ", +" ],,,$**#= ", +" ,,=+++%$ ", +" *%%%*$ ", +" /$*$#/ ", +" ],,]] "}; From 7c1f7aa81cb152e25f672ccb1d4bb109b65729b2 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sun, 30 Oct 2016 20:27:07 +0100 Subject: [PATCH 038/101] Restricted custom goodbyes to ZSDF --- src/p_usdf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index a64dc932fe..d40c542a14 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -345,7 +345,11 @@ class USDFParser : public UDMFParserBase break; case NAME_Goodbye: - Goodbye = CheckString(key); + // Custom goodbyes are exclusive to namespace ZDoom. [FishyClockwork] + if (namespace_bits == Zd) + { + Goodbye = CheckString(key); + } break; } } From 4fc5d527c6951584dad900cbf14194193c9e53f4 Mon Sep 17 00:00:00 2001 From: FishyClockwork Date: Sun, 30 Oct 2016 20:30:32 +0100 Subject: [PATCH 039/101] Moved 'goodbye' from usdf.txt to usdf_zdoom.txt I have undone all my changes to usdf.txt. It should look like how it did before commit 0df6ba6 --- specs/usdf.txt | 18 ++++++++---------- specs/usdf_zdoom.txt | 3 +++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 093c9e7d74..4d1d01c1b3 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,16 +87,14 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - goodbye = ; // Custom goodbye message. If omitted then the - // generic goodbyes will be displayed instead. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are - // satisified. + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are + // satisified. // jumps to the specified page if the player has the specified amount // or more of item in their inventory. This can be repeated as many diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 2b2e6f6da5..f800b5ae79 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -89,6 +89,9 @@ conversation // Starts a dialog. page { + goodbye = ; // Custom goodbye message. If omitted then the + // generic goodbyes will be displayed instead. + choice { // The amount of an item needed for this option to become available. From ede350ba3672c07907ebee319c015f7a365dbc7d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 30 Oct 2016 23:44:55 +0100 Subject: [PATCH 040/101] - there seem to be some problems with the line endings... --- specs/usdf.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index 4d1d01c1b3..1367ccfbf9 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,13 +87,13 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are // satisified. // jumps to the specified page if the player has the specified amount From 43b2584f79ba62fbff6e1cb2b69c862dcbd09dd4 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 30 Oct 2016 23:27:29 -0400 Subject: [PATCH 041/101] - Fixed: Reference to freed stack object in R_FindPlane. This caused a massive slowdown (90% drop in total performance) in R_FindPlane when built with optimizations on in GCC6. Although I don't really understand why since the comparison should have been O(1) regardless of memory contents and even if the check failed every plane it would still be pretty fast, this is what they mean when they say that anything can happen when undefined behavior is triggered. --- src/r_plane.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 07efb84b4d..52dfd43323 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -595,9 +595,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl fixed_t alpha = FLOAT2FIXED(Alpha); //angle_t angle = (xform.Angle + xform.baseAngle).BAMs(); + FTransform nulltransform; + if (picnum == skyflatnum) // killough 10/98 { // most skies map together - FTransform nulltransform; lightlevel = 0; xform = &nulltransform; nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; From 6e6249f896d4beda1b172eb0234fe1e98561cf9d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 31 Oct 2016 18:51:58 +0100 Subject: [PATCH 042/101] - reverted WEAPONTOP to its original value of 32 and made the added fudging bit part of the render side. This is needed so that 'offset(0,32)' does what it is supposed to do. --- src/g_shared/a_weapons.cpp | 1 + src/p_pspr.cpp | 3 +-- src/p_pspr.h | 8 +++----- src/r_things.cpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index edd250debd..b1ede01874 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -640,6 +640,7 @@ void AWeapon::PostMorphWeapon () pspr = Owner->player->GetPSprite(PSP_WEAPON); pspr->y = WEAPONBOTTOM; + pspr->ResetInterpolation(); pspr->SetState(GetUpState()); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index abbd2284ee..2e591e20d9 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -262,8 +262,7 @@ void DPSprite::NewTick() while (pspr) { pspr->processPending = true; - pspr->oldx = pspr->x; - pspr->oldy = pspr->y; + pspr->ResetInterpolation(); pspr = pspr->Next; } diff --git a/src/p_pspr.h b/src/p_pspr.h index ea03e109f8..64a2702a37 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -29,11 +29,8 @@ #define WEAPONBOTTOM 128. -// [RH] +0x6000 helps it meet the screen bottom -// at higher resolutions while still being in -// the right spot at 320x200. -#define WEAPONTOP (32+6./16) - +#define WEAPONTOP 32. +#define WEAPON_FUDGE_Y 0.375 class AInventory; // @@ -77,6 +74,7 @@ public: DPSprite* GetNext() { return Next; } AActor* GetCaller() { return Caller; } void SetCaller(AActor *newcaller) { Caller = newcaller; } + void ResetInterpolation() { oldx = x; oldy = y; } double x, y; double oldx, oldy; diff --git a/src/r_things.cpp b/src/r_things.cpp index a15921cbab..cad434fa5c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1302,7 +1302,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac; - sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac; + sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y; if (pspr->Flags & PSPF_ADDBOB) { @@ -1610,7 +1610,7 @@ void R_DrawPlayerSprites () else { wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF; - wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF; + wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF + WEAPON_FUDGE_Y; } } else From 8d7e400f8eaa964f359849df34306ade247cf850 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Mon, 31 Oct 2016 22:34:46 -0500 Subject: [PATCH 043/101] Fixed: DCanvas::FillSimplePoly must set dc_destorg - dc_destorg is normally set to the upper-left corner of the view window. If there is a border, then this won't coincide with the upper-left corner of the screen, and DCanvas::FillSimplePoly would merrily write off the end of the screen buffer. --- src/v_draw.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 20e5311cd2..bef7328944 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1330,6 +1330,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, return; } + BYTE *destorgsave = dc_destorg; + dc_destorg = screen->GetBuffer(); + if (dc_destorg == NULL) + { + I_FatalError("Attempt to write to buffer of hardware canvas"); + } + scalex /= tex->Scale.X; scaley /= tex->Scale.Y; @@ -1432,6 +1439,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, pt1 = pt2; pt2--; if (pt2 < 0) pt2 = npoints; } while (pt1 != botpt); + dc_destorg = destorgsave; #endif } From 93885974438ab57d940f1e7cdfd4495fdf5fe4bc Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 1 Nov 2016 00:08:16 -0500 Subject: [PATCH 044/101] Add 1 pixel tall and wide texture support to the renderer - These require manual detection and overriding of the scaling factors to 0, because a right shift of (32-0) bits wraps around to 0 and results in no shift at all rather than leaving the register zeroed out. --- src/asm_ia32/tmap2.asm | 3 +++ src/r_plane.cpp | 45 +++++++++++++++++++++++++++++++--------- src/r_segs.cpp | 18 ++++++++++++++++ src/textures/texture.cpp | 5 +++-- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/asm_ia32/tmap2.asm b/src/asm_ia32/tmap2.asm index 9a7aa55346..ab1695d3cd 100644 --- a/src/asm_ia32/tmap2.asm +++ b/src/asm_ia32/tmap2.asm @@ -198,7 +198,10 @@ SetTiltedSpanSize: mov [y8+2],cl mov [y9+2],cl mov [y10+2],cl + cmp eax,0 ; if x bits is 0, mask must be 0 too. + jz .notted not eax +.notted: pop ecx mov [m1+2],eax diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 52dfd43323..c57af953a9 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -221,10 +221,26 @@ void R_MapPlane (int y, int x1) distance = planeheight * yslope[y]; - ds_xstep = xs_ToFixed(32-ds_xbits, distance * xstepscale); - ds_ystep = xs_ToFixed(32-ds_ybits, distance * ystepscale); - ds_xfrac = xs_ToFixed(32-ds_xbits, distance * basexfrac) + pviewx; - ds_yfrac = xs_ToFixed(32-ds_ybits, distance * baseyfrac) + pviewy; + if (ds_xbits != 0) + { + ds_xstep = xs_ToFixed(32 - ds_xbits, distance * xstepscale); + ds_xfrac = xs_ToFixed(32 - ds_xbits, distance * basexfrac) + pviewx; + } + else + { + ds_xstep = 0; + ds_xfrac = 0; + } + if (ds_ybits != 0) + { + ds_ystep = xs_ToFixed(32 - ds_ybits, distance * ystepscale); + ds_yfrac = xs_ToFixed(32 - ds_ybits, distance * baseyfrac) + pviewy; + } + else + { + ds_ystep = 0; + ds_yfrac = 0; + } if (plane_shade) { @@ -357,7 +373,7 @@ void R_CalcTiltedLighting (double lval, double lend, int width) // //========================================================================== -void R_MapTiltedPlane (int y, int x1) +void R_MapTiltedPlane(int y, int x1) { int x2 = spanend[y]; int width = x2 - x1; @@ -366,18 +382,18 @@ void R_MapTiltedPlane (int y, int x1) DWORD u, v; int i; - iz = plane_sz[2] + plane_sz[1]*(centery-y) + plane_sz[0]*(x1-centerx); + iz = plane_sz[2] + plane_sz[1] * (centery - y) + plane_sz[0] * (x1 - centerx); // Lighting is simple. It's just linear interpolation from start to end if (plane_shade) { - uz = (iz + plane_sz[0]*width) * planelightfloat; + uz = (iz + plane_sz[0] * width) * planelightfloat; vz = iz * planelightfloat; - R_CalcTiltedLighting (vz, uz, width); + R_CalcTiltedLighting(vz, uz, width); } - uz = plane_su[2] + plane_su[1]*(centery-y) + plane_su[0]*(x1-centerx); - vz = plane_sv[2] + plane_sv[1]*(centery-y) + plane_sv[0]*(x1-centerx); + uz = plane_su[2] + plane_su[1] * (centery - y) + plane_su[0] * (x1 - centerx); + vz = plane_sv[2] + plane_sv[1] * (centery - y) + plane_sv[0] * (x1 - centerx); fb = ylookup[y] + x1 + dc_destorg; @@ -1888,6 +1904,15 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t } } + // Hack in support for 1 x Z and Z x 1 texture sizes + if (ds_ybits == 0) + { + plane_sv[2] = plane_sv[1] = plane_sv[0] = 0; + } + if (ds_xbits = 0) + { + plane_su[2] = plane_su[1] = plane_su[0] = 0; + } #if defined(X86_ASM) if (ds_source != ds_curtiltedsource) R_SetTiltedSpanSource_ASM (ds_source); diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 464fb36449..01c03e6d7a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1104,6 +1104,12 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *l rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1456,6 +1462,12 @@ void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_ rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32- rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1631,6 +1643,12 @@ void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, f rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setuptmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 760437db99..9c1b5fdb42 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -210,8 +210,9 @@ void FTexture::CalcBitSize () } WidthMask = (1 << WidthBits) - 1; - // The minimum height is 2, because we cannot shift right 32 bits. - for (i = 1; (1 << i) < Height; ++i) + //
The minimum height is 2, because we cannot shift right 32 bits. + // Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it. + for (i = 0; (1 << i) < Height; ++i) { } HeightBits = i; From 5df21fda6814431e2dae8955add6ae9587fabf72 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 1 Nov 2016 00:18:56 -0500 Subject: [PATCH 045/101] Fixed: Masked midtexture yscale incorrectly used the texture's X scale --- src/r_segs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 01c03e6d7a..45e3044d3a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2539,7 +2539,7 @@ void R_StoreWallRange (int start, int stop) lwal = (fixed_t *)(openings + ds_p->maskedtexturecol); swal = (float *)(openings + ds_p->swall); FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true); - double yscale = pic->Scale.X * sidedef->GetTextureYScale(side_t::mid); + double yscale = pic->Scale.Y * sidedef->GetTextureYScale(side_t::mid); fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); if (pic->bWorldPanning) From 46a311b23c7c09ab7e6701d62a5e8c2c331f43c3 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 1 Nov 2016 09:59:59 +0100 Subject: [PATCH 046/101] - Fixed a typo in 1 pixel tall support addition. Found by Clang -Wparentheses warning. --- src/r_plane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index c57af953a9..810aa0003c 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1909,7 +1909,7 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t { plane_sv[2] = plane_sv[1] = plane_sv[0] = 0; } - if (ds_xbits = 0) + if (ds_xbits == 0) { plane_su[2] = plane_su[1] = plane_su[0] = 0; } From 4cf0d76e8cd759bcca5adb27a1b8007ea186937f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:33:18 +0100 Subject: [PATCH 047/101] - fixed: RapidJSON in ASCII mode cannot handle extended 8 bit character sets and will produce broken data if the input contains some. This means we need to perform the conversion to UTF-8 on ZDoom's side and run RapidJSON in UTF-8 mode. Daedalus triggers this with a 0x85 character which in Windows CP 1252 is the ellipsis (...) The converter will assume ISO-8859-1, though, but cannot do anything with these characters because they map to the font being used here. --- src/p_acs.cpp | 4 ++ src/serializer.cpp | 173 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 160 insertions(+), 17 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f36aaaf69a..d82e6590c4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -791,6 +791,10 @@ void ACSStringPool::WriteStrings(FSerializer &file, const char *key) const { if (file.BeginObject(nullptr)) { + if (i == 430) + { + int a = 0; + } file("index", i) ("string", entry->Str) ("lockcount", entry->LockCount) diff --git a/src/serializer.cpp b/src/serializer.cpp index 49226ce801..dec81e86fe 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -67,6 +67,143 @@ char nulspace[1024 * 1024 * 4]; bool save_full = false; // for testing. Should be removed afterward. +int utf8_encode(int32_t codepoint, char *buffer, int *size) +{ + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if (codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +int utf8_decode(const char *src, int *size) +{ + int c = src[0] & 255; + int r; + + *size = 1; + if ((c & 0x80) == 0) + { + return c; + } + + int c1 = src[1] & 255; + + if ((c & 0xE0) == 0xC0) + { + r = ((c & 0x1F) << 6) | c1; + if (r >= 128) + { + *size = 2; + return r; + } + return -1; + } + + int c2 = src[2] & 255; + + if ((c & 0xF0) == 0xE0) + { + r = ((c & 0x0F) << 12) | (c1 << 6) | c2; + if (r >= 2048 && (r < 55296 || r > 57343)) + { + *size = 3; + return r; + } + return -1; + } + + int c3 = src[3] & 255; + + if ((c & 0xF8) == 0xF0) + { + r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + if (r >= 65536 && r <= 1114111) + { + *size = 4; + return r; + } + } + return -1; +} + +static TArray out; +static const char *StringToUnicode(const char *cc, int size = -1) +{ + int ch; + const char *c = cc; + int count = 0; + int count1 = 0; + out.Clear(); + while (ch = (*c++) & 255) + { + count1++; + if (ch >= 128) + { + if (ch < 0x800) count += 2; + else count += 3; + // The source cannot contain 4-byte chars. + } + else count++; + if (count1 == size && size > 0) break; + } + if (count == count1) return cc; // string is pure ASCII. + // we need to convert + out.Resize(count + 1); + out.Last() = 0; + c = cc; + int i = 0; + while (ch = (*c++) & 255) + { + utf8_encode(ch, &out[i], &count1); + i += count1; + } + return &out[0]; +} + +static const char *UnicodeToString(const char *cc) +{ + out.Resize((unsigned)strlen(cc) + 1); + int ndx = 0; + while (*cc != 0) + { + int size; + int c = utf8_decode(cc, &size); + if (c < 0 || c > 255) c = '?'; + out[ndx++] = c; + cc += size; + } + out[ndx] = 0; + return &out[0]; +} + //========================================================================== // // @@ -99,8 +236,8 @@ struct FJSONObject struct FWriter { - typedef rapidjson::Writer > Writer; - typedef rapidjson::PrettyWriter > PrettyWriter; + typedef rapidjson::Writer > Writer; + typedef rapidjson::PrettyWriter > PrettyWriter; Writer *mWriter1; PrettyWriter *mWriter2; @@ -173,14 +310,16 @@ struct FWriter void String(const char *k) { + k = StringToUnicode(k); if (mWriter1) mWriter1->String(k); else if (mWriter2) mWriter2->String(k); } void String(const char *k, int size) { - if (mWriter1) mWriter1->String(k, size); - else if (mWriter2) mWriter2->String(k, size); + k = StringToUnicode(k, size); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); } void Bool(bool k) @@ -602,7 +741,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe } else if (i == 0 && aval.IsString()) { - args[i] = -FName(aval.GetString()); + args[i] = -FName(UnicodeToString(aval.GetString())); } else { @@ -654,7 +793,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num) } else if (val->IsString()) { - num = -FName(val->GetString()); + num = -FName(UnicodeToString(val->GetString())); } else { @@ -709,7 +848,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d { if (val->IsString()) { - uint32_t name = *reinterpret_cast(val->GetString()); + uint32_t name = *reinterpret_cast(UnicodeToString(val->GetString())); for (auto hint = NumStdSprites; hint-- != 0; ) { if (sprites[hint].dwName == name) @@ -747,7 +886,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) { if (val->IsString()) { - charptr = val->GetString(); + charptr = UnicodeToString(val->GetString()); } else { @@ -1403,7 +1542,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe assert(nameval.IsString() && typeval.IsInt()); if (nameval.IsString() && typeval.IsInt()) { - value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt()); + value = TexMan.GetTexture(UnicodeToString(nameval.GetString()), typeval.GetInt()); } else { @@ -1553,7 +1692,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d assert(val->IsString()); if (val->IsString()) { - value = val->GetString(); + value = UnicodeToString(val->GetString()); } else { @@ -1638,7 +1777,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI assert(val->IsString() || val->IsNull()); if (val->IsString()) { - sid = val->GetString(); + sid = UnicodeToString(val->GetString()); } else if (val->IsNull()) { @@ -1687,7 +1826,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor assert(val->IsString() || val->IsNull()); if (val->IsString()) { - clst = PClass::FindActor(val->GetString()); + clst = PClass::FindActor(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1735,7 +1874,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl { if (val->IsString()) { - clst = PClass::FindClass(val->GetString()); + clst = PClass::FindClass(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1810,7 +1949,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState assert(cls.IsString() && ndx.IsUint()); if (cls.IsString() && ndx.IsUint()) { - PClassActor *clas = PClass::FindActor(cls.GetString()); + PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); if (clas && ndx.GetUint() < (unsigned)clas->NumOwnedStates) { state = clas->OwnedStates + ndx.GetUint(); @@ -1932,7 +2071,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p } else if (val->IsString()) { - pstr = AActor::mStringPropertyData.Alloc(val->GetString()); + pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString())); } else { @@ -1974,7 +2113,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString } else if (val->IsString()) { - pstr = val->GetString(); + pstr = UnicodeToString(val->GetString()); } else { @@ -2023,7 +2162,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr } else if (val->IsString()) { - pstr = copystring(val->GetString()); + pstr = copystring(UnicodeToString(val->GetString())); } else { From 3f57269a8b806d0c775381ef766364b9a18e4bb5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:36:33 +0100 Subject: [PATCH 048/101] - fixed: ACSStringPool::AddString did not check for NULL pointers as input. Let's just map them to the empty string, that's a lot better than crashing. --- src/p_acs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index d82e6590c4..9281bfad0e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -375,6 +375,7 @@ void ACSStringPool::Clear() int ACSStringPool::AddString(const char *str) { + if (str == nullptr) str = ""; size_t len = strlen(str); unsigned int h = SuperFastHash(str, len); unsigned int bucketnum = h % NUM_BUCKETS; From 6e0defdc695f9b8e18fe6c730f63e5218245728b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Nov 2016 13:48:56 +0100 Subject: [PATCH 049/101] - fixed numeric output precision for a few sliders. --- wadsrc/static/menudef.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 765fe66744..dac933af81 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -667,8 +667,8 @@ OptionMenu "VideoOptions" Slider "$DSPLYMNU_BRIGHTNESS", "Gamma", 0.75, 3.0, 0.05, 2 Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" - Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 1 - Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 1 + Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 2 + Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 2 Option "$DSPLYMNU_COLUMNMETHOD", "r_columnmethod", "ColumnMethods" StaticText " " @@ -700,7 +700,7 @@ OptionMenu "VideoOptions" ColorPicker "$DSPLYMNU_DIMCOLOR", "dimcolor" Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2 - Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1, 2 + Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1 } @@ -1242,7 +1242,7 @@ OptionMenu GameplayOptions Title "$GMPLYMNU_TITLE" //Indent 222 Option "$GMPLYMNU_TEAMPLAY", "teamplay", "OnOff" - Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05 + Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05,2 StaticText " " Option "$GMPLYMNU_SMARTAUTOAIM", "sv_smartaim", "SmartAim" StaticText " " @@ -1792,7 +1792,7 @@ OptionMenu NetworkOptions StaticText "$NETMNU_LOCALOPTIONS", 1 Option "$NETMNU_MOVEPREDICTION", "cl_noprediction", "OffOn" Option "$NETMNU_LINESPECIALPREDICTION", "cl_predict_specials", "OnOff" - Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05 + Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05, 2 Slider "$NETMNU_LERPTHRESHOLD", "cl_predict_lerpthreshold", 0.1, 16.0, 0.1 StaticText " " StaticText "$NETMNU_HOSTOPTIONS", 1 From f72ebe67689c6babe991b9b805eef419e3a186ce Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 1 Nov 2016 03:30:59 -0400 Subject: [PATCH 050/101] - Extended map, recordmap, and open commands to accept "dm/coop" as an extra parameter - to open maps in multiplayer mode with the requested ruleset. --- src/doomstat.h | 3 +++ src/g_game.cpp | 1 + src/g_level.cpp | 41 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index bbb323c7e3..70869b5a2c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -71,6 +71,9 @@ extern bool netgame; // Bot game? Like netgame, but doesn't involve network communication. extern bool multiplayer; +// [SP] MPMap implementation - invokes fake multiplayer without bots +extern bool multiplayernext; + // Flag: true only if started as net deathmatch. EXTERN_CVAR (Int, deathmatch) diff --git a/src/g_game.cpp b/src/g_game.cpp index b0c8775fc5..2c827e6391 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,6 +164,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; +bool multiplayernext = false; // [SP] MPMap implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; diff --git a/src/g_level.cpp b/src/g_level.cpp index d3a8c4015a..65e19d4237 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -90,6 +90,8 @@ #include "g_hub.h" +#include + void STAT_StartNewGame(const char *lev); void STAT_ChangeLevel(const char *newl); @@ -181,6 +183,16 @@ CCMD (map) } else { + if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew (argv[1]); } } @@ -192,7 +204,7 @@ CCMD (map) } else { - Printf ("Usage: map \n"); + Printf ("Usage: map [coop|dm]\n"); } } @@ -218,6 +230,16 @@ CCMD(recordmap) } else { + if (argv.argc() > 3 && strcmp(argv[3], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 3 && strcmp(argv[3], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew(argv[2]); gameaction = ga_recordgame; newdemoname = argv[1]; @@ -232,7 +254,7 @@ CCMD(recordmap) } else { - Printf("Usage: recordmap \n"); + Printf("Usage: recordmap [coop|dm]\n"); } } @@ -258,13 +280,23 @@ CCMD (open) } else { + if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } gameaction = ga_newgame2; d_skill = -1; } } else { - Printf ("Usage: open \n"); + Printf ("Usage: open [coop|dm]\n"); } } @@ -293,7 +325,8 @@ void G_NewInit () G_ClearSnapshots (); ST_SetNeedRefresh(); netgame = false; - multiplayer = false; + multiplayer = multiplayernext; + multiplayernext = false; if (demoplayback) { C_RestoreCVars (); From 6755373f464a709041ff77277a24bc808256e2a1 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 1 Nov 2016 09:47:01 -0400 Subject: [PATCH 051/101] - fixed: map commands will now take capslock DM/COOP as arguments --- src/doomstat.h | 2 +- src/g_game.cpp | 2 +- src/g_level.cpp | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 70869b5a2c..22ee4fdb49 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -71,7 +71,7 @@ extern bool netgame; // Bot game? Like netgame, but doesn't involve network communication. extern bool multiplayer; -// [SP] MPMap implementation - invokes fake multiplayer without bots +// [SP] Map dm/coop implementation - invokes fake multiplayer without bots extern bool multiplayernext; // Flag: true only if started as net deathmatch. diff --git a/src/g_game.cpp b/src/g_game.cpp index 2c827e6391..ec79d59e60 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,7 +164,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; -bool multiplayernext = false; // [SP] MPMap implementation +bool multiplayernext = false; // [SP] Map coop/dm implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; diff --git a/src/g_level.cpp b/src/g_level.cpp index 65e19d4237..9e8448879f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -183,12 +183,12 @@ CCMD (map) } else { - if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) { deathmatch = true; multiplayernext = true; @@ -230,12 +230,12 @@ CCMD(recordmap) } else { - if (argv.argc() > 3 && strcmp(argv[3], "coop") == 0) + if (argv.argc() > 3 && stricmp(argv[3], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 3 && strcmp(argv[3], "dm") == 0) + else if (argv.argc() > 3 && stricmp(argv[3], "dm") == 0) { deathmatch = true; multiplayernext = true; @@ -280,12 +280,12 @@ CCMD (open) } else { - if (argv.argc() > 2 && strcmp(argv[2], "coop") == 0) + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) { deathmatch = false; multiplayernext = true; } - else if (argv.argc() > 2 && strcmp(argv[2], "dm") == 0) + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) { deathmatch = true; multiplayernext = true; From b420347babeb632497298b9a3e0f0f04e38a6aa9 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Sun, 16 Oct 2016 02:50:21 +0800 Subject: [PATCH 052/101] Added "local" parameters to A_PlaySound and ACS PlaySound --- src/p_acs.cpp | 7 ++++--- src/p_actionfunctions.cpp | 5 +++-- src/s_sound.cpp | 26 ++++++++++++++++++++++++++ src/s_sound.h | 3 +++ wadsrc/static/actors/actor.txt | 2 +- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9281bfad0e..1a60a0c4fb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5350,7 +5350,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_PlaySound: case ACSF_PlayActorSound: - // PlaySound(tid, "SoundName", channel, volume, looping, attenuation) + // PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local) { FSoundID sid; @@ -5371,6 +5371,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) float vol = argCount > 3 ? ACSToFloat(args[3]) : 1.f; INTBOOL looping = argCount > 4 ? args[4] : false; float atten = argCount > 5 ? ACSToFloat(args[5]) : ATTN_NORM; + INTBOOL local = argCount > 6 ? args[6] : false; if (args[0] == 0) { @@ -5387,11 +5388,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { if (!looping) { - S_Sound(spot, chan, sid, vol, atten); + S_PlaySound(spot, chan, sid, vol, atten, local); } else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { - S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, local); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c6bc8215b0..73cade49a4 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1032,16 +1032,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) PARAM_FLOAT_OPT (volume) { volume = 1; } PARAM_BOOL_OPT (looping) { looping = false; } PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } + PARAM_BOOL_OPT (local) { local = false; } if (!looping) { - S_Sound (self, channel, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local); } else { if (!S_IsActorPlayingSomething (self, channel&7, soundid)) { - S_Sound (self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local); } } return 0; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 524b121756..a51a7101be 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1301,6 +1301,32 @@ void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, fl S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); } +//========================================================================== +// +// S_PlaySound - Subfunction used by ACS and DECORATE +// +// Has a local parameter to make the sound audible only to the source +// +//========================================================================== + +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local) +{ + if (a == nullptr) + return; + + if (!local) + { + S_Sound(a, chan, sid, vol, atten); + } + else + { + if (a->CheckLocalView(consoleplayer)) + { + S_Sound(chan, sid, vol, ATTN_NONE); + } + } +} + //========================================================================== // // S_LoadSound diff --git a/src/s_sound.h b/src/s_sound.h index 9b917e25c8..d6d2a5403e 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -241,6 +241,9 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, f void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); void S_Sound(const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation); +// [Nash] Used by ACS and DECORATE +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local); + // sound channels // channel 0 never willingly overrides // other channels (1-7) always override a playing sound on that channel diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index eecc843d39..71e82f613d 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -191,7 +191,7 @@ ACTOR Actor native //: Thinker action native A_ComboAttack(); action native A_BulletAttack(); action native A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class pufftype = "BulletPuff"); - action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM); + action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false); native void A_PlayWeaponSound(sound whattoplay); action native A_FLoopActiveSound(); action native A_LoopActiveSound(); From 3f32ccada6cf3533ab1f4aeb4a66df9cdc37bd2b Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 1 Nov 2016 22:54:27 -0500 Subject: [PATCH 053/101] Zero In2D before calling Flip() - Fixes an assert when resizing the window in windowed mode. Flip() can call V_OutputResized() in windowed mode. --- src/win32/fb_d3d9.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 06bfa05691..8bb680dbda 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1092,6 +1092,7 @@ void D3DFB::Update () DrawRateStuff(); DrawPackedTextures(d3d_showpacks); EndBatch(); // Make sure all batched primitives are drawn. + In2D = 0; Flip(); } In2D = 0; From f8641c0ffb65402598bd7c51906cba3e2b6f03dc Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Wed, 2 Nov 2016 00:07:57 -0500 Subject: [PATCH 054/101] Fixed: MaxVisForFloor was broken by the switch to floats - TODO: See if these visibility limits are even needed anymore. --- 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 4252f4155a..c69c22c7ba 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -355,7 +355,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, MaxVisForWall = (InvZtoScale * (SCREENWIDTH*r_Yaspect) / (viewwidth*SCREENHEIGHT * FocalTangent)); MaxVisForWall = 32767.0 / MaxVisForWall; - MaxVisForFloor = 32767.0 / (viewheight * FocalLengthY / 160); + MaxVisForFloor = 32767.0 / (viewheight >> 2) * FocalLengthY / 160; // Reset r_*Visibility vars R_SetVisibility(R_GetVisibility()); From 6ef5cdebb29093727838858632de4a999c7c6421 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Nov 2016 19:41:51 +0100 Subject: [PATCH 055/101] - slider fixes. --- wadsrc/static/menudef.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 6bbf8d5da5..658e729da3 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -675,7 +675,7 @@ OptionMenu "VideoOptions" Slider "$DSPLYMNU_SCREENSIZE", "screenblocks", 3.0, 12.0, 1.0, 0 Slider "$DSPLYMNU_GAMMA", "Gamma", 0.75, 3.0, 0.05, 2 - Slider "$DSPLYMNU_BRIGHTNESS", "vid_brightness", -0.8,0.8, 0.05 + Slider "$DSPLYMNU_BRIGHTNESS", "vid_brightness", -0.8,0.8, 0.05,2 Slider "$DSPLYMNU_CONTRAST", "vid_contrast", 0.1, 3.0, 0.1 Option "$DSPLYMNU_HWGAMMA", "vid_hwgamma", "HWGammaModes" From b04118032ee1b0ee6e03ee3293543e7155fe73ed Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 1 Nov 2016 22:58:53 +0100 Subject: [PATCH 056/101] Fix wrapping and scaling issue for the U texture coordinate for sprites --- src/r_things.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index cad434fa5c..6ef4e8027a 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -954,15 +954,14 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor return; tx += tex->GetWidth() * thingxscalemul; - double dtx2 = tx * xscale; - x2 = centerx + xs_RoundToInt(dtx2); + x2 = centerx + xs_RoundToInt(tx * xscale); // off the left side or too small? if ((x2 < WindowLeft || x2 <= x1)) return; xscale = spriteScale.X * xscale / tex->Scale.X; - iscale = (fixed_t)(tex->GetWidth() / (dtx2 - dtx1) * FRACUNIT); + iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases double yscale = spriteScale.Y / tex->Scale.Y; @@ -990,7 +989,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->xiscale = iscale; } - vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx - dtx1 + 0.5 * thingxscalemul)); + vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx + 0.5 - dtx1)); } else { From 4b4d7a07685c5cbf752db9c9b8df4b1a8015d37d Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 4 Nov 2016 02:03:23 +0100 Subject: [PATCH 057/101] Add texturefrac bounds clamping to R_DrawMaskedColumn to avoid buffer overruns --- src/r_things.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/r_things.cpp b/src/r_things.cpp index 6ef4e8027a..e7d130fa85 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -281,6 +281,15 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span, bool us dc_source = column; dc_dest = (ylookup[dc_yl] + dc_x) + dc_destorg; dc_count = dc_yh - dc_yl + 1; + + fixed_t maxfrac = ((top + length) << FRACBITS) - 1; + dc_texturefrac = MAX(dc_texturefrac, 0); + dc_texturefrac = MIN(dc_texturefrac, maxfrac); + if (dc_iscale > 0) + dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale); + else if (dc_iscale < 0) + dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale)); + if (useRt) hcolfunc_pre(); else From 7755a3525aeff2936baaad1d1d79ed89045186a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Nov 2016 11:17:22 +0100 Subject: [PATCH 058/101] - do not allow menu slider values very close to zero. They not only can produce a glitched number display but also some weird inconsistencies when operating a slider. --- src/menu/optionmenuitems.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 76718809e1..0fadeca374 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -671,6 +671,7 @@ public: { return FOptionMenuItem::MenuEvent(mkey, fromcontroller); } + if (fabs(value) < FLT_EPSILON) value = 0; SetSliderValue(clamp(value, mMin, mMax)); S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); return true; From 540f20882ee1a9827feec5ff7125cc1f8d9241b8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Nov 2016 11:32:57 +0100 Subject: [PATCH 059/101] - fixed: Degeneration should use the same base health value as all the rest of the engine. - also replaced deh.MaxHealth in the bot code which was the only other remaining case where this was used as health limiter. --- src/b_think.cpp | 2 +- src/p_user.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/b_think.cpp b/src/b_think.cpp index 5a98b5c1ae..d097db8640 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -358,7 +358,7 @@ void DBot::WhatToGet (AActor *item) } else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere) return; - else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= deh.MaxHealth /*MAXHEALTH*/) + else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina) return; if ((dest == NULL || diff --git a/src/p_user.cpp b/src/p_user.cpp index b7bd4c2ec4..4a15e7f180 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2677,10 +2677,11 @@ void P_PlayerThink (player_t *player) // Apply degeneration. if (dmflags2 & DF2_YES_DEGENERATION) { - if ((level.time % TICRATE) == 0 && player->health > deh.MaxHealth) + int maxhealth = player->mo->GetMaxHealth() + player->mo->stamina; + if ((level.time % TICRATE) == 0 && player->health > maxhealth) { - if (player->health - 5 < deh.MaxHealth) - player->health = deh.MaxHealth; + if (player->health - 5 < maxhealth) + player->health = maxhealth; else player->health--; From faea61cf0177832ff668b1c07bb24c9064c33104 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Nov 2016 12:43:23 +0100 Subject: [PATCH 060/101] - fixed: Turbo messages were printed, even when no turbo mode was active. --- src/g_game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index ec79d59e60..810a29da10 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1172,7 +1172,7 @@ void G_Ticker () } // check for turbo cheats - if (cmd->ucmd.forwardmove > TURBOTHRESHOLD && + if (turbo > 100.f && cmd->ucmd.forwardmove > TURBOTHRESHOLD && !(gametic&31) && ((gametic>>5)&(MAXPLAYERS-1)) == i ) { Printf ("%s is turbo!\n", players[i].userinfo.GetName()); From 60ae4a8568d9fc929c803036fa16fa0f9bfb68a2 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 5 Nov 2016 04:02:30 +0100 Subject: [PATCH 061/101] Replace build wallscan with a rewritten version that tile and scale correctly --- src/r_segs.cpp | 791 +++++++++++++++++++------------------------------ 1 file changed, 303 insertions(+), 488 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 45e3044d3a..ae33332de6 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1066,56 +1066,188 @@ void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2) return; } -// prevlineasm1 is like vlineasm1 but skips the loop if only drawing one pixel -inline fixed_t prevline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest) +struct WallscanSampler { - dc_iscale = vince; - dc_colormap = colormap; - dc_count = count; - dc_texturefrac = vplce; - dc_source = bufplce; - dc_dest = dest; - return doprevline1 (); -} + WallscanSampler() { } + WallscanSampler(int y1, float swal, double yrepeat, fixed_t xoffset, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)); -void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, - double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) + uint32_t uv_pos; + uint32_t uv_step; + uint32_t uv_max; + + const BYTE *source; + uint32_t height; +}; + +WallscanSampler::WallscanSampler(int y1, float swal, double yrepeat, fixed_t xoffset, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)) { - int x, fracbits; - int y1ve[4], y2ve[4], u4, d4, z; - char bad; - float light = rw_light - rw_lightstep; - SDWORD xoffset; - BYTE *basecolormapdata; - double iscale; + height = texture->GetHeight(); - // This function also gets used to draw skies. Unlike BUILD, skies are - // drawn by visplane instead of by bunch, so these checks are invalid. - //if ((uwal[x1] > viewheight) && (uwal[x2] > viewheight)) return; - //if ((dwal[x1] < 0) && (dwal[x2] < 0)) return; - - if (rw_pic->UseType == FTexture::TEX_Null) + int uv_fracbits = 32 - texture->HeightBits; + if (uv_fracbits != 32) { - return; + uv_max = height << uv_fracbits; + + // Find start uv in [0-base_height[ range. + // Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range. + double uv_stepd = swal * yrepeat; + double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height; + v = v - floor(v); + v *= height; + v *= (1 << uv_fracbits); + + uv_pos = (uint32_t)v; + uv_step = xs_ToFixed(uv_fracbits, uv_stepd); + if (uv_step == 0) // To prevent divide by zero elsewhere + uv_step = 1; + } + else + { // Hack for one pixel tall textures + uv_pos = 0; + uv_step = 0; + uv_max = 1; } -//extern cycle_t WallScanCycles; -//clock (WallScanCycles); + source = getcol(texture, xoffset >> FRACBITS); +} - rw_pic->GetHeight(); // Make sure texture size is loaded - fracbits = 32 - rw_pic->HeightBits; +// Draw a column with support for non-power-of-two ranges +void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*draw1column)()) +{ + if (sampler.uv_max == 0) // power of two + { + int count = y2 - y1; + + dc_source = sampler.source; + dc_dest = (ylookup[y1] + x) + dc_destorg; + dc_count = count; + dc_iscale = sampler.uv_step; + dc_texturefrac = sampler.uv_pos; + draw1column(); + + uint64_t step64 = sampler.uv_step; + uint64_t pos64 = sampler.uv_pos; + sampler.uv_pos = (uint32_t)(pos64 + step64 * count); + } + else + { + uint32_t uv_pos = sampler.uv_pos; + + uint32_t left = y2 - y1; + while (left > 0) + { + uint32_t available = sampler.uv_max - uv_pos; + uint32_t next_uv_wrap = available / sampler.uv_step; + if (available % sampler.uv_step != 0) + next_uv_wrap++; + uint32_t count = MIN(left, next_uv_wrap); + + dc_source = sampler.source; + dc_dest = (ylookup[y1] + x) + dc_destorg; + dc_count = count; + dc_iscale = sampler.uv_step; + dc_texturefrac = uv_pos; + draw1column(); + + left -= count; + uv_pos += sampler.uv_step * count; + if (uv_pos >= sampler.uv_max) + uv_pos -= sampler.uv_max; + } + + sampler.uv_pos = uv_pos; + } +} + +// Draw four columns with support for non-power-of-two ranges +void wallscan_drawcol4(int x, int y1, int y2, WallscanSampler *sampler, void(*draw4columns)()) +{ + if (sampler[0].uv_max == 0) // power of two, no wrap handling needed + { + int count = y2 - y1; + for (int i = 0; i < 4; i++) + { + bufplce[i] = sampler[i].source; + vplce[i] = sampler[i].uv_pos; + vince[i] = sampler[i].uv_step; + + uint64_t step64 = sampler[i].uv_step; + uint64_t pos64 = sampler[i].uv_pos; + sampler[i].uv_pos = (uint32_t)(pos64 + step64 * count); + } + dc_dest = (ylookup[y1] + x) + dc_destorg; + dc_count = count; + draw4columns(); + } + else + { + dc_dest = (ylookup[y1] + x) + dc_destorg; + for (int i = 0; i < 4; i++) + { + bufplce[i] = sampler[i].source; + } + + uint32_t left = y2 - y1; + while (left > 0) + { + // Find which column wraps first + uint32_t count = left; + for (int i = 0; i < 4; i++) + { + uint32_t available = sampler[i].uv_max - sampler[i].uv_pos; + uint32_t next_uv_wrap = available / sampler[i].uv_step; + if (available % sampler[i].uv_step != 0) + next_uv_wrap++; + count = MIN(next_uv_wrap, count); + } + + // Draw until that column wraps + for (int i = 0; i < 4; i++) + { + vplce[i] = sampler[i].uv_pos; + vince[i] = sampler[i].uv_step; + } + dc_count = count; + draw4columns(); + + // Wrap the uv position + for (int i = 0; i < 4; i++) + { + sampler[i].uv_pos += sampler[i].uv_step * count; + if (sampler[i].uv_pos >= sampler[i].uv_max) + sampler[i].uv_pos -= sampler[i].uv_max; + } + + left -= count; + } + } +} + +typedef DWORD(*Draw1ColumnFuncPtr)(); +typedef void(*Draw4ColumnsFuncPtr)(); + +void wallscan_any( + int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, + const BYTE *(*getcol)(FTexture *tex, int x), + void(setupwallscan(int bits, Draw1ColumnFuncPtr &draw1, Draw4ColumnsFuncPtr &draw2))) +{ + if (rw_pic->UseType == FTexture::TEX_Null) + return; + + fixed_t xoffset = rw_offset; + + rw_pic->GetHeight(); // To ensure that rw_pic->HeightBits has been set + int fracbits = 32 - rw_pic->HeightBits; if (fracbits == 32) { // Hack for one pixel tall textures fracbits = 0; yrepeat = 0; dc_texturemid = 0; } - setupvline(fracbits); - xoffset = rw_offset; - basecolormapdata = basecolormap->Maps; - x = x1; - //while ((umost[x] > dmost[x]) && (x < x2)) x++; + DWORD(*draw1column)(); + void(*draw4columns)(); + setupwallscan(fracbits, draw1column, draw4columns); bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0); if (fixed) @@ -1126,128 +1258,175 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *l palookupoffse[3] = dc_colormap; } - for(; (x < x2) && (x & 3); ++x) + if (fixedcolormap) + dc_colormap = fixedcolormap; + else + dc_colormap = basecolormap->Maps; + + float light = rw_light; + + // Calculate where 4 column alignment begins and ends: + int aligned_x1 = clamp((x1 + 3) / 4 * 4, x1, x2); + int aligned_x2 = clamp(x2 / 4 * 4, x1, x2); + + // First unaligned columns: + for (int x = x1; x < aligned_x1; x++, light += rw_lightstep) { - light += rw_lightstep; - y1ve[0] = uwal[x];//max(uwal[x],umost[x]); - y2ve[0] = dwal[x];//min(dwal[x],dmost[x]); - if (y2ve[0] <= y1ve[0]) continue; - assert (y1ve[0] < viewheight); - assert (y2ve[0] <= viewheight); + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 <= y1) + continue; if (!fixed) - { // calculate lighting - dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } + dc_colormap = basecolormap->Maps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT); - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + x + dc_destorg; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - dovline1(); + WallscanSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, rw_pic, getcol); + wallscan_drawcol1(x, y1, y2, sampler, draw1column); } - for(; x < x2-3; x += 4) + // The aligned columns + for (int x = aligned_x1; x < aligned_x2; x += 4) { - bad = 0; - for (z = 3; z>= 0; --z) - { - y1ve[z] = uwal[x+z];//max(uwal[x+z],umost[x+z]); - y2ve[z] = dwal[x+z];//min(dwal[x+z],dmost[x+z])-1; - if (y2ve[z] <= y1ve[z]) { bad += 1<> FRACBITS); - iscale = swal[x + z] * yrepeat; - vince[z] = xs_ToFixed(fracbits, iscale); - vplce[z] = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[z] - CenterY + 0.5)); - } - if (bad == 15) + float lights[4]; + for (int i = 0; i < 4; i++) { - light += rw_lightstep * 4; - continue; + lights[i] = light; + light += rw_lightstep; } - if (!fixed) + WallscanSampler sampler[4]; + for (int i = 0; i < 4; i++) + sampler[i] = WallscanSampler(y1[i], swal[x + i], yrepeat, lwal[x + i] + xoffset, rw_pic, getcol); + + // Figure out where we vertically can start and stop drawing 4 columns in one go + int middle_y1 = y1[0]; + int middle_y2 = y2[0]; + for (int i = 1; i < 4; i++) { - for (z = 0; z < 4; ++z) + middle_y1 = MAX(y1[i], middle_y1); + middle_y2 = MIN(y2[i], middle_y2); + } + + // If we got an empty column in our set we cannot draw 4 columns in one go: + bool empty_column_in_set = false; + for (int i = 0; i < 4; i++) + { + if (y2[i] <= y1[i]) + empty_column_in_set = true; + } + + if (empty_column_in_set || middle_y2 <= middle_y1) + { + for (int i = 0; i < 4; i++) { - light += rw_lightstep; - palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - } + if (y2[i] <= y1[i]) + continue; - u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3])); - d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3])); - - if ((bad != 0) || (u4 >= d4)) - { - for (z = 0; z < 4; ++z) - { - if (!(bad & 1)) - { - prevline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg); - } - bad >>= 1; + if (!fixed) + dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT); + wallscan_drawcol1(x + i, y1[i], y2[i], sampler[i], draw1column); } continue; } - for (z = 0; z < 4; ++z) + // Draw the first rows where not all 4 columns are active + for (int i = 0; i < 4; i++) { - if (u4 > y1ve[z]) - { - vplce[z] = prevline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg); - } + if (!fixed) + dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT); + + if (y1[i] < middle_y1) + wallscan_drawcol1(x + i, y1[i], middle_y1, sampler[i], draw1column); } - if (d4 > u4) + // Draw the area where all 4 columns are active + if (!fixed) { - dc_count = d4-u4; - dc_dest = ylookup[u4]+x+dc_destorg; - dovline4(); - } - - BYTE *i = x+ylookup[d4]+dc_destorg; - for (z = 0; z < 4; ++z) - { - if (y2ve[z] > d4) + for (int i = 0; i < 4; i++) { - prevline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z); + palookupoffse[i] = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT); } } + wallscan_drawcol4(x, middle_y1, middle_y2, sampler, draw4columns); + + // Draw the last rows where not all 4 columns are active + for (int i = 0; i < 4; i++) + { + if (!fixed) + dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT); + + if (middle_y2 < y2[i]) + wallscan_drawcol1(x + i, middle_y2, y2[i], sampler[i], draw1column); + } } - for(;xMaps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT); - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + x + dc_destorg; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - dovline1(); + WallscanSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, rw_pic, getcol); + wallscan_drawcol1(x, y1, y2, sampler, draw1column); } -//unclock (WallScanCycles); + NetUpdate(); +} - NetUpdate (); +void wallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) +{ + wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4) + { + setupvline(bits); + line1 = dovline1; + line4 = dovline4; + }); +} + +void maskwallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) +{ + if (!rw_pic->bMasked) // Textures that aren't masked can use the faster wallscan. + { + wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol); + } + else + { + wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4) + { + setupmvline(bits); + line1 = domvline1; + line4 = domvline4; + }); + } +} + +void transmaskwallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) +{ + static fixed_t(*tmvline1)(); + static void(*tmvline4)(); + if (!R_GetTransMaskDrawers(&tmvline1, &tmvline4)) + { + // The current translucency is unsupported, so draw with regular maskwallscan instead. + maskwallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol); + } + else + { + wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4) + { + setuptmvline(bits); + line1 = reinterpret_cast(tmvline1); + line4 = tmvline4; + }); + } } void wallscan_striped (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat) @@ -1423,370 +1602,6 @@ static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *d } } -inline fixed_t mvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest) -{ - dc_iscale = vince; - dc_colormap = colormap; - dc_count = count; - dc_texturefrac = vplce; - dc_source = bufplce; - dc_dest = dest; - return domvline1 (); -} - -void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, - double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) -{ - int x, fracbits; - BYTE *p; - int y1ve[4], y2ve[4], u4, d4, startx, dax, z; - char bad; - float light = rw_light - rw_lightstep; - SDWORD xoffset; - BYTE *basecolormapdata; - double iscale; - - if (rw_pic->UseType == FTexture::TEX_Null) - { - return; - } - - if (!rw_pic->bMasked) - { // Textures that aren't masked can use the faster wallscan. - wallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol); - return; - } - -//extern cycle_t WallScanCycles; -//clock (WallScanCycles); - - rw_pic->GetHeight(); // Make sure texture size is loaded - fracbits = 32- rw_pic->HeightBits; - if (fracbits == 32) - { // Hack for one pixel tall textures - fracbits = 0; - yrepeat = 0; - dc_texturemid = 0; - } - setupmvline(fracbits); - xoffset = rw_offset; - basecolormapdata = basecolormap->Maps; - - x = startx = x1; - p = x + dc_destorg; - - bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0); - if (fixed) - { - palookupoffse[0] = dc_colormap; - palookupoffse[1] = dc_colormap; - palookupoffse[2] = dc_colormap; - palookupoffse[3] = dc_colormap; - } - - for(; (x < x2) && ((size_t)p & 3); ++x, ++p) - { - light += rw_lightstep; - y1ve[0] = uwal[x];//max(uwal[x],umost[x]); - y2ve[0] = dwal[x];//min(dwal[x],dmost[x]); - if (y2ve[0] <= y1ve[0]) continue; - - if (!fixed) - { // calculate lighting - dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + p; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - domvline1(); - } - - for(; x < x2-3; x += 4, p+= 4) - { - bad = 0; - for (z = 3, dax = x+3; z >= 0; --z, --dax) - { - y1ve[z] = uwal[dax]; - y2ve[z] = dwal[dax]; - if (y2ve[z] <= y1ve[z]) { bad += 1<> FRACBITS); - iscale = swal[dax] * yrepeat; - vince[z] = xs_ToFixed(fracbits, iscale); - vplce[z] = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[z] - CenterY + 0.5)); - } - if (bad == 15) - { - light += rw_lightstep * 4; - continue; - } - - if (!fixed) - { - for (z = 0; z < 4; ++z) - { - light += rw_lightstep; - palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - } - - u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3])); - d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3])); - - if ((bad != 0) || (u4 >= d4)) - { - for (z = 0; z < 4; ++z) - { - if (!(bad & 1)) - { - mvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z); - } - bad >>= 1; - } - continue; - } - - for (z = 0; z < 4; ++z) - { - if (u4 > y1ve[z]) - { - vplce[z] = mvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z); - } - } - - if (d4 > u4) - { - dc_count = d4-u4; - dc_dest = ylookup[u4]+p; - domvline4(); - } - - BYTE *i = p+ylookup[d4]; - for (z = 0; z < 4; ++z) - { - if (y2ve[z] > d4) - { - mvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z); - } - } - } - for(; x < x2; ++x, ++p) - { - light += rw_lightstep; - y1ve[0] = uwal[x]; - y2ve[0] = dwal[x]; - if (y2ve[0] <= y1ve[0]) continue; - - if (!fixed) - { // calculate lighting - dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + p; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - domvline1(); - } - -//unclock(WallScanCycles); - - NetUpdate (); -} - -inline void preptmvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest) -{ - dc_iscale = vince; - dc_colormap = colormap; - dc_count = count; - dc_texturefrac = vplce; - dc_source = bufplce; - dc_dest = dest; -} - -void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, - double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) -{ - fixed_t (*tmvline1)(); - void (*tmvline4)(); - int x, fracbits; - BYTE *p; - int y1ve[4], y2ve[4], u4, d4, startx, dax, z; - char bad; - float light = rw_light - rw_lightstep; - SDWORD xoffset; - BYTE *basecolormapdata; - double iscale; - - if (rw_pic->UseType == FTexture::TEX_Null) - { - return; - } - - if (!R_GetTransMaskDrawers (&tmvline1, &tmvline4)) - { - // The current translucency is unsupported, so draw with regular maskwallscan instead. - maskwallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol); - return; - } - -//extern cycle_t WallScanCycles; -//clock (WallScanCycles); - - rw_pic->GetHeight(); // Make sure texture size is loaded - fracbits = 32 - rw_pic->HeightBits; - if (fracbits == 32) - { // Hack for one pixel tall textures - fracbits = 0; - yrepeat = 0; - dc_texturemid = 0; - } - setuptmvline(fracbits); - xoffset = rw_offset; - basecolormapdata = basecolormap->Maps; - fixed_t centeryfrac = FLOAT2FIXED(CenterY); - - x = startx = x1; - p = x + dc_destorg; - - bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0); - if (fixed) - { - palookupoffse[0] = dc_colormap; - palookupoffse[1] = dc_colormap; - palookupoffse[2] = dc_colormap; - palookupoffse[3] = dc_colormap; - } - - for(; (x < x2) && ((size_t)p & 3); ++x, ++p) - { - light += rw_lightstep; - y1ve[0] = uwal[x];//max(uwal[x],umost[x]); - y2ve[0] = dwal[x];//min(dwal[x],dmost[x]); - if (y2ve[0] <= y1ve[0]) continue; - - if (!fixed) - { // calculate lighting - dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + p; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - tmvline1(); - } - - for(; x < x2-3; x += 4, p+= 4) - { - bad = 0; - for (z = 3, dax = x+3; z >= 0; --z, --dax) - { - y1ve[z] = uwal[dax]; - y2ve[z] = dwal[dax]; - if (y2ve[z] <= y1ve[z]) { bad += 1<> FRACBITS); - iscale = swal[dax] * yrepeat; - vince[z] = xs_ToFixed(fracbits, iscale); - vplce[z] = xs_ToFixed(fracbits, dc_texturemid + vince[z] * (y1ve[z] - CenterY + 0.5)); - } - if (bad == 15) - { - light += rw_lightstep * 4; - continue; - } - - if (!fixed) - { - for (z = 0; z < 4; ++z) - { - light += rw_lightstep; - palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - } - - u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3])); - d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3])); - - if ((bad != 0) || (u4 >= d4)) - { - for (z = 0; z < 4; ++z) - { - if (!(bad & 1)) - { - preptmvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z); - tmvline1(); - } - bad >>= 1; - } - continue; - } - - for (z = 0; z < 4; ++z) - { - if (u4 > y1ve[z]) - { - preptmvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z); - vplce[z] = tmvline1(); - } - } - - if (d4 > u4) - { - dc_count = d4-u4; - dc_dest = ylookup[u4]+p; - tmvline4(); - } - - BYTE *i = p+ylookup[d4]; - for (z = 0; z < 4; ++z) - { - if (y2ve[z] > d4) - { - preptmvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z); - tmvline1(); - } - } - } - for(; x < x2; ++x, ++p) - { - light += rw_lightstep; - y1ve[0] = uwal[x]; - y2ve[0] = dwal[x]; - if (y2ve[0] <= y1ve[0]) continue; - - if (!fixed) - { // calculate lighting - dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT); - } - - dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS); - dc_dest = ylookup[y1ve[0]] + p; - dc_count = y2ve[0] - y1ve[0]; - iscale = swal[x] * yrepeat; - dc_iscale = xs_ToFixed(fracbits, iscale); - dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5)); - - tmvline1(); - } - -//unclock(WallScanCycles); - - NetUpdate (); -} - // // R_RenderSegLoop // Draws zero, one, or two textures for walls. From dd1f72bbf91f50a7a782f84da63b9242bedc887b Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 4 Nov 2016 23:27:04 -0400 Subject: [PATCH 062/101] - Check the version of FMOD in CMake to produce an error on the condition that OpenAL is also enabled and the FMOD version is low enough to also export Xiph symbols. --- src/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 09e2201434..576da36478 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -282,6 +282,19 @@ if( NOT NO_FMOD ) if( EXISTS "${FMOD_INCLUDE_DIR}/fmod_common.h" ) set( FMOD_STUDIO YES ) + set( FMOD_VERSION_FILE "fmod_common.h" ) + else() + set( FMOD_STUDIO NO ) + set( FMOD_VERSION_FILE "fmod.h" ) + endif() + + file( STRINGS "${FMOD_INCLUDE_DIR}/${FMOD_VERSION_FILE}" FMOD_VERSION_LINE REGEX "^#define[ \t]+FMOD_VERSION[ \t]+0x[0-9]+$" ) + string( REGEX REPLACE "^#define[ \t]+FMOD_VERSION[ \t]+0x([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])$" "\\1.\\2.\\3" FMOD_VERSION "${FMOD_VERSION_LINE}" ) + message( STATUS "FMOD version: ${FMOD_VERSION}" ) + + # FMOD Ex didn't hide xiph symbols in the past (not applicable to Win32 since symbols are hidden by default there). + if( NOT WIN32 AND NOT FMOD_STUDIO AND NOT NO_OPENAL AND "${FMOD_VERSION}" VERSION_LESS "4.36.00") + message( SEND_ERROR "Use of FMOD Ex ${FMOD_VERSION} with OpenAL will result in crashes. Either update FMOD to 4.36 or later or set NO_OPENAL." ) endif() else() message( STATUS "Could not find FMOD include files" ) From ae28c9b29cdf3f88b6fc335f229aa9f4536df83c Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:09:38 -0500 Subject: [PATCH 063/101] Fix divide by 0 in new wallscan functions with 1-pixel tall textures --- 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 ae33332de6..3697222425 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1114,7 +1114,7 @@ WallscanSampler::WallscanSampler(int y1, float swal, double yrepeat, fixed_t xof // Draw a column with support for non-power-of-two ranges void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*draw1column)()) { - if (sampler.uv_max == 0) // power of two + if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two { int count = y2 - y1; @@ -1162,7 +1162,7 @@ void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*d // Draw four columns with support for non-power-of-two ranges void wallscan_drawcol4(int x, int y1, int y2, WallscanSampler *sampler, void(*draw4columns)()) { - if (sampler[0].uv_max == 0) // power of two, no wrap handling needed + if (sampler[0].uv_max == 0 || sampler[0].uv_step == 0) // power of two, no wrap handling needed { int count = y2 - y1; for (int i = 0; i < 4; i++) From dbc54fbca0d93b9b9f71f218ed3020c8a2057a9a Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:29:02 -0500 Subject: [PATCH 064/101] Fix FillSimplePoly() for 1-pixel tall or wide textures --- src/v_draw.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index bef7328944..d50bea6cc8 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1348,10 +1348,26 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, R_SetupSpanBits(tex); R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap); R_SetSpanSource(tex->GetPixels()); - scalex = double(1u << (32 - ds_xbits)) / scalex; - scaley = double(1u << (32 - ds_ybits)) / scaley; - ds_xstep = xs_RoundToInt(cosrot * scalex); - ds_ystep = xs_RoundToInt(sinrot * scaley); + if (ds_xbits != 0) + { + scalex = double(1u << (32 - ds_xbits)) / scalex; + ds_xstep = xs_RoundToInt(cosrot * scalex); + } + else + { // Texture is one pixel wide. + scalex = 0; + ds_xstep = 0; + } + if (ds_ybits != 0) + { + scaley = double(1u << (32 - ds_ybits)) / scaley; + ds_ystep = xs_RoundToInt(sinrot * scaley); + } + else + { // Texture is one pixel tall. + scaley = 0; + ds_ystep = 0; + } // Travel down the right edge and create an outline of that edge. pt1 = toppt; From 55ee78fc0b133c88b35bc8bde26ca2aa216032c5 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:49:33 -0500 Subject: [PATCH 065/101] Add bottomclip parameter to FillSimplePoly() for the software implementation - Polygons will be clipped to bottomclip. If this is zero or below, they will be clipped to the bottom of the screen instead. This keeps the polygons from overwriting the status bar border for sofware 2D. The hardware version ignores it, since it always draws the status bar border every frame. --- src/am_map.cpp | 3 ++- src/v_draw.cpp | 17 +++++++++++------ src/v_video.h | 2 +- src/win32/fb_d3d9.cpp | 9 +++++++-- src/win32/win32iface.h | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 9292e81d9f..d74927b684 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2046,7 +2046,8 @@ void AM_drawSubsectors() scale / scaley, rotation, colormap, - floorlight + floorlight, + f_y + f_h ); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index d50bea6cc8..8483b9844a 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1282,7 +1282,7 @@ void DCanvas::FinishSimplePolys() void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - FDynamicColormap *colormap, int lightlevel) + FDynamicColormap *colormap, int lightlevel, int bottomclip) { #ifndef NO_SWRENDER // Use an equation similar to player sprites to determine shade @@ -1300,6 +1300,11 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, return; } + if (bottomclip <= 0) + { + bottomclip = Height; + } + // Find the extents of the polygon, in particular the highest and lowest points. for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i) { @@ -1322,7 +1327,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, rightx = points[i].X; } } - if (topy >= Height || // off the bottom of the screen + if (topy >= bottomclip || // off the bottom of the screen boty <= 0 || // off the top of the screen leftx >= Width || // off the right of the screen rightx <= 0) // off the left of the screen @@ -1377,13 +1382,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, { x = FLOAT2FIXED(points[pt1].X + 0.5f); y2 = xs_RoundToInt(points[pt2].Y + 0.5f); - if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip)) { } else { fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); - int y3 = MIN(y2, Height); + int y3 = MIN(y2, bottomclip); if (y1 < 0) { x += xinc * -y1; @@ -1408,13 +1413,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, { x = FLOAT2FIXED(points[pt1].X + 0.5f); y2 = xs_RoundToInt(points[pt2].Y + 0.5f); - if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip)) { } else { fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); - int y3 = MIN(y2, Height); + int y3 = MIN(y2, bottomclip); if (y1 < 0) { x += xinc * -y1; diff --git a/src/v_video.h b/src/v_video.h index d19a3b06ec..890ab6d638 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -224,7 +224,7 @@ public: // Fill a simple polygon with a texture virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - struct FDynamicColormap *colormap, int lightlevel); + struct FDynamicColormap *colormap, int lightlevel, int bottomclip); // Set an area to a specified color virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color); diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 8bb680dbda..10ab11c729 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -3084,11 +3084,16 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo // // Here, "simple" means that a simple triangle fan can draw it. // +// Bottomclip is ignored by this implementation, since the hardware renderer +// will unconditionally draw the status bar border every frame on top of the +// polygons, so there's no need to waste time setting up a special scissor +// rectangle here and needlessly forcing separate batches. +// //========================================================================== void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel) + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) { // Use an equation similar to player sprites to determine shade double fadelevel = clamp((LIGHT2SHADE(lightlevel)/65536. - 12) / NUMCOLORMAPS, 0.0, 1.0); @@ -3109,7 +3114,7 @@ void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, } if (In2D < 2) { - Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel); + Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel, bottomclip); return; } if (!InScene) diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 9b2754eae1..b5262089bc 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -265,7 +265,7 @@ public: void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor); void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel); + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) override; bool WipeStartScreen(int type); void WipeEndScreen(); bool WipeDo(int ticks); From 640bf2a6d4f878a0262bfa28e77d5b003311d834 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 6 Nov 2016 17:07:44 -0500 Subject: [PATCH 066/101] - Fixed: SBarInfo didn't support animated images in some places. --- src/g_shared/sbarinfo_commands.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index d105ab8180..b3aecb0b54 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -241,7 +241,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl applyscale = false; } if(type == PLAYERICON) - texture = TexMan[statusBar->CPlayer->mo->ScoreIcon]; + texture = TexMan(statusBar->CPlayer->mo->ScoreIcon); else if(type == AMMO1) { AAmmo *ammo = statusBar->ammo1; @@ -270,7 +270,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { AInventory *item = statusBar->CPlayer->mo->FindInventory(); if (item != NULL) - texture = TexMan[item->Icon]; + texture = TexMan(item->Icon); } else if(type == HEXENARMOR_ARMOR || type == HEXENARMOR_SHIELD || type == HEXENARMOR_HELM || type == HEXENARMOR_AMULET) { @@ -290,7 +290,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl } } else if(type == INVENTORYICON) - texture = TexMan[sprite]; + texture = TexMan(sprite); else if(type == SELECTEDINVENTORYICON && statusBar->CPlayer->mo->InvSel != NULL) texture = TexMan(statusBar->CPlayer->mo->InvSel->Icon); else if(image >= 0) @@ -312,7 +312,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl spawnScaleY = item->Scale.Y; } - texture = TexMan[icon]; + texture = TexMan(icon); } enum ImageType @@ -2436,22 +2436,22 @@ class CommandDrawKeyBar : public SBarInfoCommand { if(!vertical) { - statusBar->DrawGraphic(TexMan[item->Icon], x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledHeight()+2 : rowIconSize; + statusBar->DrawGraphic(TexMan(item->Icon), x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan(item->Icon)->GetScaledHeight()+2 : rowIconSize; } else { - statusBar->DrawGraphic(TexMan[item->Icon], x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledWidth()+2 : rowIconSize; + statusBar->DrawGraphic(TexMan(item->Icon), x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan(item->Icon)->GetScaledWidth()+2 : rowIconSize; } // If cmd.special is -1 then the slot size is auto detected if(iconSize == -1) { if(!vertical) - slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledWidth() + 2); + slotOffset += (reverse ? -1 : 1) * (TexMan(item->Icon)->GetScaledWidth() + 2); else - slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledHeight() + 2); + slotOffset += (reverse ? -1 : 1) * (TexMan(item->Icon)->GetScaledHeight() + 2); } else slotOffset += (reverse ? -iconSize : iconSize); From d36993a03b8bf46fd47f5c6377834d849ab374c8 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 8 Nov 2016 15:05:23 -0500 Subject: [PATCH 067/101] - Textured automap would crash due to an additional parameter in the software renderer to the FillSimplePoly function call, causing stack issues. --- src/gl/renderer/gl_renderer.h | 2 +- src/gl/system/gl_framebuffer.cpp | 2 +- src/gl/system/gl_framebuffer.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 19bc93af02..6ea1e357a2 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -206,7 +206,7 @@ public: void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel); + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip); int PTM_BestColor (const uint32 *pal_in, int r, int g, int b, int first, int num); }; diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 6264352f6c..4904cc1f6f 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -464,7 +464,7 @@ void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palc void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel) + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) { if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr && npoints >= 3) { diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 5315bb0a9a..27c3d1cf97 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -71,7 +71,7 @@ public: void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel); + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip); FNativePalette *CreatePalette(FRemapTable *remap); From fd31c8474589464cf2c51da97609373d6c86deb6 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Fri, 11 Nov 2016 17:18:39 +0800 Subject: [PATCH 068/101] Added a slider to control the intensity of underwater screen blending. --- src/g_shared/shared_sbar.cpp | 6 +++++- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.txt | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index a3bb76b7f4..5e76b422f2 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -119,6 +119,7 @@ CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) } CVAR (Bool, idmypos, false, 0); +CVAR(Float, underwater_fade_scalar, 1.0f, CVAR_ARCHIVE) // [Nash] user-settable underwater blend intensity //--------------------------------------------------------------------------- // @@ -1544,7 +1545,10 @@ void DBaseStatusBar::DrawPowerups () void DBaseStatusBar::BlendView (float blend[4]) { - V_AddBlend (BaseBlendR / 255.f, BaseBlendG / 255.f, BaseBlendB / 255.f, BaseBlendA, blend); + // [Nash] Allow user to set blend intensity + float cnt = (BaseBlendA * underwater_fade_scalar); + + V_AddBlend (BaseBlendR / 255.f, BaseBlendG / 255.f, BaseBlendB / 255.f, cnt, blend); V_AddPlayerBlend(CPlayer, blend, 1.0f, 228); if (screen->Accel2D || (CPlayer->camera != NULL && menuactive == MENU_Off && ConsoleState == c_up)) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 01eb692b8e..28db40e649 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1784,6 +1784,7 @@ DSPLYMNU_WIPETYPE = "Screen wipe style"; DSPLYMNU_SHOWENDOOM = "Show ENDOOM screen"; DSPLYMNU_BLOODFADE = "Blood Flash Intensity"; DSPLYMNU_PICKUPFADE = "Pickup Flash Intensity"; +DSPLYMNU_WATERFADE = "Underwater Blend Intensity"; DSPLYMNU_PALLETEHACK = "DirectDraw palette hack"; // Not used DSPLYMNU_ATTACHEDSURFACES = "Use attached surfaces"; // Not used DSPLYMNU_SKYMODE = "Sky render mode"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index dac933af81..30cad4dd24 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -669,6 +669,7 @@ OptionMenu "VideoOptions" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 2 Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 2 + Slider "$DSPLYMNU_WATERFADE", "underwater_fade_scalar", 0.0, 1.0, 0.05, 2 Option "$DSPLYMNU_COLUMNMETHOD", "r_columnmethod", "ColumnMethods" StaticText " " From 970c750daa8bcf9f0ace7bb153198b488f4f32e1 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Fri, 11 Nov 2016 18:08:47 +0800 Subject: [PATCH 069/101] Added OpenGL support to the underwater view blend scalar option. --- src/gl/scene/gl_scene.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b53be4aaa6..1437d3fd5d 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -82,6 +82,7 @@ CVAR(Bool, gl_sort_textures, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) EXTERN_CVAR (Bool, cl_capfps) EXTERN_CVAR (Bool, r_deathcamera) +EXTERN_CVAR (Float, underwater_fade_scalar) extern int viewpitch; @@ -602,7 +603,11 @@ void FGLRenderer::DrawBlend(sector_t * viewsector) } else if (blendv.a) { - V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, blendv.a / 255.0f, blend); + // [Nash] allow user to set blend intensity + int cnt = blendv.a; + cnt = (int)(cnt * underwater_fade_scalar); + + V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, cnt / 255.0f, blend); } } From 3926ca13b0b32d3f5936241005e51d60041d4967 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 11 Nov 2016 22:31:49 -0600 Subject: [PATCH 070/101] Fix console input not scrolling when you hit the side of the screen - Also changed the console input buffer into a struct instead of a frankenstein buffer. --- src/c_console.cpp | 529 +++++++++++++++++++++++----------------------- src/v_video.cpp | 2 - src/zstring.cpp | 97 ++++++--- src/zstring.h | 1 + 4 files changed, 340 insertions(+), 289 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 2d164c4787..2be93a2396 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -100,7 +100,7 @@ extern bool advancedemo; extern FBaseCVar *CVars; extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; -int ConCols, PhysRows; +unsigned ConCols, PhysRows; int ConWidth; bool vidactive = false; bool cursoron = false; @@ -112,7 +112,6 @@ constate_e ConsoleState = c_up; static int TopLine, InsertLine; static void ClearConsole (); -static void C_PasteText(FString clip, BYTE *buffer, int len); struct GameAtExit { @@ -139,27 +138,9 @@ static bool ConsoleDrawing; static char *work = NULL; static int worklen = 0; - -struct History -{ - struct History *Older; - struct History *Newer; - char String[1]; -}; - -// CmdLine[0] = # of chars on command line -// CmdLine[1] = cursor position -// CmdLine[2+] = command line (max 255 chars + NULL) -// CmdLine[259]= offset from beginning of cmdline to display -static BYTE CmdLine[260]; - -#define MAXHISTSIZE 50 -static struct History *HistHead = NULL, *HistTail = NULL, *HistPos = NULL; -static int HistSize; - -CVAR (Float, con_notifytime, 3.f, CVAR_ARCHIVE) -CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE) -CUSTOM_CVAR (Int, con_scaletext, 1, CVAR_ARCHIVE) // Scale notify text at high resolutions? +CVAR(Float, con_notifytime, 3.f, CVAR_ARCHIVE) +CVAR(Bool, con_centernotify, false, CVAR_ARCHIVE) +CUSTOM_CVAR(Int, con_scaletext, 1, CVAR_ARCHIVE) // Scale notify text at high resolutions? { if (self < 0) self = 0; if (self > 3) self = 3; @@ -172,10 +153,16 @@ CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE) int active_con_scale() { - if (con_scale == 0) - return uiscale; - else - return con_scale; + int scale = con_scale; + if (scale == 0) + { + scale = uiscale; + if (scale == 0) + { + scale = CleanXfac; + } + } + return scale; } int active_con_scaletext() @@ -197,7 +184,195 @@ CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) } // Command to run when Ctrl-D is pressed at start of line -CVAR (String, con_ctrl_d, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(String, con_ctrl_d, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + + +struct History +{ + struct History *Older; + struct History *Newer; + FString String; +}; + +struct FCommandBuffer +{ + FString Text; // The actual command line text + unsigned CursorPos; + unsigned StartPos; // First character to display + + FCommandBuffer() + { + CursorPos = StartPos = 0; + } + + FCommandBuffer(const FCommandBuffer &o) + { + Text = o.Text; + CursorPos = o.CursorPos; + StartPos = o.StartPos; + } + + void Draw(int x, int y, int scale, bool cursor) + { + if (scale == 1) + { + screen->DrawChar(ConFont, CR_ORANGE, x, y, '\x1c', TAG_DONE); + screen->DrawText(ConFont, CR_ORANGE, x + ConFont->GetCharWidth(0x1c), y, + &Text[StartPos], TAG_DONE); + + if (cursor) + { + screen->DrawChar(ConFont, CR_YELLOW, + x + ConFont->GetCharWidth(0x1c) + (CursorPos - StartPos) * ConFont->GetCharWidth(0xb), + y, '\xb', TAG_DONE); + } + } + else + { + screen->DrawChar(ConFont, CR_ORANGE, x, y, '\x1c', + DTA_VirtualWidth, screen->GetWidth() / scale, + DTA_VirtualHeight, screen->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + + screen->DrawText(ConFont, CR_ORANGE, x + ConFont->GetCharWidth(0x1c), y, + &Text[StartPos], + DTA_VirtualWidth, screen->GetWidth() / scale, + DTA_VirtualHeight, screen->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + + if (cursor) + { + screen->DrawChar(ConFont, CR_YELLOW, + x + ConFont->GetCharWidth(0x1c) + (CursorPos - StartPos) * ConFont->GetCharWidth(0xb), + y, '\xb', + DTA_VirtualWidth, screen->GetWidth() / scale, + DTA_VirtualHeight, screen->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + } + } + } + + void MakeStartPosGood() + { + int n = StartPos; + unsigned cols = ConCols / active_con_scale(); + + if (StartPos >= Text.Len()) + { // Start of visible line is beyond end of line + n = CursorPos - cols + 2; + } + if ((CursorPos - StartPos) >= cols - 2) + { // The cursor is beyond the visible part of the line + n = CursorPos - cols + 2; + } + if (StartPos > CursorPos) + { // The cursor is in front of the visible part of the line + n = CursorPos; + } + StartPos = MAX(0, n); + } + + void CursorStart() + { + CursorPos = 0; + StartPos = 0; + } + + void CursorEnd() + { + CursorPos = Text.Len(); + StartPos = 0; + MakeStartPosGood(); + } + + void CursorLeft() + { + if (CursorPos > 0) + { + CursorPos--; + MakeStartPosGood(); + } + } + + void CursorRight() + { + if (CursorPos < Text.Len()) + { + CursorPos++; + MakeStartPosGood(); + } + } + + void DeleteLeft() + { + if (CursorPos > 0) + { + Text.Remove(CursorPos - 1, 1); + CursorPos--; + MakeStartPosGood(); + } + } + + void DeleteRight() + { + if (CursorPos < Text.Len()) + { + Text.Remove(CursorPos, 1); + MakeStartPosGood(); + } + } + + void AddChar(int character) + { + ///FIXME: Not Unicode-aware + if (CursorPos == Text.Len()) + { + Text += char(character); + } + else + { + char foo = char(character); + Text.Insert(CursorPos, &foo, 1); + } + CursorPos++; + MakeStartPosGood(); + } + + void AddString(FString clip) + { + if (clip.IsNotEmpty()) + { + // Only paste the first line. + long brk = clip.IndexOfAny("\r\n\b"); + if (brk >= 0) + { + clip.Truncate(brk); + } + if (Text.IsEmpty()) + { + Text = clip; + } + else + { + Text.Insert(CursorPos, clip); + } + CursorPos += clip.Len(); + MakeStartPosGood(); + } + } + + void SetString(FString str) + { + Text = str; + CursorPos = Text.Len(); + MakeStartPosGood(); + } +}; +static FCommandBuffer CmdLine; + +#define MAXHISTSIZE 50 +static struct History *HistHead = NULL, *HistTail = NULL, *HistPos = NULL; +static int HistSize; #define NUMNOTIFIES 4 #define NOTIFYFADETIME 6 @@ -860,8 +1035,6 @@ void C_DrawConsole (bool hw2d) int lines, left, offset; int textScale = active_con_scale(); - if (textScale == 0) - textScale = CleanXfac; left = LEFTMARGIN; lines = (ConBottom/textScale-ConFont->GetHeight()*2)/ConFont->GetHeight(); @@ -1037,44 +1210,8 @@ void C_DrawConsole (bool hw2d) { // Make a copy of the command line, in case an input event is handled // while we draw the console and it changes. - CmdLine[2+CmdLine[0]] = 0; - FString command((char *)&CmdLine[2+CmdLine[259]]); - int cursorpos = CmdLine[1] - CmdLine[259]; - - if (textScale == 1) - { - screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c', TAG_DONE); - screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline, - command, TAG_DONE); - - if (cursoron) - { - screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb), - bottomline, '\xb', TAG_DONE); - } - } - else - { - screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c', - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - - screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline, - command, - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - - if (cursoron) - { - screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb), - bottomline, '\xb', - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - } - } + FCommandBuffer command(CmdLine); + command.Draw(left, bottomline, textScale, cursoron); } if (RowAdjust && ConBottom >= ConFont->GetHeight()*7/2) { @@ -1146,35 +1283,8 @@ void C_HideConsole () } } -static void makestartposgood () +static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) { - int n; - int pos = CmdLine[259]; - int curs = CmdLine[1]; - int len = CmdLine[0]; - - n = pos; - - if (pos >= len) - { // Start of visible line is beyond end of line - n = curs - ConCols + 2; - } - if ((curs - pos) >= ConCols - 2) - { // The cursor is beyond the visible part of the line - n = curs - ConCols + 2; - } - if (pos > curs) - { // The cursor is in front of the visible part of the line - n = curs; - } - if (n < 0) - n = 0; - CmdLine[259] = n; -} - -static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) -{ - int i; int data1 = ev->data1; switch (ev->subtype) @@ -1184,29 +1294,8 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) case EV_GUI_Char: // Add keypress to command line - if (buffer[0] < len) - { - if (buffer[1] == buffer[0]) - { - buffer[buffer[0] + 2] = BYTE(ev->data1); - } - else - { - char *c, *e; - - e = (char *)&buffer[buffer[0] + 1]; - c = (char *)&buffer[buffer[1] + 2]; - - for (; e >= c; e--) - *(e + 1) = *e; - - *c = char(ev->data1); - } - buffer[0]++; - buffer[1]++; - makestartposgood (); - HistPos = NULL; - } + buffer.AddChar(ev->data1); + HistPos = NULL; TabbedLast = false; TabbedList = false; break; @@ -1289,7 +1378,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) } else { // Move cursor to start of line - buffer[1] = buffer[len+4] = 0; + buffer.CursorStart(); } break; @@ -1300,66 +1389,30 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) } else { // Move cursor to end of line - buffer[1] = buffer[0]; - makestartposgood (); + buffer.CursorEnd(); } break; case GK_LEFT: // Move cursor left one character - if (buffer[1]) - { - buffer[1]--; - makestartposgood (); - } + buffer.CursorLeft(); break; case GK_RIGHT: // Move cursor right one character - if (buffer[1] < buffer[0]) - { - buffer[1]++; - makestartposgood (); - } + buffer.CursorRight(); break; case '\b': // Erase character to left of cursor - if (buffer[0] && buffer[1]) - { - char *c, *e; - - e = (char *)&buffer[buffer[0] + 2]; - c = (char *)&buffer[buffer[1] + 2]; - - for (; c < e; c++) - *(c - 1) = *c; - - buffer[0]--; - buffer[1]--; - if (buffer[len+4]) - buffer[len+4]--; - makestartposgood (); - } + buffer.DeleteLeft(); TabbedLast = false; TabbedList = false; break; case GK_DEL: // Erase character under cursor - if (buffer[1] < buffer[0]) - { - char *c, *e; - - e = (char *)&buffer[buffer[0] + 2]; - c = (char *)&buffer[buffer[1] + 3]; - - for (; c < e; c++) - *(c - 1) = *c; - - buffer[0]--; - makestartposgood (); - } + buffer.DeleteRight(); TabbedLast = false; TabbedList = false; break; @@ -1377,10 +1430,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) if (HistPos) { - strcpy ((char *)&buffer[2], HistPos->String); - buffer[0] = buffer[1] = (BYTE)strlen ((char *)&buffer[2]); - buffer[len+4] = 0; - makestartposgood(); + buffer.SetString(HistPos->String); } TabbedLast = false; @@ -1392,17 +1442,13 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) if (HistPos && HistPos->Newer) { HistPos = HistPos->Newer; - - strcpy ((char *)&buffer[2], HistPos->String); - buffer[0] = buffer[1] = (BYTE)strlen ((char *)&buffer[2]); + buffer.SetString(HistPos->String); } else { HistPos = NULL; - buffer[0] = buffer[1] = 0; + buffer.SetString(""); } - buffer[len+4] = 0; - makestartposgood(); TabbedLast = false; TabbedList = false; break; @@ -1410,24 +1456,19 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) case 'X': if (ev->data3 & GKM_CTRL) { - buffer[1] = buffer[0] = 0; + buffer.SetString(""); TabbedLast = TabbedList = false; } break; case 'D': - if (ev->data3 & GKM_CTRL && buffer[0] == 0) + if (ev->data3 & GKM_CTRL && buffer.Text.Len() == 0) { // Control-D pressed on an empty line - int replen = (int)strlen (con_ctrl_d); - - if (replen == 0) + if (strlen(con_ctrl_d) == 0) + { break; // Replacement is empty, so do nothing - - if (replen > len) - replen = len; - - memcpy (&buffer[2], con_ctrl_d, replen); - buffer[0] = buffer[1] = replen; + } + buffer.SetString(*con_ctrl_d); } else { @@ -1438,16 +1479,16 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) case '\r': // Execute command line (ENTER) - buffer[2 + buffer[0]] = 0; + buffer.Text.StripLeftRight(); + Printf(127, TEXTCOLOR_WHITE "]%s\n", buffer.Text.GetChars()); + AddCommandString(buffer.Text.LockBuffer()); + buffer.Text.UnlockBuffer(); - for (i = 0; i < buffer[0] && isspace(buffer[2+i]); ++i) - { - } - if (i == buffer[0]) + if (buffer.Text.Len() == 0) { // Command line is empty, so do nothing to the history } - else if (HistHead && stricmp (HistHead->String, (char *)&buffer[2]) == 0) + else if (HistHead && HistHead->String.CompareNoCase(buffer.Text) == 0) { // Command line was the same as the previous one, // so leave the history list alone @@ -1458,9 +1499,8 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) // or there is nothing in the history list, // so add it to the history list. - History *temp = (History *)M_Malloc (sizeof(struct History) + buffer[0]); - - strcpy (temp->String, (char *)&buffer[2]); + History *temp = new History; + temp->String = buffer.Text; temp->Older = HistHead; if (HistHead) { @@ -1477,7 +1517,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) if (HistSize == MAXHISTSIZE) { HistTail = HistTail->Newer; - M_Free (HistTail->Older); + delete HistTail->Older; HistTail->Older = NULL; } else @@ -1486,9 +1526,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) } } HistPos = NULL; - Printf (127, TEXTCOLOR_WHITE "]%s\n", &buffer[2]); - buffer[0] = buffer[1] = buffer[len+4] = 0; - AddCommandString ((char *)&buffer[2]); + buffer.SetString(""); TabbedLast = false; TabbedList = false; break; @@ -1514,7 +1552,7 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) } else { - buffer[0] = buffer[1] = buffer[len+4] = 0; + buffer.SetString(""); HistPos = NULL; C_ToggleConsole (); } @@ -1532,15 +1570,15 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) { if (data1 == 'C') { // copy to clipboard - if (buffer[0] > 0) + if (buffer.Text.IsNotEmpty()) { - buffer[2 + buffer[0]] = 0; - I_PutInClipboard ((char *)&buffer[2]); + I_PutInClipboard(buffer.Text); } } else { // paste from clipboard - C_PasteText(I_GetFromClipboard(false), buffer, len); + buffer.AddString(I_GetFromClipboard(false)); + HistPos = NULL; } break; } @@ -1550,7 +1588,8 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) #ifdef __unix__ case EV_GUI_MButtonDown: - C_PasteText(I_GetFromClipboard(true), buffer, len); + buffer.AddString(I_GetFromClipboard(true)); + HistPos = NULL; break; #endif } @@ -1560,36 +1599,6 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len) return true; } -static void C_PasteText(FString clip, BYTE *buffer, int len) -{ - if (clip.IsNotEmpty()) - { - // Only paste the first line. - long brk = clip.IndexOfAny("\r\n\b"); - int cliplen = brk >= 0 ? brk : (int)clip.Len(); - - // Make sure there's room for the whole thing. - if (buffer[0] + cliplen > len) - { - cliplen = len - buffer[0]; - } - - if (cliplen > 0) - { - if (buffer[1] < buffer[0]) - { - memmove (&buffer[2 + buffer[1] + cliplen], - &buffer[2 + buffer[1]], buffer[0] - buffer[1]); - } - memcpy (&buffer[2 + buffer[1]], clip, cliplen); - buffer[0] += cliplen; - buffer[1] += cliplen; - makestartposgood (); - HistPos = NULL; - } - } -} - bool C_Responder (event_t *ev) { if (ev->type != EV_GUI_Event || @@ -1600,7 +1609,7 @@ bool C_Responder (event_t *ev) return false; } - return C_HandleKey (ev, CmdLine, 255); + return C_HandleKey(ev, CmdLine); } CCMD (history) @@ -1793,7 +1802,7 @@ static int FindDiffPoint (FName name1, const char *str2) static void C_TabComplete (bool goForward) { - int i; + unsigned i; int diffpoint; if (!TabbedLast) @@ -1801,25 +1810,20 @@ static void C_TabComplete (bool goForward) bool cancomplete; // Skip any spaces at beginning of command line - if (CmdLine[2] == ' ') + for (i = 0; i < CmdLine.Text.Len(); ++i) { - for (i = 0; i < CmdLine[0]; i++) - if (CmdLine[2+i] != ' ') - break; - - TabStart = i + 2; + if (CmdLine.Text[i] != ' ') + break; } - else - { - TabStart = 2; + if (i == CmdLine.Text.Len()) + { // Line was nothing but spaces + return; } + TabStart = i; - if (TabStart == CmdLine[0] + 2) - return; // Line was nothing but spaces + TabSize = CmdLine.Text.Len() - TabStart; - TabSize = CmdLine[0] - TabStart + 2; - - if (!FindTabCommand ((char *)(CmdLine + TabStart), &TabPos, TabSize)) + if (!FindTabCommand(&CmdLine.Text[TabStart], &TabPos, TabSize)) return; // No initial matches // Show a list of possible completions, if more than one. @@ -1842,7 +1846,7 @@ static void C_TabComplete (bool goForward) { // Find the last matching tab, then go one past it. while (++TabPos < (int)TabCommands.Size()) { - if (FindDiffPoint (TabCommands[TabPos].TabName, (char *)(CmdLine + TabStart)) < TabSize) + if (FindDiffPoint(TabCommands[TabPos].TabName, &CmdLine.Text[TabStart]) < TabSize) { break; } @@ -1859,27 +1863,26 @@ static void C_TabComplete (bool goForward) (!goForward && --TabPos < 0)) { TabbedLast = false; - CmdLine[0] = CmdLine[1] = TabSize; + CmdLine.Text.Truncate(TabSize); } else { - diffpoint = FindDiffPoint (TabCommands[TabPos].TabName, (char *)(CmdLine + TabStart)); + diffpoint = FindDiffPoint(TabCommands[TabPos].TabName, &CmdLine.Text[TabStart]); if (diffpoint < TabSize) { // No more matches TabbedLast = false; - CmdLine[0] = CmdLine[1] = TabSize + TabStart - 2; + CmdLine.Text.Truncate(TabSize - TabStart); } else - { - strcpy ((char *)(CmdLine + TabStart), TabCommands[TabPos].TabName.GetChars()); - CmdLine[0] = CmdLine[1] = (BYTE)strlen ((char *)(CmdLine + 2)) + 1; - CmdLine[CmdLine[0] + 1] = ' '; + { + CmdLine.Text.Truncate(TabStart); + CmdLine.Text << TabCommands[TabPos].TabName << ' '; } } - - makestartposgood (); + CmdLine.CursorPos = CmdLine.Text.Len(); + CmdLine.MakeStartPosGood(); } static bool C_TabCompleteList () @@ -1893,7 +1896,7 @@ static bool C_TabCompleteList () for (i = TabPos; i < (int)TabCommands.Size(); ++i) { - if (FindDiffPoint (TabCommands[i].TabName, (char *)(CmdLine + TabStart)) < TabSize) + if (FindDiffPoint (TabCommands[i].TabName, &CmdLine.Text[TabStart]) < TabSize) { break; } @@ -1918,7 +1921,7 @@ static bool C_TabCompleteList () { size_t x = 0; maxwidth += 3; - Printf (TEXTCOLOR_BLUE "Completions for %s:\n", CmdLine+2); + Printf (TEXTCOLOR_BLUE "Completions for %s:\n", CmdLine.Text.GetChars()); for (i = TabPos; nummatches > 0; ++i, --nummatches) { // [Dusk] Print console commands blue, CVars green, aliases red. @@ -1936,7 +1939,7 @@ static bool C_TabCompleteList () Printf ("%s%-*s", colorcode, int(maxwidth), TabCommands[i].TabName.GetChars()); x += maxwidth; - if (x > ConCols - maxwidth) + if (x > ConCols / active_con_scale() - maxwidth) { x = 0; Printf ("\n"); @@ -1950,9 +1953,9 @@ static bool C_TabCompleteList () if (TabSize != commonsize) { TabSize = commonsize; - strncpy ((char *)CmdLine + TabStart, TabCommands[TabPos].TabName.GetChars(), commonsize); - CmdLine[0] = TabStart + commonsize - 2; - CmdLine[1] = CmdLine[0]; + CmdLine.Text.Truncate(TabStart); + CmdLine.Text.AppendCStrPart(TabCommands[TabPos].TabName.GetChars(), commonsize); + CmdLine.CursorPos = CmdLine.Text.Len(); } return false; } diff --git a/src/v_video.cpp b/src/v_video.cpp index b1f1ced9cf..37cfdd4801 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -877,8 +877,6 @@ void DFrameBuffer::DrawRateStuff () int rate_x; int textScale = active_con_scale(); - if (textScale == 0) - textScale = CleanXfac; chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount); rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]); diff --git a/src/zstring.cpp b/src/zstring.cpp index f4a3a1fbbf..63fdf64285 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -343,28 +343,74 @@ FString &FString::operator += (char tail) FString &FString::AppendCStrPart (const char *tail, size_t tailLen) { - size_t len1 = Len(); - ReallocBuffer (len1 + tailLen); - StrCopy (Chars + len1, tail, tailLen); + if (tailLen > 0) + { + size_t len1 = Len(); + ReallocBuffer(len1 + tailLen); + StrCopy(Chars + len1, tail, tailLen); + } return *this; } FString &FString::CopyCStrPart(const char *tail, size_t tailLen) { - ReallocBuffer(tailLen); - StrCopy(Chars, tail, tailLen); + if (tailLen > 0) + { + ReallocBuffer(tailLen); + StrCopy(Chars, tail, tailLen); + } + else + { + Data()->Release(); + NullString.RefCount++; + Chars = &NullString.Nothing[0]; + } return *this; } void FString::Truncate(long newlen) { - if (newlen >= 0 && newlen < (long)Len()) + if (newlen <= 0) + { + Data()->Release(); + NullString.RefCount++; + Chars = &NullString.Nothing[0]; + } + else if (newlen < (long)Len()) { ReallocBuffer (newlen); Chars[newlen] = '\0'; } } +void FString::Remove(size_t index, size_t remlen) +{ + if (index < Len()) + { + if (index + remlen >= Len()) + { + Truncate((long)index); + } + else + { + remlen = Len() - remlen < remlen ? Len() - remlen : remlen; + if (Data()->RefCount == 1) + { // Can do this in place + memmove(Chars + index, Chars + index + remlen, Len() - index - remlen); + Data()->Len -= remlen; + } + else + { // Must do it in a copy + FStringData *old = Data(); + AllocBuffer(old->Len - remlen); + StrCopy(Chars, old->Chars(), index); + StrCopy(Chars + index, old->Chars() + index + remlen, old->Len - index - remlen); + old->Release(); + } + } + } +} + FString FString::Left (size_t numChars) const { size_t len = Len(); @@ -768,25 +814,28 @@ void FString::Insert (size_t index, const char *instr) void FString::Insert (size_t index, const char *instr, size_t instrlen) { - size_t mylen = Len(); - if (index > mylen) + if (instrlen > 0) { - index = mylen; - } - if (Data()->RefCount <= 1) - { - ReallocBuffer (mylen + instrlen); - memmove (Chars + index + instrlen, Chars + index, (mylen - index + 1)*sizeof(char)); - memcpy (Chars + index, instr, instrlen*sizeof(char)); - } - else - { - FStringData *old = Data(); - AllocBuffer (mylen + instrlen); - StrCopy (Chars, old->Chars(), index); - StrCopy (Chars + index, instr, instrlen); - StrCopy (Chars + index + instrlen, old->Chars() + index, mylen - index); - old->Release(); + size_t mylen = Len(); + if (index >= mylen) + { + AppendCStrPart(instr, instrlen); + } + else if (Data()->RefCount <= 1) + { + ReallocBuffer(mylen + instrlen); + memmove(Chars + index + instrlen, Chars + index, (mylen - index + 1) * sizeof(char)); + memcpy(Chars + index, instr, instrlen * sizeof(char)); + } + else + { + FStringData *old = Data(); + AllocBuffer(mylen + instrlen); + StrCopy(Chars, old->Chars(), index); + StrCopy(Chars + index, instr, instrlen); + StrCopy(Chars + index + instrlen, old->Chars() + index, mylen - index); + old->Release(); + } } } diff --git a/src/zstring.h b/src/zstring.h index 00f373b59a..ba92087199 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -268,6 +268,7 @@ public: bool IsNotEmpty() const { return Len() != 0; } void Truncate (long newlen); + void Remove(size_t index, size_t remlen); int Compare (const FString &other) const { return strcmp (Chars, other.Chars); } int Compare (const char *other) const { return strcmp (Chars, other); } From 4dce07762bd05bed6eb35a19f32926176097e5b8 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 11 Nov 2016 22:43:42 -0600 Subject: [PATCH 071/101] Change con_scale behavior for value 0 - Do not use uiscale for con_scale default. A 40 column console when everything is defaults is maddening. The default is now CleanXfac minus 1. --- src/c_console.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 2be93a2396..180898cc5e 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -154,12 +154,12 @@ CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE) int active_con_scale() { int scale = con_scale; - if (scale == 0) + if (scale <= 0) { - scale = uiscale; - if (scale == 0) + scale = CleanXfac - 1; + if (scale <= 0) { - scale = CleanXfac; + scale = 1; } } return scale; From c5eb28d360d8fe6b61fc8f4afbfff236d462accd Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 11 Nov 2016 22:56:19 -0600 Subject: [PATCH 072/101] Fix console scrolling too far when page scrolling with scaled text --- src/c_console.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 180898cc5e..d4377682db 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -100,7 +100,7 @@ extern bool advancedemo; extern FBaseCVar *CVars; extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; -unsigned ConCols, PhysRows; +unsigned ConCols; int ConWidth; bool vidactive = false; bool cursoron = false; @@ -533,7 +533,6 @@ void C_InitConsole (int width, int height, bool ingame) } ConWidth = (width - LEFTMARGIN - RIGHTMARGIN); ConCols = ConWidth / cwidth; - PhysRows = height / cheight; if (conbuffer == NULL) conbuffer = new FConsoleBuffer; } @@ -1324,7 +1323,7 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) case GK_PGUP: if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) { // Scroll console buffer up one page - RowAdjust += (SCREENHEIGHT-4) / + RowAdjust += (SCREENHEIGHT-4)/active_con_scale() / ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? ConFont->GetHeight() : ConFont->GetHeight()*2) - 3; } else if (RowAdjust < conbuffer->GetFormattedLineCount()) @@ -1347,7 +1346,7 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) case GK_PGDN: if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) { // Scroll console buffer down one page - const int scrollamt = (SCREENHEIGHT-4) / + const int scrollamt = (SCREENHEIGHT-4)/active_con_scale() / ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? ConFont->GetHeight() : ConFont->GetHeight()*2) - 3; if (RowAdjust < scrollamt) { From 513ad7f75ff39c9fc065a56d39ae89d03a82e9be Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 11 Nov 2016 23:01:29 -0600 Subject: [PATCH 073/101] Use FString to store console atexit commands --- src/c_console.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index d4377682db..2f86228b70 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -115,8 +115,10 @@ static void ClearConsole (); struct GameAtExit { + GameAtExit(FString str) : Command(str) {} + GameAtExit *Next; - char Command[1]; + FString Command; }; static GameAtExit *ExitCmdList; @@ -551,16 +553,14 @@ CCMD (atexit) GameAtExit *record = ExitCmdList; while (record != NULL) { - Printf ("%s\n", record->Command); + Printf ("%s\n", record->Command.GetChars()); record = record->Next; } return; } for (int i = 1; i < argv.argc(); ++i) { - GameAtExit *record = (GameAtExit *)M_Malloc ( - sizeof(GameAtExit)+strlen(argv[i])); - strcpy (record->Command, argv[i]); + GameAtExit *record = new GameAtExit(argv[i]); record->Next = ExitCmdList; ExitCmdList = record; } @@ -582,8 +582,8 @@ void C_DeinitConsole () while (cmd != NULL) { GameAtExit *next = cmd->Next; - AddCommandString (cmd->Command); - M_Free (cmd); + AddCommandString (cmd->Command.LockBuffer()); + delete cmd; cmd = next; } From 1e497e0b3e1eec847fbc2d17aabd2954b6a358e3 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Fri, 11 Nov 2016 23:55:02 -0600 Subject: [PATCH 074/101] Fixed: FString::StripLeftRight() lost the right character when copying to a new buffer - Also, some minor improvements to the strip functions to avoid doing extra work. --- src/zstring.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/zstring.cpp b/src/zstring.cpp index 63fdf64285..29270b9703 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -635,6 +635,10 @@ void FString::StripLeft () if (!isspace(Chars[i])) break; } + if (i == 0) + { // Nothing to strip. + return; + } if (Data()->RefCount <= 1) { for (j = 0; i <= max; ++j, ++i) @@ -666,6 +670,10 @@ void FString::StripLeft (const char *charset) if (!strchr (charset, Chars[i])) break; } + if (i == 0) + { // Nothing to strip. + return; + } if (Data()->RefCount <= 1) { for (j = 0; i <= max; ++j, ++i) @@ -686,11 +694,16 @@ void FString::StripLeft (const char *charset) void FString::StripRight () { size_t max = Len(), i; - for (i = max; i-- > 0; ) + if (max == 0) return; + for (i = --max; i-- > 0; ) { if (!isspace(Chars[i])) break; } + if (i == max) + { // Nothing to strip. + return; + } if (Data()->RefCount <= 1) { Chars[i+1] = '\0'; @@ -714,11 +727,15 @@ void FString::StripRight (const char *charset) { size_t max = Len(), i; if (max == 0) return; - for (i = max; i-- > 0; ) + for (i = --max; i-- > 0; ) { if (!strchr (charset, Chars[i])) break; } + if (i == max) + { // Nothing to strip. + return; + } if (Data()->RefCount <= 1) { Chars[i+1] = '\0'; @@ -747,6 +764,10 @@ void FString::StripLeftRight () if (!isspace(Chars[j])) break; } + if (i == 0 && j == max - 1) + { // Nothing to strip. + return; + } if (Data()->RefCount <= 1) { for (k = 0; i <= j; ++i, ++k) @@ -759,8 +780,8 @@ void FString::StripLeftRight () else { FStringData *old = Data(); - AllocBuffer (j - i); - StrCopy (Chars, old->Chars(), j - i); + AllocBuffer(j - i + 1); + StrCopy(Chars, old->Chars(), j - i + 1); old->Release(); } } From c69394fa40901ce51c37e411efb6bb3c2d717aba Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 12 Nov 2016 00:30:38 -0600 Subject: [PATCH 075/101] Add con_numnotify cvar to control number of lines of notification text - If con_numnotify < 0, then there is no limit on the number of lines of text. - If con_numnotify == 0, then any text that would normally be shown in the notification area is discarded. - If con_numnotify > 0, then that is the maximum number of lines of notification text to display. --- src/c_console.cpp | 192 ++++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 75 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 2f86228b70..8292624cb3 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -379,14 +379,36 @@ static int HistSize; #define NUMNOTIFIES 4 #define NOTIFYFADETIME 6 -static struct NotifyText +struct FNotifyText { int TimeOut; int PrintLevel; FString Text; -} NotifyStrings[NUMNOTIFIES]; +}; + +struct FNotifyBuffer +{ +public: + FNotifyBuffer(); + void AddString(int printlevel, FString source); + void Shift(int maxlines); + void Clear() { Text.Clear(); } + void Tick(); + void Draw(); + +private: + TArray Text; + int Top; + int TopGoal; + enum { NEWLINE, APPENDLINE, REPLACELINE } AddType; +}; +static FNotifyBuffer NotifyStrings; + +CUSTOM_CVAR(Int, con_numnotify, NUMNOTIFIES, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +{ + NotifyStrings.Shift(con_numnotify); +} -static int NotifyTop, NotifyTopGoal; int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_GOLD }; @@ -394,8 +416,6 @@ static void setmsgcolor (int index, int color); FILE *Logfile = NULL; -void C_AddNotifyString (int printlevel, const char *source); - FIntCVar msglevel ("msg", 0, CVAR_ARCHIVE); @@ -489,7 +509,7 @@ void DequeueConsoleText () TextQueue *next = queued->Next; if (queued->bNotify) { - C_AddNotifyString (queued->PrintLevel, queued->Text); + NotifyStrings.AddString(queued->PrintLevel, queued->Text); } else { @@ -668,22 +688,30 @@ static void setmsgcolor (int index, int color) extern int DisplayWidth; -void C_AddNotifyString (int printlevel, const char *source) +FNotifyBuffer::FNotifyBuffer() { - static enum - { - NEWLINE, - APPENDLINE, - REPLACELINE - } addtype = NEWLINE; + Top = TopGoal = 0; + AddType = NEWLINE; +} +void FNotifyBuffer::Shift(int maxlines) +{ + if (maxlines >= 0 && Text.Size() > (unsigned)maxlines) + { + Text.Delete(0, Text.Size() - maxlines); + } +} + +void FNotifyBuffer::AddString(int printlevel, FString source) +{ FBrokenLines *lines; - int i, len, width; + int i, width; if ((printlevel != 128 && !show_messages) || - !(len = (int)strlen (source)) || + source.IsEmpty() || gamestate == GS_FULLCONSOLE || - gamestate == GS_DEMOSCREEN) + gamestate == GS_DEMOSCREEN || + con_numnotify == 0) return; if (ConsoleDrawing) @@ -701,15 +729,18 @@ void C_AddNotifyString (int printlevel, const char *source) width = DisplayWidth / active_con_scaletext(); } - if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel) + if (AddType == APPENDLINE && Text.Size() > 0 && Text[Text.Size() - 1].PrintLevel == printlevel) { - FString str = NotifyStrings[NUMNOTIFIES-1].Text + source; + FString str = Text[Text.Size() - 1].Text + source; lines = V_BreakLines (SmallFont, width, str); } else { lines = V_BreakLines (SmallFont, width, source); - addtype = (addtype == APPENDLINE) ? NEWLINE : addtype; + if (AddType == APPENDLINE) + { + AddType = NEWLINE; + } } if (lines == NULL) @@ -717,30 +748,37 @@ void C_AddNotifyString (int printlevel, const char *source) for (i = 0; lines[i].Width >= 0; i++) { - if (addtype == NEWLINE) + FNotifyText newline; + + newline.Text = lines[i].Text; + newline.TimeOut = gametic + int(con_notifytime * TICRATE); + newline.PrintLevel = printlevel; + if (AddType == NEWLINE || Text.Size() == 0) { - for (int j = 0; j < NUMNOTIFIES-1; ++j) + if (con_numnotify > 0) { - NotifyStrings[j] = NotifyStrings[j+1]; + Shift(con_numnotify - 1); } + Text.Push(newline); } - NotifyStrings[NUMNOTIFIES-1].Text = lines[i].Text; - NotifyStrings[NUMNOTIFIES-1].TimeOut = gametic + (int)(con_notifytime * TICRATE); - NotifyStrings[NUMNOTIFIES-1].PrintLevel = printlevel; - addtype = NEWLINE; + else + { + Text[Text.Size() - 1] = newline; + } + AddType = NEWLINE; } V_FreeBrokenLines (lines); lines = NULL; - switch (source[len-1]) + switch (source[source.Len()-1]) { - case '\r': addtype = REPLACELINE; break; - case '\n': addtype = NEWLINE; break; - default: addtype = APPENDLINE; break; + case '\r': AddType = REPLACELINE; break; + case '\n': AddType = NEWLINE; break; + default: AddType = APPENDLINE; break; } - NotifyTopGoal = 0; + TopGoal = 0; } void AddToConsole (int printlevel, const char *text) @@ -763,7 +801,7 @@ int PrintString (int printlevel, const char *outline) AddToConsole (printlevel, outline); if (vidactive && screen && SmallFont) { - C_AddNotifyString (printlevel, outline); + NotifyStrings.AddString(printlevel, outline); maybedrawnow (false, false); } } @@ -831,10 +869,7 @@ int DPrintf (int level, const char *format, ...) void C_FlushDisplay () { - int i; - - for (i = 0; i < NUMNOTIFIES; i++) - NotifyStrings[i].TimeOut = 0; + NotifyStrings.Clear(); } void C_AdjustBottom () @@ -853,7 +888,7 @@ void C_NewModeAdjust () } int consoletic = 0; -void C_Ticker () +void C_Ticker() { static int lasttic = 0; consoletic++; @@ -895,28 +930,43 @@ void C_Ticker () } lasttic = consoletic; + NotifyStrings.Tick(); +} - if (NotifyTopGoal > NotifyTop) +void FNotifyBuffer::Tick() +{ + if (TopGoal > Top) { - NotifyTop++; + Top++; } - else if (NotifyTopGoal < NotifyTop) + else if (TopGoal < Top) { - NotifyTop--; + Top--; + } + + // Remove lines from the beginning that have expired. + unsigned i; + for (i = 0; i < Text.Size(); ++i) + { + if (Text[i].TimeOut != 0 && Text[i].TimeOut > gametic) + break; + } + if (i > 0) + { + Text.Delete(0, i); } } -static void C_DrawNotifyText () +void FNotifyBuffer::Draw() { bool center = (con_centernotify != 0.f); - int i, line, lineadv, color, j, skip; + int line, lineadv, color, j; bool canskip; if (gamestate == GS_FULLCONSOLE || gamestate == GS_DEMOSCREEN/* || menuactive != MENU_Off*/) return; - line = NotifyTop; - skip = 0; + line = Top; canskip = true; lineadv = SmallFont->GetHeight (); @@ -927,67 +977,60 @@ static void C_DrawNotifyText () BorderTopRefresh = screen->GetPageCount (); - for (i = 0; i < NUMNOTIFIES; i++) + for (unsigned i = 0; i < Text.Size(); ++ i) { - if (NotifyStrings[i].TimeOut == 0) + FNotifyText ¬ify = Text[i]; + + if (notify.TimeOut == 0) continue; - j = NotifyStrings[i].TimeOut - gametic; + j = notify.TimeOut - gametic; if (j > 0) { - if (!show_messages && NotifyStrings[i].PrintLevel != 128) + if (!show_messages && notify.PrintLevel != 128) continue; - double alpha; + double alpha = (j < NOTIFYFADETIME) ? 1. * j / NOTIFYFADETIME : 1; - if (j < NOTIFYFADETIME) - { - alpha = 1. * j / NOTIFYFADETIME; - } - else - { - alpha = 1; - } - - if (NotifyStrings[i].PrintLevel >= PRINTLEVELS) + if (notify.PrintLevel >= PRINTLEVELS) color = CR_UNTRANSLATED; else - color = PrintColors[NotifyStrings[i].PrintLevel]; + color = PrintColors[notify.PrintLevel]; if (active_con_scaletext() == 0) { if (!center) - screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, + screen->DrawText (SmallFont, color, 0, line, notify.Text, DTA_CleanNoMove, true, DTA_AlphaF, alpha, TAG_DONE); else screen->DrawText (SmallFont, color, (SCREENWIDTH - - SmallFont->StringWidth (NotifyStrings[i].Text)*CleanXfac)/2, - line, NotifyStrings[i].Text, DTA_CleanNoMove, true, + SmallFont->StringWidth (notify.Text)*CleanXfac)/2, + line, notify.Text, DTA_CleanNoMove, true, DTA_AlphaF, alpha, TAG_DONE); } else if (active_con_scaletext() == 1) { if (!center) - screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, + screen->DrawText (SmallFont, color, 0, line, notify.Text, DTA_AlphaF, alpha, TAG_DONE); else screen->DrawText (SmallFont, color, (SCREENWIDTH - - SmallFont->StringWidth (NotifyStrings[i].Text))/2, - line, NotifyStrings[i].Text, + SmallFont->StringWidth (notify.Text))/2, + line, notify.Text, DTA_AlphaF, alpha, TAG_DONE); } else { if (!center) - screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, + screen->DrawText (SmallFont, color, 0, line, notify.Text, DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(), DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(), DTA_KeepRatio, true, DTA_AlphaF, alpha, TAG_DONE); else screen->DrawText (SmallFont, color, (screen->GetWidth() - - SmallFont->StringWidth (NotifyStrings[i].Text) * active_con_scaletext()) / 2 / active_con_scaletext(), - line, NotifyStrings[i].Text, + SmallFont->StringWidth (notify.Text) * active_con_scaletext()) / 2 / active_con_scaletext(), + line, notify.Text, DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(), DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(), DTA_KeepRatio, true, @@ -1000,16 +1043,15 @@ static void C_DrawNotifyText () { if (canskip) { - NotifyTop += lineadv; + Top += lineadv; line += lineadv; - skip++; } - NotifyStrings[i].TimeOut = 0; + notify.TimeOut = 0; } } if (canskip) { - NotifyTop = NotifyTopGoal; + Top = TopGoal; } } @@ -1059,7 +1101,7 @@ void C_DrawConsole (bool hw2d) if (ConsoleState == c_up) { - C_DrawNotifyText (); + NotifyStrings.Draw(); return; } else if (ConBottom) From f123da938575a329f35fd274eae802e74caf3ea9 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 12 Nov 2016 11:07:39 +0100 Subject: [PATCH 076/101] - Fixed GCC warnings with new history code. --- src/c_console.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 8292624cb3..f5265cf409 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -613,7 +613,7 @@ void C_DeinitConsole () while (hist != NULL) { History *next = hist->Newer; - free (hist); + delete hist; hist = next; } HistTail = HistHead = HistPos = NULL; @@ -1659,7 +1659,7 @@ CCMD (history) while (hist) { - Printf (" %s\n", hist->String); + Printf (" %s\n", hist->String.GetChars()); hist = hist->Newer; } } From 104030697ff6c04aa1d4b99b860531bfe6e02a3b Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 12 Nov 2016 11:08:33 +0100 Subject: [PATCH 077/101] - Rename con_numnotify to con_notifylines. Zandronum 1.1 added an option with the same purpose. Use it to avoid duplicates. --- src/c_console.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index f5265cf409..7cde25c57e 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -404,9 +404,9 @@ private: }; static FNotifyBuffer NotifyStrings; -CUSTOM_CVAR(Int, con_numnotify, NUMNOTIFIES, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +CUSTOM_CVAR(Int, con_notifylines, NUMNOTIFIES, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) { - NotifyStrings.Shift(con_numnotify); + NotifyStrings.Shift(self); } @@ -711,7 +711,7 @@ void FNotifyBuffer::AddString(int printlevel, FString source) source.IsEmpty() || gamestate == GS_FULLCONSOLE || gamestate == GS_DEMOSCREEN || - con_numnotify == 0) + con_notifylines == 0) return; if (ConsoleDrawing) @@ -755,9 +755,9 @@ void FNotifyBuffer::AddString(int printlevel, FString source) newline.PrintLevel = printlevel; if (AddType == NEWLINE || Text.Size() == 0) { - if (con_numnotify > 0) + if (con_notifylines > 0) { - Shift(con_numnotify - 1); + Shift(con_notifylines - 1); } Text.Push(newline); } From ffea457d81d6f1f920f02dea5cec7847e28ab1ad Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 12 Nov 2016 11:18:17 +0100 Subject: [PATCH 078/101] - Fixed GCC/Clang warnings with serializer Unicode parser. --- src/serializer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serializer.cpp b/src/serializer.cpp index dec81e86fe..8875b61f99 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -162,7 +162,7 @@ static const char *StringToUnicode(const char *cc, int size = -1) int count = 0; int count1 = 0; out.Clear(); - while (ch = (*c++) & 255) + while ((ch = (*c++) & 255)) { count1++; if (ch >= 128) @@ -180,7 +180,7 @@ static const char *StringToUnicode(const char *cc, int size = -1) out.Last() = 0; c = cc; int i = 0; - while (ch = (*c++) & 255) + while ((ch = (*c++) & 255)) { utf8_encode(ch, &out[i], &count1); i += count1; From 32e0123e1bdf7910849e35ae7c2c82576caa2c88 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 12 Nov 2016 14:01:34 +0100 Subject: [PATCH 079/101] - fixed: FResourceLump::LumpNameSetup passed negative numbers to FString::Truncate for extension-less lump names. --- src/resourcefiles/resourcefile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 912998d9ae..6036063417 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -95,7 +95,8 @@ void FResourceLump::LumpNameSetup(FString iname) { long slash = iname.LastIndexOf('/'); FString base = (slash >= 0) ? iname.Mid(slash + 1) : iname; - base.Truncate(base.LastIndexOf('.')); + auto dot = base.LastIndexOf('.'); + if (dot >= 0) base.Truncate(dot); uppercopy(Name, base); Name[8] = 0; FullName = iname; From 0c0cb6d69c79a5d06498a1b10595587f029bdeb1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 12 Nov 2016 15:36:36 +0100 Subject: [PATCH 080/101] - fixed warnings. --- src/c_console.cpp | 12 ++++++------ src/zstring.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 7cde25c57e..3064abb0d2 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -282,7 +282,7 @@ struct FCommandBuffer void CursorEnd() { - CursorPos = Text.Len(); + CursorPos = (unsigned)Text.Len(); StartPos = 0; MakeStartPosGood(); } @@ -358,7 +358,7 @@ struct FCommandBuffer { Text.Insert(CursorPos, clip); } - CursorPos += clip.Len(); + CursorPos += (unsigned)clip.Len(); MakeStartPosGood(); } } @@ -366,7 +366,7 @@ struct FCommandBuffer void SetString(FString str) { Text = str; - CursorPos = Text.Len(); + CursorPos = (unsigned)Text.Len(); MakeStartPosGood(); } }; @@ -1862,7 +1862,7 @@ static void C_TabComplete (bool goForward) } TabStart = i; - TabSize = CmdLine.Text.Len() - TabStart; + TabSize = (int)CmdLine.Text.Len() - TabStart; if (!FindTabCommand(&CmdLine.Text[TabStart], &TabPos, TabSize)) return; // No initial matches @@ -1922,7 +1922,7 @@ static void C_TabComplete (bool goForward) CmdLine.Text << TabCommands[TabPos].TabName << ' '; } } - CmdLine.CursorPos = CmdLine.Text.Len(); + CmdLine.CursorPos = (unsigned)CmdLine.Text.Len(); CmdLine.MakeStartPosGood(); } @@ -1996,7 +1996,7 @@ static bool C_TabCompleteList () TabSize = commonsize; CmdLine.Text.Truncate(TabStart); CmdLine.Text.AppendCStrPart(TabCommands[TabPos].TabName.GetChars(), commonsize); - CmdLine.CursorPos = CmdLine.Text.Len(); + CmdLine.CursorPos = (unsigned)CmdLine.Text.Len(); } return false; } diff --git a/src/zstring.cpp b/src/zstring.cpp index 29270b9703..b6e5b4b8de 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -397,7 +397,7 @@ void FString::Remove(size_t index, size_t remlen) if (Data()->RefCount == 1) { // Can do this in place memmove(Chars + index, Chars + index + remlen, Len() - index - remlen); - Data()->Len -= remlen; + Data()->Len -= (unsigned)remlen; } else { // Must do it in a copy From 93428983612b8837df0645a280c15493ea67965d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 12 Nov 2016 18:32:09 -0500 Subject: [PATCH 081/101] - Added support for GTK3 (thanks to "MineyMe" and edward-san) - Replaced GTK/OS X (note different from Cocoa) clipboard code with SDL clipboard API. - Removed requirement to link to GTK in order to compile with GTK support. - GTK is no longer init'd if the GTK IWAD picker is not used. - Our usage of GTK is such that the dynamic loader can work with both GTK2 and GTK3 depending on what's installed. - Since we're accumulating a lot of library loaders I've built a generic interface as FModule which replaces TOptWin32Proc and the loaders in the OpenAL and Fluidsynth code. --- src/CMakeLists.txt | 37 ++- src/i_module.cpp | 101 +++++++ src/i_module.h | 229 +++++++++++++++ src/posix/sdl/i_main.cpp | 11 - src/posix/sdl/i_system.cpp | 329 +-------------------- src/posix/unix/iwadpicker_gtk.cpp | 331 ++++++++++++++++++++++ src/sound/i_musicinterns.h | 64 ++--- src/sound/music_fluidsynth_mididevice.cpp | 177 ++++-------- src/sound/oalload.h | 17 +- src/sound/oalsound.cpp | 36 +-- src/win32/i_main.cpp | 23 ++ src/win32/i_specialpaths.cpp | 16 +- src/win32/i_system.cpp | 11 +- src/win32/i_system.h | 24 -- src/win32/optwin32.h | 24 ++ src/win32/win32video.cpp | 9 +- 16 files changed, 857 insertions(+), 582 deletions(-) create mode 100644 src/i_module.cpp create mode 100644 src/i_module.h create mode 100644 src/posix/unix/iwadpicker_gtk.cpp create mode 100644 src/win32/optwin32.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 576da36478..04e6087ead 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -189,6 +189,7 @@ else() set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NO_GTK ON ) + set( DYN_GTK OFF ) # Prevent inclusion of fp.h and FixMath.h from Carbon framework # Declarations from these files are not used but cause the following conflicts: @@ -197,6 +198,7 @@ else() add_definitions( -D__FP__ -D__FIXMATH__ ) else() option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) + option( DYN_GTK "Load GTK+ at runtime instead of compile time" ON ) option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) set( FMOD_SEARCH_PATHS @@ -212,22 +214,37 @@ else() # Use GTK+ for the IWAD picker, if available. if( NOT NO_GTK ) - pkg_check_modules( GTK2 gtk+-2.0 ) - if( GTK2_FOUND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) - include_directories( ${GTK2_INCLUDE_DIRS} ) - link_directories( ${GTK2_LIBRARY_DIRS} ) + pkg_check_modules( GTK3 gtk+-3.0 ) + if( GTK3_FOUND ) + if( NOT DYN_GTK ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK3_LIBRARIES} ) + endif() + include_directories( ${GTK3_INCLUDE_DIRS} ) + link_directories( ${GTK3_LIBRARY_DIRS} ) else() - set( NO_GTK ON ) + pkg_check_modules( GTK2 gtk+-2.0 ) + if( GTK2_FOUND ) + if( NOT DYN_GTK ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) + endif() + include_directories( ${GTK2_INCLUDE_DIRS} ) + link_directories( ${GTK2_LIBRARY_DIRS} ) + else() + set( NO_GTK ON ) + endif() endif() endif() endif() set( NASM_NAMES nasm ) if( NO_GTK ) - add_definitions( -DNO_GTK=1 ) + add_definitions( -DNO_GTK ) + elseif( DYN_GTK ) + add_definitions( -DDYN_GTK=1 ) + else() + add_definitions( -DDYN_GTK=0 ) endif() - + # Non-Windows version also needs SDL except native OS X backend if( NOT APPLE OR NOT OSX_COCOA_BACKEND ) find_package( SDL2 REQUIRED ) @@ -688,7 +705,8 @@ set( PLAT_SDL_SOURCES posix/sdl/sdlvideo.cpp posix/sdl/st_start.cpp ) set( PLAT_UNIX_SOURCES - posix/unix/i_specialpaths.cpp ) + posix/unix/i_specialpaths.cpp + posix/unix/iwadpicker_gtk.cpp ) set( PLAT_OSX_SOURCES posix/osx/iwadpicker_cocoa.mm posix/osx/i_specialpaths.mm @@ -1078,6 +1096,7 @@ set (PCH_SOURCES gi.cpp gitinfo.cpp hu_scores.cpp + i_module.cpp i_net.cpp info.cpp keysections.cpp diff --git a/src/i_module.cpp b/src/i_module.cpp new file mode 100644 index 0000000000..1ed40310fa --- /dev/null +++ b/src/i_module.cpp @@ -0,0 +1,101 @@ +/* +** i_module.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2016 Braden Obrzut +** 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_module.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#else +#include +#endif + +#ifndef _WIN32 +#define LoadLibrary(x) dlopen((x), RTLD_LAZY) +#define GetProcAddress(a,b) dlsym((a),(b)) +#define FreeLibrary(x) dlclose((x)) +using HMODULE = void*; +#endif + +bool FModule::Load(std::initializer_list libnames) +{ + for(auto lib : libnames) + { + if(!Open(lib)) + continue; + + StaticProc *proc; + for(proc = reqSymbols;proc;proc = proc->Next) + { + if(!(proc->Call = GetSym(proc->Name)) && !proc->Optional) + { + Unload(); + break; + } + } + + if(IsLoaded()) + return true; + } + + return false; +} + +void FModule::Unload() +{ + if(handle) + { + FreeLibrary((HMODULE)handle); + handle = nullptr; + } +} + +bool FModule::Open(const char* lib) +{ +#ifdef _WIN32 + if((handle = GetModuleHandle(lib)) != nullptr) + return true; +#else + // Loading an empty string in Linux doesn't do what we expect it to. + if(*lib == '\0') + return false; +#endif + handle = LoadLibrary(lib); + return handle != nullptr; +} + +void *FModule::GetSym(const char* name) +{ + return GetProcAddress((HMODULE)handle, name); +} diff --git a/src/i_module.h b/src/i_module.h new file mode 100644 index 0000000000..9690d8c2f8 --- /dev/null +++ b/src/i_module.h @@ -0,0 +1,229 @@ +/* +** i_module.h +** +**--------------------------------------------------------------------------- +** Copyright 2016 Braden Obrzut +** 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. +**--------------------------------------------------------------------------- +** +*/ + +#pragma once + +#include +#include + +/* FModule Run Time Library Loader + * + * This provides an interface for loading optional dependencies or detecting + * version specific symbols at run time. These classes largely provide an + * interface for statically declaring the symbols that are going to be used + * ahead of time, thus should not be used on the stack or as part of a + * dynamically allocated object. The procedure templates take the FModule + * as a template argument largely to make such use of FModule awkward. + * + * Declared procedures register themselves with FModule and the module will not + * be considered loaded unless all required procedures can be resolved. In + * order to remove the need for boilerplate code, optional procedures do not + * enforce the requirement that the value is null checked before use. As a + * debugging aid debug builds will check that operator bool was called at some + * point, but this is just a first order sanity check. + */ + +class FModule; +class FStaticModule; + +template +class TOptProc; + +template +class TReqProc; + +template +class TStaticProc; + +class FModule +{ + template + friend class TOptProc; + template + friend class TReqProc; + + struct StaticProc + { + void *Call; + const char* Name; + StaticProc *Next; + bool Optional; + }; + + void RegisterStatic(StaticProc &proc) + { + proc.Next = reqSymbols; + reqSymbols = &proc; + } + + void *handle = nullptr; + + // Debugging aid + const char *name; + + // Since FModule is supposed to be statically allocated it is assumed that + // reqSymbols will be initialized to nullptr avoiding initialization order + // problems with declaring procedures. + StaticProc *reqSymbols; + + bool Open(const char* lib); + void *GetSym(const char* name); + +public: + template + using Opt = TOptProc; + template + using Req = TReqProc; + + FModule(const char* name) : name(name) {}; + ~FModule() { Unload(); } + + // Load a shared library using the first library name which satisfies all + // of the required symbols. + bool Load(std::initializer_list libnames); + void Unload(); + + bool IsLoaded() const { return handle != nullptr; } +}; + +// Null version of FModule which satisfies the API so the same code can be used +// for run time and compile time linking. +class FStaticModule +{ + template + friend class TStaticProc; + + const char *name; +public: + template + using Opt = TStaticProc; + template + using Req = TStaticProc; + + FStaticModule(const char* name) : name(name) {}; + + bool Load(std::initializer_list libnames) { return true; } + void Unload() {} + + bool IsLoaded() const { return true; } +}; + +// Allow FModuleMaybe to switch based on preprocessor flag. +// Use FModuleMaybe::Opt and FModuleMaybe::Req for procs. +template +struct TModuleType { using Type = FModule; }; +template<> +struct TModuleType { using Type = FStaticModule; }; + +template +using FModuleMaybe = typename TModuleType::Type; + +// ------------------------------------------------------------------------ + +template +class TOptProc +{ + FModule::StaticProc proc; +#ifndef NDEBUG + mutable bool checked = false; +#endif + + // I am not a pointer + bool operator==(void*) const; + bool operator!=(void*) const; + +public: + TOptProc(const char* function) + { + proc.Name = function; + proc.Optional = true; + Module.RegisterStatic(proc); + } + + operator Proto() const + { +#ifndef NDEBUG + assert(checked); +#endif + return (Proto)proc.Call; + } + explicit operator bool() const + { +#ifndef NDEBUG + assert(Module.IsLoaded()); + checked = true; +#endif + return proc.Call != nullptr; + } +}; + +template +class TReqProc +{ + FModule::StaticProc proc; + + // I am not a pointer + bool operator==(void*) const; + bool operator!=(void*) const; + +public: + TReqProc(const char* function) + { + proc.Name = function; + proc.Optional = false; + Module.RegisterStatic(proc); + } + + operator Proto() const + { +#ifndef NDEBUG + assert(Module.IsLoaded()); +#endif + return (Proto)proc.Call; + } + explicit operator bool() const { return true; } +}; + +template +class TStaticProc +{ + // I am not a pointer + bool operator==(void*) const; + bool operator!=(void*) const; + +public: + TStaticProc(const char* function) {} + + operator Proto() const { return Sym; } + explicit operator bool() const { return Sym != nullptr; } +}; diff --git a/src/posix/sdl/i_main.cpp b/src/posix/sdl/i_main.cpp index 41497afe34..cb9ed58722 100644 --- a/src/posix/sdl/i_main.cpp +++ b/src/posix/sdl/i_main.cpp @@ -40,9 +40,6 @@ #include #include #include -#ifndef NO_GTK -#include -#endif #include #if defined(__MACH__) && !defined(NOASM) #include @@ -87,10 +84,6 @@ void Mac_I_FatalError(const char* errortext); // PUBLIC DATA DEFINITIONS ------------------------------------------------- -#ifndef NO_GTK -bool GtkAvailable; -#endif - // The command line arguments. DArgs *Args; @@ -259,10 +252,6 @@ int main (int argc, char **argv) // Note that the LANG environment variable is overridden by LC_* setenv ("LC_NUMERIC", "C", 1); -#ifndef NO_GTK - GtkAvailable = gtk_init_check (&argc, &argv); -#endif - setlocale (LC_ALL, "C"); if (SDL_Init (0) < 0) diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index dcefcdbad6..8e4e63c4fc 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -34,10 +34,8 @@ #include #include #include -#ifndef NO_GTK -#include -#include -#endif + +#include #include "doomerrors.h" #include @@ -71,10 +69,6 @@ #include "m_fixed.h" #include "g_level.h" -#ifdef __APPLE__ -#include -#endif // __APPLE__ - EXTERN_CVAR (String, language) extern "C" @@ -84,7 +78,8 @@ extern "C" } #ifndef NO_GTK -extern bool GtkAvailable; +bool I_GtkAvailable (); +int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad); #elif defined(__APPLE__) int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad); #endif @@ -262,183 +257,6 @@ void I_PrintStr (const char *cp) fflush (stdout); } -#ifndef NO_GTK -// GtkTreeViews eats return keys. I want this to be like a Windows listbox -// where pressing Return can still activate the default button. -gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data) -{ - if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Return) - { - gtk_window_activate_default (GTK_WINDOW(func_data)); - } - return FALSE; -} - -// Double-clicking an entry in the list is the same as pressing OK. -gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data) -{ - if (event->type == GDK_2BUTTON_PRESS) - { - *(int *)func_data = 1; - gtk_main_quit(); - } - return FALSE; -} - -// When the user presses escape, that should be the same as canceling the dialog. -gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data) -{ - if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape) - { - gtk_main_quit(); - } - return FALSE; -} - -void ClickedOK(GtkButton *button, gpointer func_data) -{ - *(int *)func_data = 1; - gtk_main_quit(); -} - -EXTERN_CVAR (Bool, queryiwad); - -int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) -{ - GtkWidget *window; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *bbox; - GtkWidget *widget; - GtkWidget *tree; - GtkWidget *check; - GtkListStore *store; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GtkTreeSelection *selection; - GtkTreeIter iter, defiter; - int close_style = 0; - int i; - char caption[100]; - - // Create the dialog window. - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - mysnprintf(caption, countof(caption), GAMESIG " %s: Select an IWAD to use", GetVersionString()); - gtk_window_set_title (GTK_WINDOW(window), caption); - gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_container_set_border_width (GTK_CONTAINER(window), 10); - g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL); - g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL); - - // Create the vbox container. - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER(window), vbox); - - // Create the top label. - widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"); - gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); - gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); - - // Create a list store with all the found IWADs. - store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); - for (i = 0; i < numwads; ++i) - { - const char *filepart = strrchr (wads[i].Path, '/'); - if (filepart == NULL) - filepart = wads[i].Path; - else - filepart++; - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - 0, filepart, - 1, wads[i].Name.GetChars(), - 2, i, - -1); - if (i == defaultiwad) - { - defiter = iter; - } - } - - // Create the tree view control to show the list. - tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)); - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); - gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0); - g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style); - g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window); - - // Select the default IWAD. - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree)); - gtk_tree_selection_select_iter (selection, &defiter); - - // Create the hbox for the bottom row. - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0); - - // Create the "Don't ask" checkbox. - check = gtk_check_button_new_with_label ("Don't ask me this again"); - gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check), !showwin); - - // Create the OK/Cancel button box. - bbox = gtk_hbutton_box_new (); - gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_set_spacing (GTK_BOX(bbox), 10); - gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0); - - // Create the OK button. - widget = gtk_button_new_from_stock (GTK_STOCK_OK); - gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); - GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT); - gtk_widget_grab_default (widget); - g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style); - g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style); - - // Create the cancel button. - widget = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); - g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window); - - // Finally we can show everything. - gtk_widget_show_all (window); - - gtk_main (); - - if (close_style == 1) - { - GtkTreeModel *model; - GValue value = { 0, { {0} } }; - - // Find out which IWAD was selected. - gtk_tree_selection_get_selected (selection, &model, &iter); - gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value); - i = g_value_get_int (&value); - g_value_unset (&value); - - // Set state of queryiwad based on the checkbox. - queryiwad = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check)); - } - else - { - i = -1; - } - - if (GTK_IS_WINDOW(window)) - { - gtk_widget_destroy (window); - // If we don't do this, then the X window might not actually disappear. - while (g_main_context_iteration (NULL, FALSE)) {} - } - - return i; -} -#endif - int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { int i; @@ -448,7 +266,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) return defaultiwad; } -#if !defined(__APPLE__) +#ifndef __APPLE__ const char *str; if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) { @@ -500,12 +318,15 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) } } #endif + #ifndef NO_GTK - if (GtkAvailable) + if (I_GtkAvailable()) { return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad); } -#elif defined(__APPLE__) +#endif + +#ifdef __APPLE__ return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad); #endif @@ -605,139 +426,19 @@ int I_FindAttr (findstate_t *fileinfo) return 0; } -#ifdef __APPLE__ -static PasteboardRef s_clipboard; - -static CFDataRef GetPasteboardData(const PasteboardItemID itemID, const CFStringRef flavorType) -{ - CFDataRef data = NULL; - - const OSStatus result = PasteboardCopyItemFlavorData(s_clipboard, itemID, flavorType, &data); - - return noErr == result ? data : NULL; -} -#endif // __APPLE__ - -// Clipboard support requires GTK+ -// TODO: GTK+ uses UTF-8. We don't, so some conversions would be appropriate. void I_PutInClipboard (const char *str) { -#ifndef NO_GTK - if (GtkAvailable) - { - GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - if (clipboard != NULL) - { - gtk_clipboard_set_text(clipboard, str, -1); - } - /* Should I? I don't know. It's not actually a selection. - clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); - if (clipboard != NULL) - { - gtk_clipboard_set_text(clipboard, str, -1); - } - */ - } -#elif defined __APPLE__ - if (NULL == s_clipboard) - { - PasteboardCreate(kPasteboardClipboard, &s_clipboard); - } - - PasteboardClear(s_clipboard); - PasteboardSynchronize(s_clipboard); - - const CFDataRef textData = CFDataCreate(kCFAllocatorDefault, - reinterpret_cast(str), strlen(str)); - - if (NULL != textData) - { - PasteboardPutItemFlavor(s_clipboard, PasteboardItemID(1), - CFSTR("public.utf8-plain-text"), textData, 0); - } -#endif + SDL_SetClipboardText(str); } FString I_GetFromClipboard (bool use_primary_selection) { -#ifndef NO_GTK - if (GtkAvailable) + if(char *ret = SDL_GetClipboardText()) { - GtkClipboard *clipboard = gtk_clipboard_get(use_primary_selection ? - GDK_SELECTION_PRIMARY : GDK_SELECTION_CLIPBOARD); - if (clipboard != NULL) - { - gchar *text = gtk_clipboard_wait_for_text(clipboard); - if (text != NULL) - { - FString copy(text); - g_free(text); - return copy; - } - } + FString text(ret); + SDL_free(ret); + return text; } -#elif defined __APPLE__ - FString result; - - if (NULL == s_clipboard) - { - PasteboardCreate(kPasteboardClipboard, &s_clipboard); - } - - PasteboardSynchronize(s_clipboard); - - ItemCount itemCount = 0; - PasteboardGetItemCount(s_clipboard, &itemCount); - - if (0 == itemCount) - { - return FString(); - } - - PasteboardItemID itemID; - - if (0 != PasteboardGetItemIdentifier(s_clipboard, 1, &itemID)) - { - return FString(); - } - - if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF8PlainText)) - { - const CFIndex bufferLength = CFDataGetLength(data); - char* const buffer = result.LockNewBuffer(bufferLength); - - memcpy(buffer, CFDataGetBytePtr(data), bufferLength); - - result.UnlockBuffer(); - } - else if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF16PlainText)) - { -#ifdef __LITTLE_ENDIAN__ - static const CFStringEncoding ENCODING = kCFStringEncodingUTF16LE; -#else // __BIG_ENDIAN__ - static const CFStringEncoding ENCODING = kCFStringEncodingUTF16BE; -#endif // __LITTLE_ENDIAN__ - - if (const CFStringRef utf16 = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, ENCODING)) - { - const CFRange range = { 0, CFStringGetLength(utf16) }; - CFIndex bufferLength = 0; - - if (CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &bufferLength) > 0) - { - UInt8* const buffer = reinterpret_cast(result.LockNewBuffer(bufferLength)); - - CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, buffer, bufferLength, NULL); - - result.UnlockBuffer(); - } - - CFRelease(utf16); - } - } - - return result; -#endif return ""; } diff --git a/src/posix/unix/iwadpicker_gtk.cpp b/src/posix/unix/iwadpicker_gtk.cpp new file mode 100644 index 0000000000..f5fd393b94 --- /dev/null +++ b/src/posix/unix/iwadpicker_gtk.cpp @@ -0,0 +1,331 @@ +#ifndef NO_GTK + +#if !DYN_GTK +// Function addresses will never be NULL, but that's because we're using the +// same code for both dynamic and static. +#pragma GCC diagnostic ignored "-Waddress" +#endif + +#include +#if GTK_MAJOR_VERSION >= 3 +#include +#else +#include +#endif + +#include "c_cvars.h" +#include "d_main.h" +#include "i_module.h" +#include "i_system.h" +#include "version.h" + +EXTERN_CVAR (Bool, queryiwad); + +namespace Gtk { + +FModuleMaybe GtkModule{"GTK"}; +static int GtkAvailable = -1; + +#define DYN_GTK_SYM(x) const FModuleMaybe::Req x{#x}; +#define DYN_GTK_REQ_SYM(x, proto) const FModuleMaybe::Req x{#x}; +#if GTK_MAJOR_VERSION >= 3 +#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#else +#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#endif + +DYN_GTK_SYM(g_main_context_iteration); +DYN_GTK_SYM(g_signal_connect_data); +DYN_GTK_SYM(g_type_check_instance_cast); +DYN_GTK_SYM(g_type_check_instance_is_a); +DYN_GTK_SYM(g_value_get_int); +DYN_GTK_SYM(g_value_unset); +DYN_GTK_SYM(gtk_box_get_type); +DYN_GTK_SYM(gtk_box_pack_end); +DYN_GTK_SYM(gtk_box_pack_start); +DYN_GTK_SYM(gtk_box_set_spacing); +DYN_GTK_SYM(gtk_button_box_get_type); +DYN_GTK_SYM(gtk_button_box_set_layout); +DYN_GTK_SYM(gtk_button_new_with_label); +DYN_GTK_SYM(gtk_cell_renderer_text_new); +DYN_GTK_SYM(gtk_check_button_new_with_label); +DYN_GTK_SYM(gtk_container_add); +DYN_GTK_SYM(gtk_container_get_type); +DYN_GTK_SYM(gtk_container_set_border_width); +DYN_GTK_SYM(gtk_init_check); +DYN_GTK_SYM(gtk_label_new); +DYN_GTK_SYM(gtk_list_store_append); +DYN_GTK_SYM(gtk_list_store_new); +DYN_GTK_SYM(gtk_list_store_set); +DYN_GTK_SYM(gtk_toggle_button_get_type); +DYN_GTK_SYM(gtk_toggle_button_set_active); +DYN_GTK_SYM(gtk_tree_model_get_type); +DYN_GTK_SYM(gtk_tree_model_get_value); +DYN_GTK_SYM(gtk_tree_selection_get_selected); +DYN_GTK_SYM(gtk_tree_selection_select_iter); +DYN_GTK_SYM(gtk_tree_view_append_column); +// Explicitly give the type so that attributes don't cause a warning. +DYN_GTK_REQ_SYM(gtk_tree_view_column_new_with_attributes, GtkTreeViewColumn *(*)(const gchar *, GtkCellRenderer *, ...)); +DYN_GTK_SYM(gtk_toggle_button_get_active); +DYN_GTK_SYM(gtk_tree_view_get_selection); +DYN_GTK_SYM(gtk_tree_view_get_type); +DYN_GTK_SYM(gtk_tree_view_new_with_model); +DYN_GTK_SYM(gtk_main); +DYN_GTK_SYM(gtk_main_quit); +DYN_GTK_SYM(gtk_widget_destroy); +DYN_GTK_SYM(gtk_widget_grab_default); +DYN_GTK_SYM(gtk_widget_get_type); +DYN_GTK_SYM(gtk_widget_set_can_default); +DYN_GTK_SYM(gtk_widget_show_all); +DYN_GTK_SYM(gtk_window_activate_default); +DYN_GTK_SYM(gtk_window_get_type); +DYN_GTK_SYM(gtk_window_new); +DYN_GTK_SYM(gtk_window_set_gravity); +DYN_GTK_SYM(gtk_window_set_position); +DYN_GTK_SYM(gtk_window_set_title); + +// Gtk3 Only +DYN_GTK_OPT3_SYM(gtk_box_new, GtkWidget *(*)(GtkOrientation, gint)); +DYN_GTK_OPT3_SYM(gtk_button_box_new, GtkWidget *(*)(GtkOrientation)); +DYN_GTK_OPT3_SYM(gtk_widget_set_halign, void(*)(GtkWidget *, GtkAlign)); +DYN_GTK_OPT3_SYM(gtk_widget_set_valign, void(*)(GtkWidget *, GtkAlign)); + +// Gtk2 Only +DYN_GTK_OPT2_SYM(gtk_misc_get_type, GType(*)()); +DYN_GTK_OPT2_SYM(gtk_hbox_new, GtkWidget *(*)(gboolean, gint)); +DYN_GTK_OPT2_SYM(gtk_hbutton_box_new, GtkWidget *(*)()); +DYN_GTK_OPT2_SYM(gtk_misc_set_alignment, void(*)(GtkMisc *, gfloat, gfloat)); +DYN_GTK_OPT2_SYM(gtk_vbox_new, GtkWidget *(*)(gboolean, gint)); + +#undef DYN_GTK_SYM +#undef DYN_GTK_REQ_SYM +#undef DYN_GTK_OPT2_SYM +#undef DYN_GTK_OPT3_SYM + +// GtkTreeViews eats return keys. I want this to be like a Windows listbox +// where pressing Return can still activate the default button. +static gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Return) + { + gtk_window_activate_default (GTK_WINDOW(func_data)); + } + return FALSE; +} + +// Double-clicking an entry in the list is the same as pressing OK. +static gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + *(int *)func_data = 1; + gtk_main_quit(); + } + return FALSE; +} + +// When the user presses escape, that should be the same as canceling the dialog. +static gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Escape) + { + gtk_main_quit(); + } + return FALSE; +} + +static void ClickedOK(GtkButton *button, gpointer func_data) +{ + *(int *)func_data = 1; + gtk_main_quit(); +} + +static int PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) +{ + GtkWidget *window; + GtkWidget *vbox = nullptr; + GtkWidget *hbox = nullptr; + GtkWidget *bbox = nullptr; + GtkWidget *widget; + GtkWidget *tree; + GtkWidget *check; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + GtkTreeIter iter, defiter; + int close_style = 0; + int i; + char caption[100]; + + // Create the dialog window. + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + mysnprintf(caption, countof(caption), GAMESIG " %s: Select an IWAD to use", GetVersionString()); + gtk_window_set_title (GTK_WINDOW(window), caption); + gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_gravity (GTK_WINDOW(window), GDK_GRAVITY_CENTER); + gtk_container_set_border_width (GTK_CONTAINER(window), 10); + g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL); + + // Create the vbox container. + if (gtk_box_new) // Gtk3 + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); + else if (gtk_vbox_new) // Gtk2 + vbox = gtk_vbox_new (FALSE, 10); + + gtk_container_add (GTK_CONTAINER(window), vbox); + + // Create the top label. + widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"); + gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); + + if (gtk_widget_set_halign && gtk_widget_set_valign) // Gtk3 + { + gtk_widget_set_halign (widget, GTK_ALIGN_START); + gtk_widget_set_valign (widget, GTK_ALIGN_START); + } + else if (gtk_misc_set_alignment && gtk_misc_get_type) // Gtk2 + gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); + + // Create a list store with all the found IWADs. + store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); + for (i = 0; i < numwads; ++i) + { + const char *filepart = strrchr (wads[i].Path, '/'); + if (filepart == NULL) + filepart = wads[i].Path; + else + filepart++; + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, filepart, + 1, wads[i].Name.GetChars(), + 2, i, + -1); + if (i == defaultiwad) + { + defiter = iter; + } + } + + // Create the tree view control to show the list. + tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); + gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0); + g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style); + g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window); + + // Select the default IWAD. + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree)); + gtk_tree_selection_select_iter (selection, &defiter); + + // Create the hbox for the bottom row. + if (gtk_box_new) // Gtk3 + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + else if (gtk_hbox_new) // Gtk2 + hbox = gtk_hbox_new (FALSE, 0); + + gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0); + + // Create the "Don't ask" checkbox. + check = gtk_check_button_new_with_label ("Don't ask me this again"); + gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check), !showwin); + + // Create the OK/Cancel button box. + if (gtk_button_box_new) // Gtk3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + else if (gtk_hbutton_box_new) // Gtk2 + bbox = gtk_hbutton_box_new (); + + gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing (GTK_BOX(bbox), 10); + gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0); + + // Create the OK button. + widget = gtk_button_new_with_label ("OK"); + + gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); + + gtk_widget_set_can_default (widget, true); + + gtk_widget_grab_default (widget); + g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style); + g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style); + + // Create the cancel button. + widget = gtk_button_new_with_label ("Cancel"); + + gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); + g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window); + + // Finally we can show everything. + gtk_widget_show_all (window); + + gtk_main (); + + if (close_style == 1) + { + GtkTreeModel *model; + GValue value = { 0, { {0} } }; + + // Find out which IWAD was selected. + gtk_tree_selection_get_selected (selection, &model, &iter); + gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value); + i = g_value_get_int (&value); + g_value_unset (&value); + + // Set state of queryiwad based on the checkbox. + queryiwad = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check)); + } + else + { + i = -1; + } + + if (GTK_IS_WINDOW(window)) + { + gtk_widget_destroy (window); + // If we don't do this, then the X window might not actually disappear. + while (g_main_context_iteration (NULL, FALSE)) {} + } + + return i; +} + +} // namespace Gtk + +int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) +{ + return Gtk::PickIWad (wads, numwads, showwin, defaultiwad); +} + +bool I_GtkAvailable() +{ + using namespace Gtk; + + if(GtkAvailable < 0) + { + if (!GtkModule.Load({"libgtk-3.so.0", "libgtk-x11-2.0.so.0"})) + { + GtkAvailable = 0; + return false; + } + + int argc = 0; + char **argv = nullptr; + GtkAvailable = Gtk::gtk_init_check (&argc, &argv); + } + + return GtkAvailable != 0; +} + +#endif diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 861d94927e..a86429e973 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -359,6 +359,9 @@ protected: #ifndef DYN_FLUIDSYNTH #include #else +#include "i_module.h" +extern FModule FluidSynthModule; + struct fluid_settings_t; struct fluid_synth_t; #endif @@ -386,40 +389,35 @@ protected: #ifdef DYN_FLUIDSYNTH enum { FLUID_FAILED = -1, FLUID_OK = 0 }; - fluid_settings_t *(*new_fluid_settings)(); - fluid_synth_t *(*new_fluid_synth)(fluid_settings_t *); - int (*delete_fluid_synth)(fluid_synth_t *); - void (*delete_fluid_settings)(fluid_settings_t *); - int (*fluid_settings_setnum)(fluid_settings_t *, const char *, double); - int (*fluid_settings_setstr)(fluid_settings_t *, const char *, const char *); - int (*fluid_settings_setint)(fluid_settings_t *, const char *, int); - int (*fluid_settings_getstr)(fluid_settings_t *, const char *, char **); - int (*fluid_settings_getint)(fluid_settings_t *, const char *, int *); - void (*fluid_synth_set_reverb_on)(fluid_synth_t *, int); - void (*fluid_synth_set_chorus_on)(fluid_synth_t *, int); - int (*fluid_synth_set_interp_method)(fluid_synth_t *, int, int); - int (*fluid_synth_set_polyphony)(fluid_synth_t *, int); - int (*fluid_synth_get_polyphony)(fluid_synth_t *); - int (*fluid_synth_get_active_voice_count)(fluid_synth_t *); - double (*fluid_synth_get_cpu_load)(fluid_synth_t *); - int (*fluid_synth_system_reset)(fluid_synth_t *); - int (*fluid_synth_noteon)(fluid_synth_t *, int, int, int); - int (*fluid_synth_noteoff)(fluid_synth_t *, int, int); - int (*fluid_synth_cc)(fluid_synth_t *, int, int, int); - int (*fluid_synth_program_change)(fluid_synth_t *, int, int); - int (*fluid_synth_channel_pressure)(fluid_synth_t *, int, int); - int (*fluid_synth_pitch_bend)(fluid_synth_t *, int, int); - int (*fluid_synth_write_float)(fluid_synth_t *, int, void *, int, int, void *, int, int); - int (*fluid_synth_sfload)(fluid_synth_t *, const char *, int); - void (*fluid_synth_set_reverb)(fluid_synth_t *, double, double, double, double); - void (*fluid_synth_set_chorus)(fluid_synth_t *, int, double, double, double, int); - int (*fluid_synth_sysex)(fluid_synth_t *, const char *, int, char *, int *, int *, int); + static TReqProc new_fluid_settings; + static TReqProc new_fluid_synth; + static TReqProc delete_fluid_synth; + static TReqProc delete_fluid_settings; + static TReqProc fluid_settings_setnum; + static TReqProc fluid_settings_setstr; + static TReqProc fluid_settings_setint; + static TReqProc fluid_settings_getstr; + static TReqProc fluid_settings_getint; + static TReqProc fluid_synth_set_reverb_on; + static TReqProc fluid_synth_set_chorus_on; + static TReqProc fluid_synth_set_interp_method; + static TReqProc fluid_synth_set_polyphony; + static TReqProc fluid_synth_get_polyphony; + static TReqProc fluid_synth_get_active_voice_count; + static TReqProc fluid_synth_get_cpu_load; + static TReqProc fluid_synth_system_reset; + static TReqProc fluid_synth_noteon; + static TReqProc fluid_synth_noteoff; + static TReqProc fluid_synth_cc; + static TReqProc fluid_synth_program_change; + static TReqProc fluid_synth_channel_pressure; + static TReqProc fluid_synth_pitch_bend; + static TReqProc fluid_synth_write_float; + static TReqProc fluid_synth_sfload; + static TReqProc fluid_synth_set_reverb; + static TReqProc fluid_synth_set_chorus; + static TReqProc fluid_synth_sysex; -#ifdef _WIN32 - HMODULE FluidSynthDLL; -#else - void *FluidSynthSO; -#endif bool LoadFluidSynth(); void UnloadFluidSynth(); #endif diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index fd0bab645f..bbd6536bc8 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -60,9 +60,9 @@ #include #ifdef __APPLE__ -#define FLUIDSYNTHLIB "libfluidsynth.1.dylib" +#define FLUIDSYNTHLIB1 "libfluidsynth.1.dylib" #else // !__APPLE__ -#define FLUIDSYNTHLIB "libfluidsynth.so.1" +#define FLUIDSYNTHLIB1 "libfluidsynth.so.1" #endif // __APPLE__ #endif @@ -644,12 +644,6 @@ FString FluidSynthMIDIDevice::GetStats() #ifdef DYN_FLUIDSYNTH -struct LibFunc -{ - void **FuncPointer; - const char *FuncName; -}; - //========================================================================== // // FluidSynthMIDIDevice :: LoadFluidSynth @@ -658,124 +652,65 @@ struct LibFunc // //========================================================================== +FModuleMaybe FluidSynthModule{"FluidSynth"}; + +#define DYN_FLUID_SYM(x) decltype(FluidSynthMIDIDevice::x) FluidSynthMIDIDevice::x{#x} +DYN_FLUID_SYM(new_fluid_settings); +DYN_FLUID_SYM(new_fluid_synth); +DYN_FLUID_SYM(delete_fluid_synth); +DYN_FLUID_SYM(delete_fluid_settings); +DYN_FLUID_SYM(fluid_settings_setnum); +DYN_FLUID_SYM(fluid_settings_setstr); +DYN_FLUID_SYM(fluid_settings_setint); +DYN_FLUID_SYM(fluid_settings_getstr); +DYN_FLUID_SYM(fluid_settings_getint); +DYN_FLUID_SYM(fluid_synth_set_reverb_on); +DYN_FLUID_SYM(fluid_synth_set_chorus_on); +DYN_FLUID_SYM(fluid_synth_set_interp_method); +DYN_FLUID_SYM(fluid_synth_set_polyphony); +DYN_FLUID_SYM(fluid_synth_get_polyphony); +DYN_FLUID_SYM(fluid_synth_get_active_voice_count); +DYN_FLUID_SYM(fluid_synth_get_cpu_load); +DYN_FLUID_SYM(fluid_synth_system_reset); +DYN_FLUID_SYM(fluid_synth_noteon); +DYN_FLUID_SYM(fluid_synth_noteoff); +DYN_FLUID_SYM(fluid_synth_cc); +DYN_FLUID_SYM(fluid_synth_program_change); +DYN_FLUID_SYM(fluid_synth_channel_pressure); +DYN_FLUID_SYM(fluid_synth_pitch_bend); +DYN_FLUID_SYM(fluid_synth_write_float); +DYN_FLUID_SYM(fluid_synth_sfload); +DYN_FLUID_SYM(fluid_synth_set_reverb); +DYN_FLUID_SYM(fluid_synth_set_chorus); +DYN_FLUID_SYM(fluid_synth_sysex); + bool FluidSynthMIDIDevice::LoadFluidSynth() { - LibFunc imports[] = - { - { (void **)&new_fluid_settings, "new_fluid_settings" }, - { (void **)&new_fluid_synth, "new_fluid_synth" }, - { (void **)&delete_fluid_synth, "delete_fluid_synth" }, - { (void **)&delete_fluid_settings, "delete_fluid_settings" }, - { (void **)&fluid_settings_setnum, "fluid_settings_setnum" }, - { (void **)&fluid_settings_setstr, "fluid_settings_setstr" }, - { (void **)&fluid_settings_setint, "fluid_settings_setint" }, - { (void **)&fluid_settings_getstr, "fluid_settings_getstr" }, - { (void **)&fluid_settings_getint, "fluid_settings_getint" }, - { (void **)&fluid_synth_set_reverb_on, "fluid_synth_set_reverb_on" }, - { (void **)&fluid_synth_set_chorus_on, "fluid_synth_set_chorus_on" }, - { (void **)&fluid_synth_set_interp_method, "fluid_synth_set_interp_method" }, - { (void **)&fluid_synth_set_polyphony, "fluid_synth_set_polyphony" }, - { (void **)&fluid_synth_get_polyphony, "fluid_synth_get_polyphony" }, - { (void **)&fluid_synth_get_active_voice_count, "fluid_synth_get_active_voice_count" }, - { (void **)&fluid_synth_get_cpu_load, "fluid_synth_get_cpu_load" }, - { (void **)&fluid_synth_system_reset, "fluid_synth_system_reset" }, - { (void **)&fluid_synth_noteon, "fluid_synth_noteon" }, - { (void **)&fluid_synth_noteoff, "fluid_synth_noteoff" }, - { (void **)&fluid_synth_cc, "fluid_synth_cc" }, - { (void **)&fluid_synth_program_change, "fluid_synth_program_change" }, - { (void **)&fluid_synth_channel_pressure, "fluid_synth_channel_pressure" }, - { (void **)&fluid_synth_pitch_bend, "fluid_synth_pitch_bend" }, - { (void **)&fluid_synth_write_float, "fluid_synth_write_float" }, - { (void **)&fluid_synth_sfload, "fluid_synth_sfload" }, - { (void **)&fluid_synth_set_reverb, "fluid_synth_set_reverb" }, - { (void **)&fluid_synth_set_chorus, "fluid_synth_set_chorus" }, - { (void **)&fluid_synth_sysex, "fluid_synth_sysex" }, - }; - int fail = 0; - const char *libname; - -#ifdef _WIN32 if (strlen(fluid_lib) > 0) { - FluidSynthDLL = LoadLibrary(libname = fluid_lib); - if (nullptr == FluidSynthDLL) + if(!FluidSynthModule.Load({fluid_lib})) { + const char* libname = fluid_lib; Printf(TEXTCOLOR_RED "Could not load %s\n", libname); } - } - else - { - FluidSynthDLL = nullptr; - } - - if (nullptr == FluidSynthDLL) - { - FluidSynthDLL = LoadLibrary(libname = FLUIDSYNTHLIB1); - if (nullptr == FluidSynthDLL) - { - FluidSynthDLL = LoadLibrary(libname = FLUIDSYNTHLIB2); - if (nullptr == FluidSynthDLL) - { - Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n"); - return false; - } - } - } -#else - if (strlen(fluid_lib) > 0) - { - FluidSynthSO = dlopen(libname = fluid_lib, RTLD_LAZY); - if (nullptr == FluidSynthSO) - { - Printf(TEXTCOLOR_RED "Could not load %s: %s\n", libname, dlerror()); - } - } - else - { - FluidSynthSO = nullptr; + else + return true; } - if (nullptr == FluidSynthSO) +#ifdef FLUIDSYNTHLIB2 + if(!FluidSynthModule.Load({FLUIDSYNTHLIB1, FLUIDSYNTHLIB2})) { - FluidSynthSO = dlopen(libname = FLUIDSYNTHLIB, RTLD_LAZY); - if (nullptr == FluidSynthSO) - { - Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB ": %s\n", dlerror()); - return false; - } - } -#endif - - for (size_t i = 0; i < countof(imports); ++i) - { -#ifdef _WIN32 - FARPROC proc = GetProcAddress(FluidSynthDLL, imports[i].FuncName); -#else - void *proc = dlsym(FluidSynthSO, imports[i].FuncName); -#endif - if (proc == NULL) - { - Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, libname); - fail++; - } - *imports[i].FuncPointer = (void *)proc; - } - if (fail == 0) - { - return true; - } - else - { -#ifdef _WIN32 - FreeLibrary(FluidSynthDLL); - FluidSynthDLL = NULL; -#else - dlclose(FluidSynthSO); - FluidSynthSO = NULL; -#endif + Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n"); return false; } - +#else + if(!FluidSynthModule.Load({fluid_lib, FLUIDSYNTHLIB1})) + { + Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 ": %s\n", dlerror()); + return false; + } +#endif + return true; } //========================================================================== @@ -786,19 +721,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() void FluidSynthMIDIDevice::UnloadFluidSynth() { -#ifdef _WIN32 - if (FluidSynthDLL != NULL) - { - FreeLibrary(FluidSynthDLL); - FluidSynthDLL = NULL; - } -#else - if (FluidSynthSO != NULL) - { - dlclose(FluidSynthSO); - FluidSynthSO = NULL; - } -#endif + FluidSynthModule.Unload(); } #endif diff --git a/src/sound/oalload.h b/src/sound/oalload.h index ca02d25d98..1fcf537732 100644 --- a/src/sound/oalload.h +++ b/src/sound/oalload.h @@ -3,24 +3,9 @@ #if !defined NO_OPENAL && defined DYN_OPENAL -#ifndef _WIN32 -typedef void* FARPROC; -#endif - -#define DEFINE_ENTRY(type, name) static type p_##name; +#define DEFINE_ENTRY(type, name) static TReqProc p_##name{#name}; #include "oaldef.h" #undef DEFINE_ENTRY -struct oalloadentry -{ - const char *name; - FARPROC *funcaddr; -}; -static oalloadentry oalfuncs[] = { -#define DEFINE_ENTRY(type, name) { #name, (FARPROC*)&p_##name }, -#include "oaldef.h" -#undef DEFINE_ENTRY -{ NULL, 0 } -}; #ifndef IN_IDE_PARSER #define alEnable p_alEnable diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 21370d082e..c1973780b4 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -55,29 +55,25 @@ #include "actor.h" #include "r_state.h" #include "w_wad.h" +#include "i_module.h" #include "i_music.h" #include "i_musicinterns.h" #include "tempfiles.h" +FModule OpenALModule{"OpenAL"}; + #include "oalload.h" CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #ifdef _WIN32 -static HMODULE hmodOpenAL; #define OPENALLIB "openal32.dll" -#else -static void* hmodOpenAL; -#ifdef __APPLE__ +#elif defined(__APPLE__) #define OPENALLIB "OpenAL.framework/OpenAL" #else #define OPENALLIB "libopenal.so.1" #endif -#define LoadLibrary(x) dlopen((x), RTLD_LAZY) -#define GetProcAddress(a,b) dlsym((a),(b)) -#define FreeLibrary(x) dlclose((x)) -#endif bool IsOpenALPresent() { @@ -92,29 +88,7 @@ bool IsOpenALPresent() if (!done) { done = true; - if (hmodOpenAL == NULL) - { - hmodOpenAL = LoadLibrary(NicePath("$PROGDIR/" OPENALLIB)); - if (hmodOpenAL == NULL) - { - hmodOpenAL = LoadLibrary(OPENALLIB); - if (hmodOpenAL == NULL) - { - return false; - } - } - for(int i = 0; oalfuncs[i].name != NULL; i++) - { - *oalfuncs[i].funcaddr = GetProcAddress(hmodOpenAL, oalfuncs[i].name); - if (*oalfuncs[i].funcaddr == NULL) - { - FreeLibrary(hmodOpenAL); - hmodOpenAL = NULL; - return false; - } - } - } - cached_result = true; + cached_result = OpenALModule.Load({NicePath("$PROGDIR/" OPENALLIB), OPENALLIB}); } return cached_result; #endif diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 52e78c3bc0..db92467bc3 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -68,6 +68,7 @@ #include "doomtype.h" #include "m_argv.h" #include "d_main.h" +#include "i_module.h" #include "i_system.h" #include "c_console.h" #include "version.h" @@ -84,6 +85,8 @@ #include "stats.h" #include "st_start.h" +#include "optwin32.h" + #include // MACROS ------------------------------------------------------------------ @@ -143,6 +146,21 @@ LONG GameTitleFontHeight; LONG DefaultGUIFontHeight; LONG ErrorIconChar; +FModule Kernel32Module{"Kernel32"}; +FModule Shell32Module{"Shell32"}; +FModule User32Module{"User32"}; + +namespace OptWin32 { +#define DYN_WIN32_SYM(x) decltype(x) x{#x} + +DYN_WIN32_SYM(SHGetFolderPathA); +DYN_WIN32_SYM(SHGetKnownFolderPath); +DYN_WIN32_SYM(GetLongPathNameA); +DYN_WIN32_SYM(GetMonitorInfoA); + +#undef DYN_WIN32_SYM +} // namespace OptWin32 + // PRIVATE DATA DEFINITIONS ------------------------------------------------ static const char WinClassName[] = GAMENAME "MainWindow"; @@ -818,6 +836,11 @@ void DoMain (HINSTANCE hInstance) Args = new DArgs(__argc, __argv); + // Load Win32 modules + Kernel32Module.Load({"kernel32.dll"}); + Shell32Module.Load({"shell32.dll"}); + User32Module.Load({"user32.dll"}); + // Under XP, get our session ID so we can know when the user changes/locks sessions. // Since we need to remain binary compatible with older versions of Windows, we // need to extract the ProcessIdToSessionId function from kernel32.dll manually. diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index ed8dc2ee6d..6d4890ea9d 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -43,7 +43,7 @@ #include "version.h" // for GAMENAME #include "i_system.h" -typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); +#include "optwin32.h" //=========================================================================== // @@ -94,19 +94,17 @@ bool UseKnownFolders() bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) { - static TOptWin32Proc SHGetKnownFolderPath("shell32.dll", "SHGetKnownFolderPath"); + using OptWin32::SHGetFolderPathA; + using OptWin32::SHGetKnownFolderPath; char pathstr[MAX_PATH]; // SHGetKnownFolderPath knows about more folders than SHGetFolderPath, but is // new to Vista, hence the reason we support both. - if (SHGetKnownFolderPath == NULL) + if (!SHGetKnownFolderPath) { - static TOptWin32Proc - SHGetFolderPathA("shell32.dll", "SHGetFolderPathA"); - // NT4 doesn't even have this function. - if (SHGetFolderPathA == NULL) + if (!SHGetFolderPathA) return false; if (shell_folder < 0) @@ -117,7 +115,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create { shell_folder |= CSIDL_FLAG_CREATE; } - if (FAILED(SHGetFolderPathA.Call(NULL, shell_folder, NULL, 0, pathstr))) + if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr))) { return false; } @@ -127,7 +125,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create else { PWSTR wpath; - if (FAILED(SHGetKnownFolderPath.Call(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) + if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) { return false; } diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 2075bd276b..d55d1e093d 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -86,6 +86,8 @@ #include "textures/bitmap.h" #include "textures/textures.h" +#include "optwin32.h" + // MACROS ------------------------------------------------------------------ #ifdef _MSC_VER @@ -1716,20 +1718,19 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { - static TOptWin32Proc - GetLongPathNameA("kernel32.dll", "GetLongPathNameA"); + using OptWin32::GetLongPathNameA; // Doesn't exist on NT4 - if (GetLongPathName == NULL) + if (!GetLongPathName) return shortpath; - DWORD buffsize = GetLongPathNameA.Call(shortpath.GetChars(), NULL, 0); + DWORD buffsize = GetLongPathNameA(shortpath.GetChars(), NULL, 0); if (buffsize == 0) { // nothing to change (it doesn't exist, maybe?) return shortpath; } TCHAR *buff = new TCHAR[buffsize]; - DWORD buffsize2 = GetLongPathNameA.Call(shortpath.GetChars(), buff, buffsize); + DWORD buffsize2 = GetLongPathNameA(shortpath.GetChars(), buff, buffsize); if (buffsize2 >= buffsize) { // Failure! Just return the short path delete[] buff; diff --git a/src/win32/i_system.h b/src/win32/i_system.h index a7fca25a68..e7437beb89 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -51,30 +51,6 @@ typedef enum { extern os_t OSPlatform; -// Helper template so that we can access newer Win32 functions with a single static -// variable declaration. If this were C++11 it could be totally transparent. -template -class TOptWin32Proc -{ - static Proto GetOptionalWin32Proc(const char* module, const char* function) - { - HMODULE hmodule = GetModuleHandle(module); - if (hmodule == NULL) - return NULL; - - return (Proto)GetProcAddress(hmodule, function); - } - -public: - const Proto Call; - - TOptWin32Proc(const char* module, const char* function) - : Call(GetOptionalWin32Proc(module, function)) {} - - // Wrapper object can be tested against NULL, but not directly called. - operator const void*() const { return Call; } -}; - // Called by DoomMain. void I_Init (void); diff --git a/src/win32/optwin32.h b/src/win32/optwin32.h new file mode 100644 index 0000000000..0f1458c57e --- /dev/null +++ b/src/win32/optwin32.h @@ -0,0 +1,24 @@ +#pragma once + +// Forward declarations for optional Win32 API procedures +// implemented in i_main.cpp + +#define WIN32_LEAN_AND_MEAN +#include +#include +#define USE_WINDOWS_DWORD + +#include "i_module.h" + +extern FModule Kernel32Module; +extern FModule Shell32Module; +extern FModule User32Module; + +namespace OptWin32 { + +extern TOptProc SHGetFolderPathA; +extern TOptProc SHGetKnownFolderPath; +extern TOptProc GetLongPathNameA; +extern TOptProc GetMonitorInfoA; + +} // namespace OptWin32 diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 8eb2349ec2..18c66f5d31 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -74,6 +74,8 @@ #include "win32iface.h" +#include "optwin32.h" + // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- @@ -387,6 +389,8 @@ void Win32Video::BlankForGDI () void Win32Video::DumpAdapters() { + using OptWin32::GetMonitorInfoA; + if (D3D == NULL) { Printf("Multi-monitor support requires Direct3D.\n"); @@ -415,9 +419,8 @@ void Win32Video::DumpAdapters() MONITORINFOEX mi; mi.cbSize = sizeof(mi); - TOptWin32Proc GetMonitorInfo("user32.dll", "GetMonitorInfoW"); - assert(GetMonitorInfo != NULL); // Missing in NT4, but so is D3D - if (GetMonitorInfo.Call(hm, &mi)) + assert(GetMonitorInfo); // Missing in NT4, but so is D3D + if (GetMonitorInfo(hm, &mi)) { mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s", mi.rcMonitor.right - mi.rcMonitor.left, From 472f35d2ce5615a7492d07030ff5fe672751bb32 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 13 Nov 2016 00:17:09 -0500 Subject: [PATCH 082/101] - Fixed building with gtk2 headers. --- src/posix/unix/iwadpicker_gtk.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/posix/unix/iwadpicker_gtk.cpp b/src/posix/unix/iwadpicker_gtk.cpp index f5fd393b94..56228c4e8c 100644 --- a/src/posix/unix/iwadpicker_gtk.cpp +++ b/src/posix/unix/iwadpicker_gtk.cpp @@ -11,6 +11,14 @@ #include #else #include +typedef enum +{ + GTK_ALIGN_FULL, + GTK_ALIGN_START, + GTK_ALIGN_END, + GTK_ALIGN_CENTER, + GTK_ALIGN_BASELINE +} GtkAlign; #endif #include "c_cvars.h" From 02435b46a0af7287a542a0887ec7ac7aa828f742 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sun, 13 Nov 2016 19:27:59 -0600 Subject: [PATCH 083/101] Fixed: A_SetInventory with an amount of 0 was not truly eliminating the actor. --- src/p_actionfunctions.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 73cade49a4..b9cfd7fe0e 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2665,8 +2665,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetInventory) } else if (amount <= 0) { - //Remove it all. - res = (mobj->TakeInventory(itemtype, item->Amount, true, false)); + // Remove it all. + if (item) + { + item->DepleteOrDestroy(); + res = true; + } ACTION_RETURN_BOOL(res); } else if (amount < item->Amount) From 109558d74d116900f3528862d062deefa3cb14d8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 14 Nov 2016 13:12:55 +0100 Subject: [PATCH 084/101] - added unsigned char casts to all isspace calls in zstring.cpp isspace takes a signed integer as parameter which triggers an assert on any non-ASCII character taken from a signed char array. --- src/zstring.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/zstring.cpp b/src/zstring.cpp index b6e5b4b8de..e8e867323d 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -632,7 +632,7 @@ void FString::StripLeft () if (max == 0) return; for (i = 0; i < max; ++i) { - if (!isspace(Chars[i])) + if (!isspace((unsigned char)Chars[i])) break; } if (i == 0) @@ -697,7 +697,7 @@ void FString::StripRight () if (max == 0) return; for (i = --max; i-- > 0; ) { - if (!isspace(Chars[i])) + if (!isspace((unsigned char)Chars[i])) break; } if (i == max) @@ -756,12 +756,12 @@ void FString::StripLeftRight () if (max == 0) return; for (i = 0; i < max; ++i) { - if (!isspace(Chars[i])) + if (!isspace((unsigned char)Chars[i])) break; } for (j = max - 1; j >= i; --j) { - if (!isspace(Chars[j])) + if (!isspace((unsigned char)Chars[j])) break; } if (i == 0 && j == max - 1) @@ -1040,7 +1040,7 @@ octdigits = [0-7]; yych = *YYCURSOR; // Skip preceding whitespace - while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; } + while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; } // Check for sign if (yych == '+' || yych == '-') { yych = *++YYCURSOR; } @@ -1078,7 +1078,7 @@ octdigits = [0-7]; } // The rest should all be whitespace - while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; } + while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; } return yych == '\0'; } @@ -1098,7 +1098,7 @@ digits = [0-9]; yych = *YYCURSOR; // Skip preceding whitespace - while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; } + while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; } // Check for sign if (yych == '+' || yych == '-') { yych = *++YYCURSOR; } @@ -1129,7 +1129,7 @@ digits = [0-9]; } // The rest should all be whitespace - while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; } + while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; } return yych == '\0'; } From 0111ec451a3a3d67055d67c9b3de6fa3d8814f31 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 14 Nov 2016 15:52:49 +0100 Subject: [PATCH 085/101] Revert "Fixed: A_SetInventory with an amount of 0 was not truly eliminating the actor." This reverts commit 02435b46a0af7287a542a0887ec7ac7aa828f742. --- src/p_actionfunctions.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index b9cfd7fe0e..73cade49a4 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2665,12 +2665,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetInventory) } else if (amount <= 0) { - // Remove it all. - if (item) - { - item->DepleteOrDestroy(); - res = true; - } + //Remove it all. + res = (mobj->TakeInventory(itemtype, item->Amount, true, false)); ACTION_RETURN_BOOL(res); } else if (amount < item->Amount) From f2ec266eec6cff1ee1353eda952989533acf2e43 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 15 Nov 2016 11:38:03 -0600 Subject: [PATCH 086/101] Fixed: Actors with NOINTERACTION shouldn't waste time continuously applying NOBLOCKMAP if it has it already and not moving. --- src/p_mobj.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3e20118784..2183f8cb9c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3373,11 +3373,14 @@ void AActor::Tick () } } - UnlinkFromWorld (); - flags |= MF_NOBLOCKMAP; - SetXYZ(Vec3Offset(Vel)); - CheckPortalTransition(false); - LinkToWorld (); + if (!Vel.isZero() || !(flags & MF_NOBLOCKMAP)) + { + UnlinkFromWorld(); + flags |= MF_NOBLOCKMAP; + SetXYZ(Vec3Offset(Vel)); + CheckPortalTransition(false); + LinkToWorld(); + } } else { From b3b5cb2fa410554edb095fb0515ed6cc17098145 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 23:13:17 +0100 Subject: [PATCH 087/101] - fixed: Lines with both sides in the same sector but an active portal may not be discarded early. --- src/gl/scene/gl_bsp.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/gl/scene/gl_bsp.cpp b/src/gl/scene/gl_bsp.cpp index 7b98300502..f0ddfd642c 100644 --- a/src/gl/scene/gl_bsp.cpp +++ b/src/gl/scene/gl_bsp.cpp @@ -140,12 +140,15 @@ static void AddLine (seg_t *seg, bool portalclip) { if (currentsector->sectornum == seg->backsector->sectornum) { - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); - if (!tex || tex->UseType==FTexture::TEX_Null) + if (!seg->linedef->isVisualPortal()) { - // nothing to do here! - seg->linedef->validcount=validcount; - return; + FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); + if (!tex || tex->UseType==FTexture::TEX_Null) + { + // nothing to do here! + seg->linedef->validcount=validcount; + return; + } } backsector=currentsector; } From 3b240b73e9585b963a76f77c00ec617fe1a4bd1b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Nov 2016 12:40:08 +0200 Subject: [PATCH 088/101] Fixed endianness issue with saved games See http://forum.zdoom.org/viewtopic.php?t=54272 --- src/resourcefiles/file_zip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 8713fe554a..8011d56cfe 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -577,7 +577,7 @@ bool WriteZip(const char *filename, TArray &filenames, TArray Date: Sat, 19 Nov 2016 12:41:01 +0200 Subject: [PATCH 089/101] Fixed compilation warnings in Cocoa backend --- src/posix/cocoa/i_input.mm | 2 +- src/posix/cocoa/i_joystick.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 3bbf42a9ad..7032806158 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -526,7 +526,7 @@ void ProcessMouseMoveInGame(NSEvent* theEvent) lastX = x; lastY = y; - if (0 != event.x | 0 != event.y) + if (0 != event.x || 0 != event.y) { event.type = EV_Mouse; diff --git a/src/posix/cocoa/i_joystick.cpp b/src/posix/cocoa/i_joystick.cpp index c4bcc85c3e..747cc14226 100644 --- a/src/posix/cocoa/i_joystick.cpp +++ b/src/posix/cocoa/i_joystick.cpp @@ -1018,7 +1018,7 @@ IOKitJoystickManager::~IOKitJoystickManager() if (0 != notification) { IOObjectRelease(notification); - notification = NULL; + notification = 0; } } } From c28bcca3f3504b97fa791be56b83e1f679cfbb5b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Nov 2016 12:44:35 +0200 Subject: [PATCH 090/101] Print unknown if release information is unavailable on macOS At least 10.4 Tiger doesn't support required sysctl name --- src/posix/cocoa/i_main.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index d8f0e74cf8..851e72e484 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -156,7 +156,7 @@ static void I_DetectOS() case 12: name = "macOS Sierra"; break; } - char release[16] = {}; + char release[16] = "unknown"; size_t size = sizeof release - 1; sysctlbyname("kern.osversion", release, &size, nullptr, 0); From 789315bb4a7a2a5701b40c4ee004336395bd452f Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 22 Nov 2016 21:22:39 -0500 Subject: [PATCH 091/101] - Fixed build with MinGW-w64 (TDM-GCC 5.1). Note that the resulting binary will crash under -O3 until the alignment violation is taken care of in FRemapTable::Alloc. - It appears that CMake added native support for building rc files with MinGW at some point so removed manual rc compiling code. --- src/CMakeLists.txt | 10 +----- src/i_module.cpp | 2 +- src/v_video.cpp | 2 +- src/win32/i_crash.cpp | 48 ----------------------------- src/win32/i_keyboard.cpp | 5 +++ src/win32/i_rawps2.cpp | 2 +- src/win32/i_specialpaths.cpp | 1 + src/win32/i_xinput.cpp | 11 +++++++ tools/updaterevision/CMakeLists.txt | 17 +++------- 9 files changed, 26 insertions(+), 72 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04e6087ead..7d532ca9cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -728,15 +728,7 @@ if( WIN32 ) set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) - if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - # CMake is not set up to compile and link rc files with GCC. :( - add_custom_command( OUTPUT zdoom-rc.o - COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc - DEPENDS win32/zdoom.rc ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o ) - else() - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) - endif() + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) elseif( APPLE ) if( OSX_COCOA_BACKEND ) set( SYSTEM_SOURCES_DIR posix posix/cocoa ) diff --git a/src/i_module.cpp b/src/i_module.cpp index 1ed40310fa..a82963ec5f 100644 --- a/src/i_module.cpp +++ b/src/i_module.cpp @@ -97,5 +97,5 @@ bool FModule::Open(const char* lib) void *FModule::GetSym(const char* name) { - return GetProcAddress((HMODULE)handle, name); + return (void *)GetProcAddress((HMODULE)handle, name); } diff --git a/src/v_video.cpp b/src/v_video.cpp index 37cfdd4801..32e1a54d39 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -72,7 +72,7 @@ FRenderer *Renderer; IMPLEMENT_ABSTRACT_CLASS (DCanvas) IMPLEMENT_ABSTRACT_CLASS (DFrameBuffer) -#if defined(_DEBUG) && defined(_M_IX86) +#if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__) #define DBGBREAK { __asm int 3 } #else #define DBGBREAK diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index d4804ec0e9..4a0a1b1606 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -75,54 +75,6 @@ #include #include -#if defined(_WIN64) && defined(__GNUC__) -struct KNONVOLATILE_CONTEXT_POINTERS { - union { - PDWORD64 IntegerContext[16]; - struct { - PDWORD64 Rax; - PDWORD64 Rcx; - PDWORD64 Rdx; - PDWORD64 Rbx; - PDWORD64 Rsp; - PDWORD64 Rbp; - PDWORD64 Rsi; - PDWORD64 Rdi; - PDWORD64 R8; - PDWORD64 R9; - PDWORD64 R10; - PDWORD64 R11; - PDWORD64 R12; - PDWORD64 R13; - PDWORD64 R14; - PDWORD64 R15; - }; - }; -}; -typedef -EXCEPTION_DISPOSITION -NTAPI -EXCEPTION_ROUTINE ( - struct _EXCEPTION_RECORD *ExceptionRecord, - PVOID EstablisherFrame, - struct _CONTEXT *ContextRecord, - PVOID DispatcherContext - ); -NTSYSAPI -EXCEPTION_ROUTINE * -NTAPI -RtlVirtualUnwind ( - DWORD HandlerType, - DWORD64 ImageBase, - DWORD64 ControlPc, - PRUNTIME_FUNCTION FunctionEntry, - PCONTEXT ContextRecord, - PVOID *HandlerData, - PDWORD64 EstablisherFrame, - KNONVOLATILE_CONTEXT_POINTERS *ContextPointers - ); -#endif - // MACROS ------------------------------------------------------------------ #define REMOTE_HOST "localhost" diff --git a/src/win32/i_keyboard.cpp b/src/win32/i_keyboard.cpp index cdcf9d8d85..e62942e8d3 100644 --- a/src/win32/i_keyboard.cpp +++ b/src/win32/i_keyboard.cpp @@ -21,6 +21,11 @@ #define DINPUT_BUFFERSIZE 32 +// MinGW-w64 (TDM5.1 - 2016/11/21) +#ifndef DIK_PREVTRACK +#define DIK_PREVTRACK DIK_CIRCUMFLEX +#endif + // TYPES ------------------------------------------------------------------- class FDInputKeyboard : public FKeyboard diff --git a/src/win32/i_rawps2.cpp b/src/win32/i_rawps2.cpp index 50de1d0f45..940ef4bb1a 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/win32/i_rawps2.cpp @@ -389,7 +389,7 @@ bool FRawPS2Controller::ProcessInput(RAWHID *raw, int code) { // w32api has an incompatible definition of bRawData. // (But the version that comes with MinGW64 is fine.) -#if defined(__GNUC__) && !defined(_WIN64) +#if defined(__GNUC__) && !defined(__MINGW64_VERSION_MAJOR) BYTE *rawdata = &raw->bRawData; #else BYTE *rawdata = raw->bRawData; diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 6d4890ea9d..745c12f12a 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -33,6 +33,7 @@ ** */ +#define _WIN32_WINNT 0x0601 #include #include #include diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index 1180f9f32c..22c2dd7142 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -33,6 +33,17 @@ #define XUSER_MAX_COUNT 4 #endif +// MinGW +#ifndef XINPUT_DLL +#define XINPUT_DLL_A "xinput1_3.dll" +#define XINPUT_DLL_W L"xinput1_3.dll" +#ifdef UNICODE + #define XINPUT_DLL XINPUT_DLL_W +#else + #define XINPUT_DLL XINPUT_DLL_A +#endif +#endif + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); diff --git a/tools/updaterevision/CMakeLists.txt b/tools/updaterevision/CMakeLists.txt index 22890472a5..db99ab812e 100644 --- a/tools/updaterevision/CMakeLists.txt +++ b/tools/updaterevision/CMakeLists.txt @@ -1,19 +1,12 @@ cmake_minimum_required( VERSION 2.8.7 ) if( WIN32 ) - if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE OR ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o - COMMAND windres -o ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o -i ${CMAKE_CURRENT_SOURCE_DIR}/trustinfo.rc - DEPENDS trustinfo.rc ) - set( TRUSTINFO trustinfo.o ) + if( MSVC_VERSION GREATER 1399 ) + # VC 8+ adds a manifest automatically to the executable. We need to + # merge ours with it. + set( MT_MERGE ON ) else() - if( MSVC_VERSION GREATER 1399 ) - # VC 8+ adds a manifest automatically to the executable. We need to - # merge ours with it. - set( MT_MERGE ON ) - else( MSVC_VERSION GREATER 1399 ) - set( TRUSTINFO trustinfo.rc ) - endif( MSVC_VERSION GREATER 1399 ) + set( TRUSTINFO trustinfo.rc ) endif() else( WIN32 ) set( TRUSTINFO "" ) From 649c96261a8ad72996b19ff84c39d074ef46cd5b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 10:13:17 +0100 Subject: [PATCH 092/101] - clarified error messages for bogus conversation scripts. --- src/p_conversation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0bc2b98a87..41c8733752 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -252,7 +252,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } @@ -272,7 +272,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1516; @@ -282,7 +282,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1488; From 0489b6e7c5075bad5c83b9b2961c9f629ec11197 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 23 Nov 2016 10:19:52 +0100 Subject: [PATCH 093/101] - Fixed missing newlines to the conversation error message. --- src/p_conversation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 41c8733752..0208e64775 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -252,7 +252,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } @@ -272,7 +272,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1516; @@ -282,7 +282,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1488; From 6ae266c76eb191f5a607b721cccc7a1b3567f1a0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:27:08 +0100 Subject: [PATCH 094/101] - fixed: The check for identical floor planes on an opening should never allow it to be narrowed down. This can cause problems in rare situations where a sloped plane is checked outside its sector boundaries. --- src/p_map.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 5cc9bdf72c..d102307bcc 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -839,9 +839,11 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec // If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. + // This should never narrow down the opening, though, only widen it. if (open.frontfloorplane == open.backfloorplane && open.bottom > LINEOPEN_MIN) { - open.bottom = open.frontfloorplane.ZatPoint(cres.Position); + auto newopen = open.frontfloorplane.ZatPoint(cres.Position); + if (newopen < open.bottom) open.bottom = newopen; } if (rail && From 5b059971f0eceb38f9883d19b37b0adcd4360e67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:32:18 +0100 Subject: [PATCH 095/101] - fixed: P_SpawnMapThing forced gravity instead of disabling it when being given Gravity = 0 from UDMF. --- src/p_mobj.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2183f8cb9c..62da260492 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5063,7 +5063,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) 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 *= mthing->Gravity; - else mobj->flags &= ~MF_NOGRAVITY; + else + { + mobj->flags |= MF_NOGRAVITY; + mobj->Gravity = 0; + } // For Hexen floatbob 'compatibility' we do not really want to alter the floorz. if (mobj->specialf1 == 0 || !(mobj->flags2 & MF2_FLOATBOB) || !(ib_compatflags & BCOMPATF_FLOATBOB)) From e138a3ffbc916ac2c9390c4f339e9154e07222a7 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 23 Nov 2016 12:15:58 +0200 Subject: [PATCH 096/101] Fixed infinite recursion with self-referencing multipatch textures See http://forum.zdoom.org/viewtopic.php?t=54355 --- src/textures/multipatchtexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 88d8815a6f..de3dd2f131 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1334,6 +1334,7 @@ void FMultiPatchTexture::ResolvePatches() { if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); + continue; } else { From 9bd19c2d2e48556018458348fe07d2a4ea4f557e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:38:45 +0100 Subject: [PATCH 097/101] - ensure that the MAPINFO parser never mixes HexenHack parsing with the new format. --- src/g_mapinfo.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index bc04704740..7bfb690e79 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1508,10 +1508,18 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) if (sc.CheckNumber()) { // MAPNAME is a number; assume a Hexen wad - char maptemp[8]; - mysnprintf (maptemp, countof(maptemp), "MAP%02d", sc.Number); - mapname = maptemp; - HexenHack = true; + if (format_type == FMT_New) + { + mapname = sc.String; + } + else + { + char maptemp[8]; + mysnprintf(maptemp, countof(maptemp), "MAP%02d", sc.Number); + mapname = maptemp; + HexenHack = true; + format_type = FMT_Old; + } } else { From dc11b6315709fb9bdf124a05e2a90be261c9c9d9 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 24 Nov 2016 00:47:53 -0500 Subject: [PATCH 098/101] - Fixed building with vanilla MinGW, at least with whatever modified header files that my system has from my last experimentation. --- src/CMakeLists.txt | 8 ++++++-- src/win32/i_specialpaths.cpp | 9 +++++++++ src/win32/i_system.cpp | 4 ++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d532ca9cf..a2bde0de51 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,8 +178,12 @@ if( WIN32 ) comdlg32 ws2_32 setupapi - oleaut32 - DelayImp ) + oleaut32 ) + + if( NOT ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} DelayImp ) + endif() + if( DX_dxguid_LIBRARY ) list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" ) endif() diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 745c12f12a..cddeacde6e 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -46,6 +46,15 @@ #include "optwin32.h" +// Vanilla MinGW does not have folder ids +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +static const GUID FOLDERID_LocalAppData = { 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91 }; +static const GUID FOLDERID_RoamingAppData = { 0x3eb685db, 0x65f9, 0x4cf6, 0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d }; +static const GUID FOLDERID_SavedGames = { 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4 }; +static const GUID FOLDERID_Documents = { 0xfdd39ad0, 0x238f, 0x46af, 0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7 }; +static const GUID FOLDERID_Pictures = { 0x33e28130, 0x4e1e, 0x4676, 0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb }; +#endif + //=========================================================================== // // IsProgramDirectoryWritable diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index d55d1e093d..29ea3c4b7c 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1314,7 +1314,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) HDC dc = GetDC(NULL); if (dc == NULL) { - return false; + return nullptr; } HDC and_mask_dc = CreateCompatibleDC(dc); HDC xor_mask_dc = CreateCompatibleDC(dc); @@ -1721,7 +1721,7 @@ FString I_GetLongPathName(FString shortpath) using OptWin32::GetLongPathNameA; // Doesn't exist on NT4 - if (!GetLongPathName) + if (!GetLongPathNameA) return shortpath; DWORD buffsize = GetLongPathNameA(shortpath.GetChars(), NULL, 0); From 68dc3c4f2daf80ef043ad6f7d1ff5b49b81a15e6 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 23 Nov 2016 16:24:56 +0100 Subject: [PATCH 099/101] - Preventive fix for future include conflicts. basicinlines.h is only included in m_fixed.h, while basictypes.h is included only in headers, so it's better to respect this convention. OSX compiles fine also without m_fixed.h, even better. --- src/posix/cocoa/i_timer.cpp | 2 -- src/posix/sdl/i_timer.cpp | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/posix/cocoa/i_timer.cpp b/src/posix/cocoa/i_timer.cpp index 901657eb95..5141f8750c 100644 --- a/src/posix/cocoa/i_timer.cpp +++ b/src/posix/cocoa/i_timer.cpp @@ -37,8 +37,6 @@ #include #include -#include "basictypes.h" -#include "basicinlines.h" #include "doomdef.h" #include "i_system.h" #include "templates.h" diff --git a/src/posix/sdl/i_timer.cpp b/src/posix/sdl/i_timer.cpp index cad3000ba4..84108f3b77 100644 --- a/src/posix/sdl/i_timer.cpp +++ b/src/posix/sdl/i_timer.cpp @@ -7,8 +7,7 @@ #include -#include "basictypes.h" -#include "basicinlines.h" +#include "m_fixed.h" #include "hardware.h" #include "i_system.h" #include "templates.h" From ae382f4005683da471e91c2f42afb5240ef5c486 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Mon, 21 Nov 2016 15:06:39 +0100 Subject: [PATCH 100/101] - Fixed the spline/cubic crashes for FMOD 4.24 64-bit, too. --- src/sound/fmodsound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index c130b7e6ae..cb4fac2cca 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -238,8 +238,8 @@ static const FEnumList ResamplerNames[] = { "No Interpolation", FMOD_DSP_RESAMPLER_NOINTERP }, { "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP }, { "Linear", FMOD_DSP_RESAMPLER_LINEAR }, - // [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers. -#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF) + // [BL] 64-bit versions of FMOD Ex between 4.24 and 4.26 crash with these resamplers. +#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42400 && FMOD_VERSION <= 0x426FF) { "Cubic", FMOD_DSP_RESAMPLER_CUBIC }, { "Spline", FMOD_DSP_RESAMPLER_SPLINE }, #endif From 4eb32a50e3151968e1b2285688ce98da98fedd9f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 24 Nov 2016 07:37:15 +0100 Subject: [PATCH 101/101] Add vid_vsync support to Linux target --- src/posix/sdl/sdlglvideo.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index d8c00f2363..173a84d801 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -442,6 +442,16 @@ void SDLGLFB::SetVSync( bool vsync ) #if defined (__APPLE__) const GLint value = vsync ? 1 : 0; CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value ); +#else + if (vsync) + { + if (SDL_GL_SetSwapInterval(-1) == -1) + SDL_GL_SetSwapInterval(1); + } + else + { + SDL_GL_SetSwapInterval(0); + } #endif }