Added haptic bindings
This commit is contained in:
parent
f573112e2a
commit
848df46ee0
8 changed files with 224 additions and 12 deletions
|
|
@ -32,6 +32,8 @@ enum EChanFlag
|
|||
CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood)
|
||||
CHANF_FORCE = 65536, // Start, even if sound is paused.
|
||||
CHANF_SINGULAR = 0x20000, // Only start if no sound of this name is already playing.
|
||||
CHANF_RUMBLE = 0x40000, // Hint to rumble trigger rumble from sound
|
||||
CHANF_NORUMBLE = 0x80000, // Disable rumble even if it would normally happen
|
||||
};
|
||||
|
||||
typedef TFlags<EChanFlag> EChanFlags;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "c_cvars.h"
|
||||
#include "gamestate.h"
|
||||
#include "i_soundinternal.h"
|
||||
#include "m_haptics.h"
|
||||
#include "m_random.h"
|
||||
#include "m_swap.h"
|
||||
#include "printf.h"
|
||||
|
|
@ -475,6 +476,11 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
// Attenuate the attenuation based on the sound.
|
||||
attenuation *= sfx->Attenuation;
|
||||
|
||||
#if 0
|
||||
// sound debug printout
|
||||
Printf("sound: '%s' -> '%s' %g\n", soundEngine->GetSoundName(org_id), soundEngine->GetSoundName(sound_id), attenuation);
|
||||
#endif
|
||||
|
||||
// The passed rolloff overrides any sound-specific rolloff.
|
||||
if (forcedrolloff != NULL && forcedrolloff->MinDistance != 0)
|
||||
{
|
||||
|
|
@ -608,6 +614,14 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
{
|
||||
chanflags |= CHANF_LISTENERZ | CHANF_JUSTSTARTED;
|
||||
}
|
||||
if (chanflags & CHANF_RUMBLE && !(chanflags & CHANF_NORUMBLE))
|
||||
{
|
||||
// I would love to use attenuation here, but it seems weird.
|
||||
// Pistol's attenuation is always 1, but it's not silent.
|
||||
// I'm not sure why that is.
|
||||
// Joy_Rumble(soundEngine->GetSoundName(org_id), (chanflags&CHANF_IS3D)? attenuation: 0);
|
||||
Joy_Rumble(soundEngine->GetSoundName(org_id));
|
||||
}
|
||||
if (chan != NULL)
|
||||
{
|
||||
chan->SoundID = sound_id;
|
||||
|
|
|
|||
|
|
@ -30,20 +30,19 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_haptics.h"
|
||||
#include "name.h"
|
||||
#include "printf.h"
|
||||
#include "s_soundinternal.h"
|
||||
#include "tarray.h"
|
||||
#include "vm.h"
|
||||
#include "zstring.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#ifndef MAX_TRY_DEPTH
|
||||
#define MAX_TRY_DEPTH 8
|
||||
#endif
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
|
@ -379,3 +378,172 @@ void Joy_Rumble(const FName identifier, double attenuation)
|
|||
|
||||
Joy_Rumble(identifier, * rumble, attenuation);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// rumble
|
||||
//
|
||||
// test command
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD (rumble)
|
||||
{
|
||||
int count = argv.argc()-1;
|
||||
int ticks;
|
||||
double high_freq, low_freq, left_trig, right_trig;
|
||||
|
||||
switch (count) {
|
||||
case 0: {
|
||||
TArray<FString> unused, used;
|
||||
|
||||
{
|
||||
TMapIterator<FName, struct Haptics> it(RumbleDefinition);
|
||||
TMap<FName, struct Haptics>::Pair* pair;
|
||||
while (it.NextPair(pair)) unused.AddUnique(pair->Key.GetChars());
|
||||
}
|
||||
{
|
||||
TMapIterator<FName, FName> it(RumbleAlias);
|
||||
TMap<FName, FName>::Pair* pair;
|
||||
while (it.NextPair(pair)) unused.AddUnique(pair->Key.GetChars());
|
||||
}
|
||||
{
|
||||
TMapIterator<FName, FName> it(RumbleAlias);
|
||||
TMap<FName, FName>::Pair* pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (unused.Contains(pair->Value.GetChars()))
|
||||
unused.Delete(unused.Find(pair->Value.GetChars()));
|
||||
}
|
||||
}
|
||||
{
|
||||
TMapIterator<FName, FName> it(RumbleMapping);
|
||||
TMap<FName, FName>::Pair* pair;
|
||||
Printf("Mappings:\n");
|
||||
while (it.NextPair(pair)) {
|
||||
used.AddUnique(pair->Value.GetChars());
|
||||
if (unused.Contains(pair->Value.GetChars()))
|
||||
unused.Delete(unused.Find(pair->Value.GetChars()));
|
||||
auto mapping = Joy_GetRumble(pair->Value);
|
||||
FString key = pair->Key.GetChars();
|
||||
FString val = pair->Value.GetChars();
|
||||
key.ToLower();
|
||||
val.ToUpper();
|
||||
FString a = FStringf("'%s'\t->\t'%s'", key.GetChars(), val.GetChars());
|
||||
FString b = mapping
|
||||
? FStringf(
|
||||
"{ %d %g %g %g %g }",
|
||||
mapping->ticks,
|
||||
mapping->high_frequency,
|
||||
mapping->low_frequency,
|
||||
mapping->left_trigger,
|
||||
mapping->right_trigger
|
||||
) : "[undefined]";
|
||||
Printf("\t%s\t->\t%s\n", a.GetChars(), b.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (unused.Size() > 0)
|
||||
{
|
||||
Printf("Unused:\n");
|
||||
for (auto i:unused)
|
||||
{
|
||||
FString s = i.GetChars();
|
||||
s.ToUpper();
|
||||
Printf("\t'%s'\n", s.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
Printf("Testing rumble for 5s\n");
|
||||
Joy_Rumble("", {5 * TICRATE, 1.0, 1.0, 1.0, 1.0});
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
Printf("Testing rumble for action '%s'\n", argv[1]);
|
||||
Joy_Rumble(argv[1]);
|
||||
break;
|
||||
case 5:
|
||||
try {
|
||||
ticks = std::stoi(argv[1], nullptr, 10);
|
||||
high_freq = static_cast <double> (std::stof(argv[2], nullptr));
|
||||
low_freq = static_cast <double> (std::stof(argv[3], nullptr));
|
||||
left_trig = static_cast <double> (std::stof(argv[4], nullptr));
|
||||
right_trig = static_cast <double> (std::stof(argv[5], nullptr));
|
||||
} catch (...) {
|
||||
Printf("Failed to parse args\n");
|
||||
return;
|
||||
}
|
||||
Printf("testing rumble with params (%d, %f, %f, %f, %f)\n", ticks, high_freq, low_freq, left_trig, right_trig);
|
||||
Joy_Rumble("", {ticks, high_freq, low_freq, left_trig, right_trig});
|
||||
break;
|
||||
default:
|
||||
Printf(
|
||||
"usage:\n %s\n %s\n %s\n",
|
||||
"rumble",
|
||||
"rumble string_id",
|
||||
"rumble int_duration float_high_freq float_low_freq float_left_trig float_right_trigger"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// _Rumble
|
||||
//
|
||||
// VM wrapper for Joy_Rumble
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void _Rumble(const int identifier) {
|
||||
Joy_Rumble(ENamedName(identifier));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Rumble
|
||||
//
|
||||
// VM function for named Joy_Rumble
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DHaptics, Rumble, _Rumble)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(identifier);
|
||||
_Rumble(ENamedName(identifier));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// _RumbleDirect
|
||||
//
|
||||
// VM wrapper for Joy_Rumble
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void _RumbleDirect(int source, int tic_count, double high_frequency, double low_frequency, double left_trigger, double right_trigger) {
|
||||
Joy_Rumble(ENamedName(source), {tic_count, high_frequency, low_frequency, left_trigger, right_trigger});
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Rumble
|
||||
//
|
||||
// VM function for direct Joy_Rumble
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DHaptics, RumbleDirect, _RumbleDirect)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(source);
|
||||
PARAM_INT(tic_count);
|
||||
PARAM_FLOAT(high_frequency);
|
||||
PARAM_FLOAT(low_frequency);
|
||||
PARAM_FLOAT(left_trigger);
|
||||
PARAM_FLOAT(right_trigger);
|
||||
_RumbleDirect(source, tic_count, high_frequency, low_frequency, left_trigger, right_trigger);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
** Routines for managing SNDINFO lumps and ambient sounds
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** Copyright 2017-2025 GZDoom Maintainers and Contributors
|
||||
** All rights reserved.
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
** 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.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
|
@ -44,6 +46,7 @@
|
|||
#include "gi.h"
|
||||
#include "i_music.h"
|
||||
#include "i_sound.h"
|
||||
#include "m_haptics.h"
|
||||
#include "r_data/sprites.h"
|
||||
#include "s_music.h"
|
||||
#include "serializer.h"
|
||||
|
|
@ -350,7 +353,7 @@ void S_CheckIntegrity()
|
|||
}
|
||||
}
|
||||
|
||||
// Joy_ReadyRumbleMapping();
|
||||
Joy_ReadyRumbleMapping();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -578,7 +581,7 @@ void S_ClearSoundData()
|
|||
HexenMusic.Clear();
|
||||
ModPlayers.Clear();
|
||||
|
||||
// Joy_ResetRumbleMapping();
|
||||
Joy_ResetRumbleMapping();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -1156,7 +1159,7 @@ static void S_AddSNDINFO (int lump)
|
|||
if (isAlias)
|
||||
{
|
||||
sc.MustGetString();
|
||||
// Joy_AddRumbleAlias(identifier, FName(sc.String));
|
||||
Joy_AddRumbleAlias(identifier, FName(sc.String));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1171,10 +1174,10 @@ static void S_AddSNDINFO (int lump)
|
|||
sc.MustGetFloat();
|
||||
double right_trig = sc.Float;
|
||||
|
||||
// Joy_AddRumbleType(
|
||||
// identifier,
|
||||
// { duration, low_freq, high_freq, left_trig, right_trig, }
|
||||
// );
|
||||
Joy_AddRumbleType(
|
||||
identifier,
|
||||
{ duration, low_freq, high_freq, left_trig, right_trig, }
|
||||
);
|
||||
}
|
||||
|
||||
// if (sc.CheckToken(TK_IntConst))
|
||||
|
|
@ -1195,7 +1198,7 @@ static void S_AddSNDINFO (int lump)
|
|||
sc.MustGetString();
|
||||
FString mapping (sc.String);
|
||||
|
||||
// Joy_MapRumbleType(sound, mapping);
|
||||
Joy_MapRumbleType(sound, mapping);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
** 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.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
|
@ -511,6 +512,20 @@ void DoomSoundEngine::StopChannel(FSoundChan* chan)
|
|||
|
||||
void S_SoundPitchActor(AActor *ent, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, float pitch, float startTime)
|
||||
{
|
||||
#if 0
|
||||
// sound source debug printout
|
||||
Printf("sound '%s' from '%s'\n", soundEngine->GetSoundName(sound_id), ent->GetClass()->TypeName.GetChars());
|
||||
#endif
|
||||
|
||||
if (flags & CHANF_NORUMBLE)
|
||||
{
|
||||
// remove conflicting flag
|
||||
if (flags & CHANF_RUMBLE)
|
||||
{
|
||||
flags = (EChanFlag)(flags - CHANF_RUMBLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (VerifyActorSound(ent, sound_id, channel, flags))
|
||||
soundEngine->StartSound (SOURCE_Actor, ent, nullptr, channel, flags, sound_id, volume, attenuation, 0, pitch, startTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ version "4.15.1"
|
|||
#include "zscript/actors/shared/randomspawner.zs"
|
||||
#include "zscript/actors/shared/dynlights.zs"
|
||||
#include "zscript/actors/shared/corona.zs"
|
||||
#include "zscript/actors/shared/haptics.zs"
|
||||
|
||||
#include "zscript/actors/doom/doomplayer.zs"
|
||||
#include "zscript/actors/doom/possessed.zs"
|
||||
|
|
|
|||
5
wadsrc/static/zscript/actors/shared/haptics.zs
Normal file
5
wadsrc/static/zscript/actors/shared/haptics.zs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class Haptics
|
||||
{
|
||||
native static void RumbleDirect(int tic_count, float high_frequency, float low_frequency, float left_trigger, float right_trigger);
|
||||
native static void Rumble(Name identifier);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
** base.zs
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** Copyright 2016-2017 Christoph Oelckers
|
||||
** Copyright 2017-2025 GZDoom Maintainers and Contributors
|
||||
** All rights reserved.
|
||||
|
|
@ -28,6 +29,7 @@
|
|||
** 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.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
|
@ -67,6 +69,8 @@ enum ESoundFlags
|
|||
CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood)
|
||||
CHANF_FORCE = 65536, // Start, even if sound is paused.
|
||||
CHANF_SINGULAR = 0x20000, // Only start if no sound of this name is already playing.
|
||||
CHANF_RUMBLE = 0x40000, // Hint to rumble trigger rumble from sound
|
||||
CHANF_NORUMBLE = 0x80000, // Disable rumble even if it would normally happen
|
||||
|
||||
CHANF_LOOPING = CHANF_LOOP | CHANF_NOSTOP, // convenience value for replicating the old 'looping' boolean.
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue