From c099cd45810884cd793fb51ef6b66b4967865429 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Tue, 8 Dec 2015 22:58:24 +1300 Subject: [PATCH 01/15] SpawnParticle functions - Added A_SpawnParticle Decorate and SpawnParticle ACS functions. --- src/p_acs.cpp | 32 ++++++++++++++++++++++++++++- src/p_effect.cpp | 25 +++++++++++++++++++++++ src/p_effect.h | 1 + src/thingdef/thingdef_codeptr.cpp | 34 +++++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 30733eac8..bc0e74469 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -76,6 +76,7 @@ #include "farchive.h" #include "decallib.h" #include "version.h" +#include "p_effect.h" #include "g_shared/a_pickups.h" @@ -4441,7 +4442,8 @@ enum EACSFunctions ACSF_ChangeActorRoll, ACSF_GetActorRoll, ACSF_QuakeEx, - ACSF_Warp, // 92 + ACSF_Warp, + ACSF_SpawnParticle, // 93 /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -5916,6 +5918,34 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return false; } + case ACSF_SpawnParticle: + { + fixed_t x = args[0]; + fixed_t y = args[1]; + fixed_t z = args[2]; + fixed_t xvel = args[3]; + fixed_t yvel = args[4]; + fixed_t zvel = args[5]; + PalEntry color = args[6]; + int lifetime = args[7]; + bool fullbright = argCount > 8 ? !!args[8] : false; + int startalpha = argCount > 9 ? args[9] : 0xFF; // Byte trans + int size = argCount > 10 ? args[10] : 1; + int fadestep = argCount > 11 ? args[11] : -1; + fixed_t accelx = argCount > 12 ? args[12] : 0; + fixed_t accely = argCount > 13 ? args[13] : 0; + fixed_t accelz = argCount > 14 ? args[14] : 0; + + startalpha = clamp(startalpha, 0, 0xFF); // Clamp to byte + lifetime = clamp(lifetime, 0, 0xFF); // Clamp to byte + fadestep = clamp(fadestep, -1, 0xFF); // Clamp to byte inc. -1 (indicating automatic) + size = clamp(size, 0, 0xFF); // Clamp to byte + + if (lifetime != 0) + P_SpawnParticle(x, y, z, xvel, yvel, zvel, color, fullbright, startalpha, lifetime, size, fadestep, accelx, accely, accelz); + } + break; + default: break; } diff --git a/src/p_effect.cpp b/src/p_effect.cpp index db3129521..59142a8cf 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -284,6 +284,31 @@ void P_ThinkParticles () } } +void P_SpawnParticle(fixed_t x, fixed_t y, fixed_t z, fixed_t velx, fixed_t vely, fixed_t velz, PalEntry color, bool fullbright, BYTE startalpha, BYTE lifetime, BYTE size, int fadestep, fixed_t accelx, fixed_t accely, fixed_t accelz) +{ + particle_t *particle = NewParticle(); + + if (particle) + { + particle->x = x; + particle->y = y; + particle->z = z; + particle->velx = velx; + particle->vely = vely; + particle->velz = velz; + particle->color = ParticleColor(color); + particle->trans = startalpha; + if (fadestep < 0) fadestep = FADEFROMTTL(lifetime); + particle->fade = fadestep; + particle->ttl = lifetime; + particle->accx = accelx; + particle->accy = accely; + particle->accz = accelz; + particle->bright = fullbright; + particle->size = size; + } +} + // // P_RunEffects // diff --git a/src/p_effect.h b/src/p_effect.h index 11116e8a3..aac9a63dc 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -83,6 +83,7 @@ particle_t *JitterParticle (int ttl); particle_t *JitterParticle (int ttl, float drift); void P_ThinkParticles (void); +void P_SpawnParticle(fixed_t x, fixed_t y, fixed_t z, fixed_t velx, fixed_t vely, fixed_t velz, PalEntry color, bool fullbright, BYTE startalpha, BYTE lifetime, BYTE size, int fadestep, fixed_t accelx, fixed_t accely, fixed_t accelz); void P_InitEffects (void); void P_RunEffects (void); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89299e0fa..b8a2c802d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -51,6 +51,7 @@ #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" +#include "p_effect.h" #include "p_enemy.h" #include "a_action.h" #include "decallib.h" @@ -2614,6 +2615,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) } } +//=========================================================================== +// +// A_SpawnParticle +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) +{ + ACTION_PARAM_START(15); + ACTION_PARAM_FIXED(xoff, 0); + ACTION_PARAM_FIXED(yoff, 1); + ACTION_PARAM_FIXED(zoff, 2); + ACTION_PARAM_FIXED(xvel, 3); + ACTION_PARAM_FIXED(yvel, 4); + ACTION_PARAM_FIXED(zvel, 5); + ACTION_PARAM_COLOR(color, 6); + ACTION_PARAM_INT(lifetime, 7); + ACTION_PARAM_BOOL(fullbright, 8); + ACTION_PARAM_INT(startalpha, 9); // Byte trans + ACTION_PARAM_INT(size, 10); + ACTION_PARAM_INT(fadestep, 11); + ACTION_PARAM_FIXED(accelx, 12); + ACTION_PARAM_FIXED(accely, 13); + ACTION_PARAM_FIXED(accelz, 14); + + startalpha = clamp(startalpha, 0, 0xFF); // Clamp to byte + lifetime = clamp(lifetime, 0, 0xFF); // Clamp to byte + fadestep = clamp(fadestep, -1, 0xFF); // Clamp to byte inc. -1 (indicating automatic) + size = clamp(size, 0, 0xFF); // Clamp to byte + + if (lifetime != 0) + P_SpawnParticle(xoff + self->x, yoff + self->y, zoff + self->z, xvel, yvel, zvel, color, fullbright, startalpha, lifetime, size, fadestep, accelx, accely, accelz); +} + //=========================================================================== // diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5158aa7b5..0d31851b7 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -234,6 +234,7 @@ ACTOR Actor native //: Thinker action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT); action native A_SetMass(int mass); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); + action native A_SpawnParticle(float xoff, float yoff, float zoff, float velx, float vely, float velz, color color1, int lifetime, bool fullbright = false, int startalpha = 255, int size = 1, int fadestep = -1, float accelx = 0.0, float accely = 0.0, float accelz = 0.0); action native A_CheckSight(state label); action native A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); action native A_DropInventory(class itemtype); From 452c82cbe2154eabe6b7d9519c603480f5013913 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 17 Dec 2015 10:34:38 -0600 Subject: [PATCH 02/15] - Added TF_SENSITIVEZ to A_Teleport. Fail teleportation instead of adjusting the actor to fit if they cannot. - When checking whether to use spot z or floorz, use spot floorz instead of ref for consistency. --- src/thingdef/thingdef_codeptr.cpp | 19 +++++++++++++++---- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89299e0fa..af40ed342 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4261,6 +4261,7 @@ enum T_Flags TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. TF_NOJUMP = 0x00000200, // Don't jump after teleporting. TF_OVERRIDE = 0x00000400, // Ignore NOTELEPORT. + TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) @@ -4323,6 +4324,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) return; } + // [MC] By default, the function adjusts the actor's Z if it's below the floor or above the ceiling. + // This can be an issue as actors designed to maintain specific z positions wind up teleporting + // anyway when they should not, such as a floor rising above or ceiling lowering below the position + // of the spot. + if (Flags & TF_SENSITIVEZ) + { + fixed_t posz = (Flags & TF_USESPOTZ) ? spot->z : spot->floorz; + if ((posz + ref->height > spot->ceilingz) || (posz < spot->floorz)) + { + ACTION_SET_RESULT(false); + return; + } + } fixed_t prevX = ref->x; fixed_t prevY = ref->y; fixed_t prevZ = ref->z; @@ -4378,10 +4392,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) } - if (Flags & TF_USESPOTZ) - ref->z = spot->z; - else - ref->z = ref->floorz; + ref->z = (Flags & TF_USESPOTZ) ? spot->z : spot->floorz; if (!(Flags & TF_KEEPANGLE)) ref->angle = spot->angle; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 956ed119f..81a0c1b63 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -204,6 +204,7 @@ enum TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. TF_NOJUMP = 0x00000200, // Don't jump after teleporting. TF_OVERRIDE = 0x00000400, // Ignore NOTELEPORT. + TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). TF_KEEPORIENTATION = TF_KEEPVELOCITY|TF_KEEPANGLE, TF_NOFOG = TF_NOSRCFOG|TF_NODESTFOG, From 1a356dfa51d929d67ab844f68c34f50ff2da8ba1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Jan 2016 14:53:56 -0600 Subject: [PATCH 03/15] Fixed: MIDI meta events were completely discarded, including their delays (unless the event was for setting the tempo) This left the following events in the track to happen at the wrong time. --- src/sound/music_smf_midiout.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 43755eb08..6284c504b 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -661,6 +661,16 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr events[2] = (MEVT_TEMPO << 24) | Tempo; events += 3; break; + + default: + if (delay != 0) + { + events[0] = delay; + events[1] = 0; + events[2] = MEVT_NOP << 24; + events += 3; + } + break; } track->TrackP += len; if (track->TrackP == track->MaxTrackP) From 7f6b421e87972904434c4551863e593fd42b49b5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Jan 2016 18:00:48 -0600 Subject: [PATCH 04/15] Make sure all unhandled delayed MIDI events generate NOPs - Looking over the code again, I see that discarded SysEx messages can cause the same issue as unhandled meta events, so generalize the returning of a NOP for everything. --- src/sound/music_smf_midiout.cpp | 38 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 6284c504b..918639399 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -384,6 +384,11 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr event = track->TrackBegin[track->TrackP++]; CHECK_FINISHED + // The actual event type will be filled in below. + events[0] = delay; + events[1] = 0; + events[2] = MEVT_NOP << 24; + if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND) { // Normal short message @@ -582,17 +587,10 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr break; } } - events[0] = delay; - events[1] = 0; if (event != MIDI_META && (!track->Designated || (track->Designation & DesignationMask))) { events[2] = event | (data1<<8) | (data2<<16); } - else - { - events[2] = MEVT_NOP << 24; - } - events += 3; } else { @@ -612,8 +610,6 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr } else { - events[0] = delay; - events[1] = 0; BYTE *msg = (BYTE *)&events[3]; if (event == MIDI_SYSEX) { // Need to add the SysEx marker to the message. @@ -631,7 +627,6 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr { *msg++ = 0; } - events = (DWORD *)msg; track->TrackP += len; } } @@ -659,17 +654,6 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr events[0] = delay; events[1] = 0; events[2] = (MEVT_TEMPO << 24) | Tempo; - events += 3; - break; - - default: - if (delay != 0) - { - events[0] = delay; - events[1] = 0; - events[2] = MEVT_NOP << 24; - events += 3; - } break; } track->TrackP += len; @@ -688,6 +672,18 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr { track->Delay = track->ReadVarLen(); } + // Advance events pointer unless this is a non-delaying NOP. + if (events[0] != 0 || MEVT_EVENTTYPE(events[2]) != MEVT_NOP) + { + if (MEVT_EVENTTYPE(events[2]) == MEVT_LONGMSG) + { + events += 3 + ((MEVT_EVENTPARM(events[2]) + 3) >> 2); + } + else + { + events += 3; + } + } return events; } From 710fa552887ed4dd49b5c35ae3e597b8f34e25bd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Jan 2016 18:37:05 -0600 Subject: [PATCH 05/15] Port recent SMF changes to XMI and HMI: - Handle SysEx messages instead of ignoring them. - Don't lose time for unhandled events with delays. --- src/sound/i_musicinterns.h | 10 ++--- src/sound/music_hmi_midiout.cpp | 75 +++++++++++++++++++++++++++------ src/sound/music_xmi_midiout.cpp | 73 +++++++++++++++++++++++++++----- 3 files changed, 128 insertions(+), 30 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 52364ab58..ccbab55f7 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -600,9 +600,9 @@ public: protected: void Heapify(); - unsigned int Parent(unsigned int i) { return (i + 1u) / 2u - 1u; } - unsigned int Left(unsigned int i) { return (i + 1u) * 2u - 1u; } - unsigned int Right(unsigned int i) { return (i + 1u) * 2u; } + unsigned int Parent(unsigned int i) const { return (i + 1u) / 2u - 1u; } + unsigned int Left(unsigned int i) const { return (i + 1u) * 2u - 1u; } + unsigned int Right(unsigned int i) const { return (i + 1u) * 2u; } }; class HMISong : public MIDIStreamer @@ -630,7 +630,7 @@ protected: struct TrackInfo; void ProcessInitialMetaEvents (); - DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay); + DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom); TrackInfo *FindNextDue (); static DWORD ReadVarLenHMI(TrackInfo *); @@ -673,7 +673,7 @@ protected: void AdvanceSong(DWORD time); void ProcessInitialMetaEvents(); - DWORD *SendCommand (DWORD *event, EventSource track, DWORD delay); + DWORD *SendCommand (DWORD *event, EventSource track, DWORD delay, ptrdiff_t room, bool &sysex_noroom); EventSource FindNextDue(); BYTE *MusHeader; diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index ca3ae0905..1796b1372 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -523,7 +523,12 @@ DWORD *HMISong::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) // Play all events for this tick. do { - DWORD *new_events = SendCommand(events, TrackDue, time); + bool sysex_noroom = false; + DWORD *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom); + if (sysex_noroom) + { + return events; + } TrackDue = FindNextDue(); if (new_events != events) { @@ -568,7 +573,7 @@ void HMISong::AdvanceTracks(DWORD time) // //========================================================================== -DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) +DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom) { DWORD len; BYTE event, data1 = 0, data2 = 0; @@ -584,10 +589,20 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) return events + 3; } + sysex_noroom = false; + size_t start_p = track->TrackP; + CHECK_FINISHED event = track->TrackBegin[track->TrackP++]; CHECK_FINISHED + // The actual event type will be filled in below. If it's not a NOP, + // the events pointer will be advanced once the actual event is written. + // Otherwise, we do it at the end of the function. + events[0] = delay; + events[1] = 0; + events[2] = MEVT_NOP << 24; + if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND && event != 0xFe) { // Normal short message @@ -626,17 +641,10 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) data2 = VolumeControllerChange(event & 15, data2); } - events[0] = delay; - events[1] = 0; if (event != MIDI_META) { events[2] = event | (data1<<8) | (data2<<16); } - else - { - events[2] = MEVT_NOP << 24; - } - events += 3; if (ReadVarLen == ReadVarLenHMI && (event & 0x70) == (MIDI_NOTEON & 0x70)) { // HMI note on events include the time until an implied note off event. @@ -645,13 +653,41 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) } else { - // Skip SysEx events just because I don't want to bother with them. - // The old MIDI player ignored them too, so this won't break - // anything that played before. + // SysEx events could potentially not have enough room in the buffer... if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { len = ReadVarLen(track); - track->TrackP += len; + if (len >= (MAX_EVENTS-1)*3*4) + { // This message will never fit. Throw it away. + track->TrackP += len; + } + else if (len + 12 >= (size_t)room * 4) + { // Not enough room left in this buffer. Backup and wait for the next one. + track->TrackP = start_p; + sysex_noroom = true; + return events; + } + else + { + BYTE *msg = (BYTE *)&events[3]; + if (event == MIDI_SYSEX) + { // Need to add the SysEx marker to the message. + events[2] = (MEVT_LONGMSG << 24) | (len + 1); + *msg++ = MIDI_SYSEX; + } + else + { + events[2] = (MEVT_LONGMSG << 24) | len; + } + memcpy(msg, &track->TrackBegin[track->TrackP], len); + msg += len; + // Must pad with 0 + while ((size_t)msg & 3) + { + *msg++ = 0; + } + track->TrackP += len; + } } else if (event == MIDI_META) { @@ -677,7 +713,6 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) events[0] = delay; events[1] = 0; events[2] = (MEVT_TEMPO << 24) | Tempo; - events += 3; break; } track->TrackP += len; @@ -720,6 +755,18 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) { track->Delay = ReadVarLen(track); } + // Advance events pointer unless this is a non-delaying NOP. + if (events[0] != 0 || MEVT_EVENTTYPE(events[2]) != MEVT_NOP) + { + if (MEVT_EVENTTYPE(events[2]) == MEVT_LONGMSG) + { + events += 3 + ((MEVT_EVENTPARM(events[2]) + 3) >> 2); + } + else + { + events += 3; + } + } return events; } diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 71246f518..fbbf4db53 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -337,7 +337,12 @@ DWORD *XMISong::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) // Play all events for this tick. do { - DWORD *new_events = SendCommand(events, EventDue, time); + bool sysex_noroom = false; + DWORD *new_events = SendCommand(events, EventDue, time, max_event_p - events, sysex_noroom); + if (sysex_noroom) + { + return events; + } EventDue = FindNextDue(); if (new_events != events) { @@ -382,7 +387,7 @@ void XMISong::AdvanceSong(DWORD time) // //========================================================================== -DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay) +DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay, ptrdiff_t room, bool &sysex_noroom) { DWORD len; BYTE event, data1 = 0, data2 = 0; @@ -399,10 +404,20 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay) TrackInfo *track = CurrSong; + sysex_noroom = false; + size_t start_p = track->EventP; + CHECK_FINISHED event = track->EventChunk[track->EventP++]; CHECK_FINISHED + // The actual event type will be filled in below. If it's not a NOP, + // the events pointer will be advanced once the actual event is written. + // Otherwise, we do it at the end of the function. + events[0] = delay; + events[1] = 0; + events[2] = MEVT_NOP << 24; + if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND) { // Normal short message @@ -499,10 +514,6 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay) { events[2] = event | (data1<<8) | (data2<<16); } - else - { - events[2] = MEVT_NOP << 24; - } events += 3; @@ -513,13 +524,41 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay) } else { - // Skip SysEx events just because I don't want to bother with them. - // The old MIDI player ignored them too, so this won't break - // anything that played before. + // SysEx events could potentially not have enough room in the buffer... if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { - len = track->ReadVarLen (); - track->EventP += len; + len = track->ReadVarLen(); + if (len >= (MAX_EVENTS-1)*3*4) + { // This message will never fit. Throw it away. + track->EventP += len; + } + else if (len + 12 >= (size_t)room * 4) + { // Not enough room left in this buffer. Backup and wait for the next one. + track->EventP = start_p; + sysex_noroom = true; + return events; + } + else + { + BYTE *msg = (BYTE *)&events[3]; + if (event == MIDI_SYSEX) + { // Need to add the SysEx marker to the message. + events[2] = (MEVT_LONGMSG << 24) | (len + 1); + *msg++ = MIDI_SYSEX; + } + else + { + events[2] = (MEVT_LONGMSG << 24) | len; + } + memcpy(msg, &track->EventChunk[track->EventP++], len); + msg += len; + // Must pad with 0 + while ((size_t)msg & 3) + { + *msg++ = 0; + } + track->EventP += len; + } } else if (event == MIDI_META) { @@ -551,6 +590,18 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay) { track->Delay = track->ReadDelay(); } + // Advance events pointer unless this is a non-delaying NOP. + if (events[0] != 0 || MEVT_EVENTTYPE(events[2]) != MEVT_NOP) + { + if (MEVT_EVENTTYPE(events[2]) == MEVT_LONGMSG) + { + events += 3 + ((MEVT_EVENTPARM(events[2]) + 3) >> 2); + } + else + { + events += 3; + } + } return events; } From 09733d808348ebc4d2e70be59cb86af60483862e Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 20 Jan 2016 18:50:30 -0600 Subject: [PATCH 06/15] - Don't set both self and pointer's z to spotz when teleporting. --- src/thingdef/thingdef_codeptr.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6a33bf595..e9d85686b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4380,7 +4380,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) } ref->SetZ((flags & TF_USESPOTZ) ? spot->Z() : ref->floorz, false); - self->SetZ((flags & TF_USESPOTZ) ? spot->Z() : self->floorz, false); if (!(flags & TF_KEEPANGLE)) ref->angle = spot->angle; From 03d7418f51ac6016ea0b0ccf24a7b16475651ad2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Jan 2016 10:23:20 +0100 Subject: [PATCH 07/15] - fixed: Since sector movement is done after P_PlayerThink is called, any player position change induced by this is not factored into player_t::viewz and needs to be added explicitly. This fixes the infamous 'view squats down a bit when riding up an elevator' effect. It is also there in the other cases but far less pronounced. --- src/p_map.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index 43c7f6af0..d096beb0d 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5268,6 +5268,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) { fixed_t oldfloorz = thing->floorz; + fixed_t oldz = thing->Z(); P_AdjustFloorCeil(thing, cpos); @@ -5297,6 +5298,10 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) P_CheckFakeFloorTriggers(thing, oldz); } } + if (thing->player && thing->player->mo == thing) + { + thing->player->viewz += thing->Z() - oldz; + } } //============================================================================= @@ -5348,6 +5353,10 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) thing->SetZ(oldz); break; } + if (thing->player && thing->player->mo == thing) + { + thing->player->viewz += thing->Z() - oldz; + } } //============================================================================= @@ -5359,6 +5368,7 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) { bool onfloor; + fixed_t oldz = thing->Z(); onfloor = thing->Z() <= thing->floorz; P_AdjustFloorCeil(thing, cpos); @@ -5395,6 +5405,10 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) break; } } + if (thing->player && thing->player->mo == thing) + { + thing->player->viewz += thing->Z() - oldz; + } } //============================================================================= @@ -5406,6 +5420,7 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) { bool isgood = P_AdjustFloorCeil(thing, cpos); + fixed_t oldz = thing->Z(); if (thing->flags4 & MF4_ACTLIKEBRIDGE) return; // do not move bridge things @@ -5432,6 +5447,10 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) thing->SetZ( MIN(thing->ceilingz - thing->height, onmobj->Top())); } } + if (thing->player && thing->player->mo == thing) + { + thing->player->viewz += thing->Z() - oldz; + } } //============================================================================= From d347415aee61d6509240719e540c2423614ffff1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Jan 2016 11:36:37 +0100 Subject: [PATCH 08/15] - fixed some garbage collection issues with interpolations: * FInterpolator depended on external references to prevent its content from getting GC'd. * none of the pointers in the interpolation objects were declared to the GC. The result of these issues was that changing anything about the life cycle of interpolation objects caused corrupted memory crashes when a level was changed. --- src/dobject.h | 5 +++++ src/dobjgc.cpp | 1 + src/p_setup.cpp | 2 +- src/r_data/r_interpolate.cpp | 32 +++++++++++++++++++++----------- src/r_data/r_interpolate.h | 7 ++++--- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 40b47ee5c..74371c0d6 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -203,6 +203,11 @@ private: \ #define IMPLEMENT_ABSTRACT_CLASS(cls) \ _IMP_PCLASS(cls,NULL,NULL) +#define IMPLEMENT_ABSTRACT_POINTY_CLASS(cls) \ + _IMP_PCLASS(cls,cls::PointerOffsets,NULL) \ + const size_t cls::PointerOffsets[] = { + + enum EObjectFlags { // GC flags diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 3812c0b08..2efb5a15e 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -335,6 +335,7 @@ static void MarkRoot() SectorMarker->SecNum = 0; } Mark(SectorMarker); + Mark(interpolator.Head); // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 3749e97aa..c915c31ec 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3353,6 +3353,7 @@ extern polyblock_t **PolyBlockMap; void P_FreeLevelData () { + interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level. Renderer->CleanLevelData(); FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. SN_StopAllSequences (); @@ -3584,7 +3585,6 @@ void P_SetupLevel (const char *lumpname, int position) // Free all level data from the previous map P_FreeLevelData (); - interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level. MapData *map = P_OpenMapData(lumpname, true); if (map == NULL) diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 3ca3b557c..268dd4aa0 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -157,7 +157,10 @@ public: // //========================================================================== -IMPLEMENT_ABSTRACT_CLASS(DInterpolation) +IMPLEMENT_ABSTRACT_POINTY_CLASS(DInterpolation) +DECLARE_POINTER(Next) +DECLARE_POINTER(Prev) +END_POINTERS IMPLEMENT_CLASS(DSectorPlaneInterpolation) IMPLEMENT_CLASS(DSectorScrollInterpolation) IMPLEMENT_CLASS(DWallScrollInterpolation) @@ -213,9 +216,9 @@ void FInterpolator::UpdateInterpolations() void FInterpolator::AddInterpolation(DInterpolation *interp) { interp->Next = Head; - if (Head != NULL) Head->Prev = &interp->Next; + if (Head != NULL) Head->Prev = interp; + interp->Prev = NULL; Head = interp; - interp->Prev = &Head; count++; } @@ -227,14 +230,19 @@ void FInterpolator::AddInterpolation(DInterpolation *interp) void FInterpolator::RemoveInterpolation(DInterpolation *interp) { - if (interp->Prev != NULL) + if (Head == interp) { - *interp->Prev = interp->Next; - if (interp->Next != NULL) interp->Next->Prev = interp->Prev; - interp->Next = NULL; - interp->Prev = NULL; - count--; + Head = interp->Next; + if (Head != NULL) Head->Prev = NULL; } + else + { + if (interp->Prev != NULL) interp->Prev->Next = interp->Next; + if (interp->Next != NULL) interp->Next->Prev = interp->Prev; + } + interp->Next = NULL; + interp->Prev = NULL; + count--; } //========================================================================== @@ -285,13 +293,15 @@ void FInterpolator::RestoreInterpolations() void FInterpolator::ClearInterpolations() { - for (DInterpolation *probe = Head; probe != NULL; ) + DInterpolation *probe = Head; + Head = NULL; + while (probe != NULL) { DInterpolation *next = probe->Next; + probe->Next = probe->Prev = NULL; probe->Destroy(); probe = next; } - Head = NULL; } diff --git a/src/r_data/r_interpolate.h b/src/r_data/r_interpolate.h index bbd2438d8..9f28b04d0 100644 --- a/src/r_data/r_interpolate.h +++ b/src/r_data/r_interpolate.h @@ -13,9 +13,10 @@ class DInterpolation : public DObject friend struct FInterpolator; DECLARE_ABSTRACT_CLASS(DInterpolation, DObject) + HAS_OBJECT_POINTERS - DInterpolation *Next; - DInterpolation **Prev; + TObjPtr Next; + TObjPtr Prev; int refcount; protected: @@ -40,7 +41,7 @@ public: struct FInterpolator { - DInterpolation *Head; + TObjPtr Head; bool didInterp; int count; From cf2ee1eb3f31178095e5483ce28a9364cb8c2312 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Jan 2016 11:58:44 +0100 Subject: [PATCH 09/15] - fixed: Interpolations were deleted too early. They were immediately deleted when the associated thinker was destroyed. But this was too early because it missed the final tic of movement, resulting in a visible jump when a moving platform with a player on it came to a halt. Changed it so that DelRef no longer destroys the interpolation itself. Instead the ::Interpolate method will check if the reference count is 0, and if so and there was no more movement, will then destroy the interpolation. This ensures that it keeps running until it has interpolated all remaining bits of movement induced by the thinker. Now moving up a lift is 100% smooth, even with movement interpolation on. --- src/r_data/r_interpolate.cpp | 65 ++++++++++++++++++++++++++---------- src/r_data/r_interpolate.h | 3 +- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index 268dd4aa0..c46e17f9c 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -344,10 +344,6 @@ int DInterpolation::AddRef() int DInterpolation::DelRef() { if (refcount > 0) --refcount; - if (refcount <= 0 && !(ObjectFlags & OF_EuthanizeMe)) - { - Destroy(); - } return refcount; } @@ -496,9 +492,16 @@ void DSectorPlaneInterpolation::Interpolate(fixed_t smoothratio) bakheight = *pheight; baktexz = sector->GetPlaneTexZ(pos); - *pheight = oldheight + FixedMul(bakheight - oldheight, smoothratio); - sector->SetPlaneTexZ(pos, oldtexz + FixedMul(baktexz - oldtexz, smoothratio)); - P_RecalculateAttached3DFloors(sector); + if (refcount == 0 && oldheight == bakheight) + { + Destroy(); + } + else + { + *pheight = oldheight + FixedMul(bakheight - oldheight, smoothratio); + sector->SetPlaneTexZ(pos, oldtexz + FixedMul(baktexz - oldtexz, smoothratio)); + P_RecalculateAttached3DFloors(sector); + } } //========================================================================== @@ -622,8 +625,15 @@ void DSectorScrollInterpolation::Interpolate(fixed_t smoothratio) bakx = sector->GetXOffset(ceiling); baky = sector->GetYOffset(ceiling, false); - sector->SetXOffset(ceiling, oldx + FixedMul(bakx - oldx, smoothratio)); - sector->SetYOffset(ceiling, oldy + FixedMul(baky - oldy, smoothratio)); + if (refcount == 0 && oldx == bakx && oldy == baky) + { + Destroy(); + } + else + { + sector->SetXOffset(ceiling, oldx + FixedMul(bakx - oldx, smoothratio)); + sector->SetYOffset(ceiling, oldy + FixedMul(baky - oldy, smoothratio)); + } } //========================================================================== @@ -706,8 +716,15 @@ void DWallScrollInterpolation::Interpolate(fixed_t smoothratio) bakx = side->GetTextureXOffset(part); baky = side->GetTextureYOffset(part); - side->SetTextureXOffset(part, oldx + FixedMul(bakx - oldx, smoothratio)); - side->SetTextureYOffset(part, oldy + FixedMul(baky - oldy, smoothratio)); + if (refcount == 0 && oldx == bakx && oldy == baky) + { + Destroy(); + } + else + { + side->SetTextureXOffset(part, oldx + FixedMul(bakx - oldx, smoothratio)); + side->SetTextureYOffset(part, oldy + FixedMul(baky - oldy, smoothratio)); + } } //========================================================================== @@ -798,6 +815,7 @@ void DPolyobjInterpolation::Restore() void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) { + bool changed = false; for(unsigned int i = 0; i < poly->Vertices.Size(); i++) { fixed_t *px = &poly->Vertices[i]->x; @@ -806,15 +824,26 @@ void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) bakverts[i*2 ] = *px; bakverts[i*2+1] = *py; - *px = oldverts[i*2 ] + FixedMul(bakverts[i*2 ] - oldverts[i*2 ], smoothratio); - *py = oldverts[i*2+1] + FixedMul(bakverts[i*2+1] - oldverts[i*2+1], smoothratio); + if (bakverts[i * 2] != oldverts[i * 2] || bakverts[i * 2 + i] != oldverts[i * 2 + 1]) + { + changed = true; + *px = oldverts[i * 2] + FixedMul(bakverts[i * 2] - oldverts[i * 2], smoothratio); + *py = oldverts[i * 2 + 1] + FixedMul(bakverts[i * 2 + 1] - oldverts[i * 2 + 1], smoothratio); + } } - bakcx = poly->CenterSpot.x; - bakcy = poly->CenterSpot.y; - poly->CenterSpot.x = bakcx + FixedMul(bakcx - oldcx, smoothratio); - poly->CenterSpot.y = bakcy + FixedMul(bakcy - oldcy, smoothratio); + if (refcount == 0 && !changed) + { + Destroy(); + } + else + { + bakcx = poly->CenterSpot.x; + bakcy = poly->CenterSpot.y; + poly->CenterSpot.x = bakcx + FixedMul(bakcx - oldcx, smoothratio); + poly->CenterSpot.y = bakcy + FixedMul(bakcy - oldcy, smoothratio); - poly->ClearSubsectorLinks(); + poly->ClearSubsectorLinks(); + } } //========================================================================== diff --git a/src/r_data/r_interpolate.h b/src/r_data/r_interpolate.h index 9f28b04d0..29e8a6171 100644 --- a/src/r_data/r_interpolate.h +++ b/src/r_data/r_interpolate.h @@ -17,9 +17,10 @@ class DInterpolation : public DObject TObjPtr Next; TObjPtr Prev; - int refcount; protected: + int refcount; + DInterpolation(); public: From 5421213711d65cf7ab8ae50478e0499d42c04129 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Jan 2016 12:37:26 +0100 Subject: [PATCH 10/15] - typo in interpolation stuff. --- src/r_data/r_interpolate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index c46e17f9c..d153b3a78 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -824,7 +824,7 @@ void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) bakverts[i*2 ] = *px; bakverts[i*2+1] = *py; - if (bakverts[i * 2] != oldverts[i * 2] || bakverts[i * 2 + i] != oldverts[i * 2 + 1]) + if (bakverts[i * 2] != oldverts[i * 2] || bakverts[i * 2 + 1] != oldverts[i * 2 + 1]) { changed = true; *px = oldverts[i * 2] + FixedMul(bakverts[i * 2] - oldverts[i * 2], smoothratio); From 673ac1295ca5492f4d029968e7b881bb6a230a59 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 21 Jan 2016 15:53:35 +0200 Subject: [PATCH 11/15] Fixed broken 'closedialog' property in Strife dialogs See http://forum.zdoom.org/viewtopic.php?t=50524 --- src/p_conversation.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a74b9bd18..7b7355181 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1345,20 +1345,24 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (reply->NextNode != 0) { int rootnode = npc->ConversationRoot; - unsigned next = (unsigned)(rootnode + (reply->NextNode < 0 ? -1 : 1) * reply->NextNode - 1); + const bool isNegative = reply->NextNode < 0; + const unsigned next = (unsigned)(rootnode + (isNegative ? -1 : 1) * reply->NextNode - 1); if (next < StrifeDialogues.Size()) { npc->Conversation = StrifeDialogues[next]; - if (gameaction != ga_slideshow) + if (isNegative) { - P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); - return; - } - else - { - S_StopSound (npc, CHAN_VOICE); + if (gameaction != ga_slideshow) + { + P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); + return; + } + else + { + S_StopSound (npc, CHAN_VOICE); + } } } } From 598bccbe9347cb8065faf07711dc9240651bbf95 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 21 Jan 2016 15:53:58 +0200 Subject: [PATCH 12/15] Added warning when next dialog page is incorrect --- src/p_conversation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 7b7355181..ab6cf5883 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1365,6 +1365,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } } + else + { + Printf ("Next node %u is invalid, no such dialog page\n", next); + } } npc->angle = player->ConversationNPCAngle; From 68fcbc0c92a5ea4c3f402a4e7f73397651f10d6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Jan 2016 14:54:14 +0100 Subject: [PATCH 13/15] - fixed: loading sector damage information from an old savegame could retrieve invalid data due to an uninitialized variable. --- src/p_sectors.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 83adc438f..8ee5c280b 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -878,6 +878,7 @@ FArchive &operator<< (FArchive &arc, secspecial_t &p) int special; arc << special; sector_t sec; + memset(&sec, 0, sizeof(sec)); P_InitSectorSpecial(&sec, special, true); sec.GetSpecial(&p); } From f10dd68ca6d917907e65e77fea9b5b34532d166b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 21 Jan 2016 16:21:09 +0200 Subject: [PATCH 14/15] Fixed actors intersection check --- src/actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index 3a474bc6f..a9bd60f75 100644 --- a/src/actor.h +++ b/src/actor.h @@ -881,7 +881,7 @@ public: bool intersects(AActor *other) const { fixed_t blockdist = radius + other->radius; - return ( abs(X() - other->Y()) < blockdist && abs(Y() - other->Y()) < blockdist); + return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist); } // 'absolute' is reserved for a linked portal implementation which needs From d190da9e2e51ecb4371d80fa2b288749e0436476 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Jan 2016 12:03:52 -0600 Subject: [PATCH 15/15] Silence pointer truncation warnings in Ppmd7.c --- lzma/C/Ppmd7.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lzma/C/Ppmd7.c b/lzma/C/Ppmd7.c index 7ef84d47b..abd7e6309 100644 --- a/lzma/C/Ppmd7.c +++ b/lzma/C/Ppmd7.c @@ -276,12 +276,12 @@ static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU return oldPtr; } -#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) +#define SUCCESSOR(p) ((CPpmd_Void_Ref)(size_t)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) { - (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); - (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); + (p)->SuccessorLow = (UInt16)((UInt32)((size_t)v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)((size_t)v) >> 16) & 0xFFFF); } static void RestartModel(CPpmd7 *p)