Browse Source

Initial pass at getting subtitle support in. Doesn't compile for unknown reasons

tickets/38/38/1
ZarothYe 3 years ago
parent
commit
229883654e
  1. 2
      Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj
  2. 6
      Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj.filters
  3. 1
      Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj
  4. 3
      Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj.filters
  5. 1
      Sources/Plasma/Apps/plClient/plClient.cpp
  6. 5
      Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
  7. 32
      Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.cpp
  8. 1
      Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.h
  9. 16
      Sources/Plasma/FeatureLib/pfPython/pyAudioControl.cpp
  10. 5
      Sources/Plasma/FeatureLib/pfPython/pyAudioControl.h
  11. 11
      Sources/Plasma/FeatureLib/pfPython/pyAudioControlGlue.cpp
  12. 46
      Sources/Plasma/NucleusLib/inc/plCreatableIndex.h
  13. 2
      Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h
  14. 6
      Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.cpp
  15. 2
      Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.h
  16. 29
      Sources/Plasma/PubUtilLib/plAudio/plWin32Sound.cpp
  17. 27
      Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.cpp
  18. 4
      Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.h
  19. 192
      Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.cpp
  20. 105
      Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.h
  21. 4
      Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h
  22. 82
      Sources/Plasma/PubUtilLib/plMessage/plSubtitleMsg.h

2
Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj

@ -244,6 +244,7 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release_Internal|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release_Internal|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp" />
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.cpp"> <ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug_Internal|Win32'">Disabled</Optimization> <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug_Internal|Win32'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization> <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
@ -315,6 +316,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioFileReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plBufferedFileReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plBufferedFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plFastWavReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plFastWavReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundBuffer.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundBuffer.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundDeswizzler.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundDeswizzler.h" />

6
Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj.filters

@ -32,6 +32,9 @@
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.cpp"> <ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioCore.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioCore.h">
@ -61,5 +64,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

1
Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj

@ -817,6 +817,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSimStateMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSimStateMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnModMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnModMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnRequestMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnRequestMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSwimMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSwimMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSynchEnableMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSynchEnableMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plTimerCallbackMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plTimerCallbackMsg.h" />

3
Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj.filters

@ -361,5 +361,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plVaultNotifyMsg.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plVaultNotifyMsg.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

1
Sources/Plasma/Apps/plClient/plClient.cpp

@ -2313,6 +2313,7 @@ void plClient::IDetectAudioVideoSettings()
WriteInt(stream, "Audio.SetChannelVolume Ambience", 1); WriteInt(stream, "Audio.SetChannelVolume Ambience", 1);
WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1); WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1);
WriteInt(stream, "Audio.EnableVoiceRecording", 1); WriteInt(stream, "Audio.EnableVoiceRecording", 1);
WriteInt(stream, "Audio.EnableSubtitles", false);
WriteString(stream, "Audio.SetDeviceName", deviceName ); WriteString(stream, "Audio.SetDeviceName", deviceName );
stream->Close(); stream->Close();
delete stream; delete stream;

5
Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp

@ -3391,6 +3391,11 @@ PF_CONSOLE_CMD( Audio, MuteAll, "bool on", "Mute or unmute all sounds")
plgAudioSys::SetMuted( (bool)params[ 0 ] ); plgAudioSys::SetMuted( (bool)params[ 0 ] );
} }
PF_CONSOLE_CMD(Audio, EnableSubtitles, "bool on", "Enable or disable displaying subtitles for audio files containing speech")
{
plgAudioSys::SetEnableSubtitles((bool)params[0]);
}
PF_CONSOLE_CMD( Audio, SetDistanceModel, "int type", "Sets the distance model for all 3d sounds") PF_CONSOLE_CMD( Audio, SetDistanceModel, "int type", "Sets the distance model for all 3d sounds")
{ {
if(plgAudioSys::Sys()) if(plgAudioSys::Sys())

32
Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.cpp

@ -94,6 +94,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../pfGameMgr/pfGameMgr.h" #include "../pfGameMgr/pfGameMgr.h"
#include "../plMessage/plAIMsg.h" #include "../plMessage/plAIMsg.h"
#include "../plAvatar/plAvBrainCritter.h" #include "../plAvatar/plAvBrainCritter.h"
#include "../plMessage/plSubtitleMsg.h"
#include "plProfile.h" #include "plProfile.h"
@ -189,6 +190,7 @@ char* plPythonFileMod::fFunctionNames[] =
{ "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg { "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg
{ "OnGameCliMsg" }, // kfunc_OnGameCliMsg { "OnGameCliMsg" }, // kfunc_OnGameCliMsg
{ "OnAIMsg" }, // kfunc_OnAIMsg { "OnAIMsg" }, // kfunc_OnAIMsg
{ "OnSubtitleMsg" }, // kfunc_OnSubtitleMsg
{ nil } { nil }
}; };
@ -2780,6 +2782,36 @@ hsBool plPythonFileMod::MsgReceive(plMessage* msg)
} }
} }
if (fPyFunctionInstances[kfunc_OnSubtitleMsg])
{
plSubtitleMsg* pSubMsg = plSubtitleMsg::ConvertNoRef(msg);
if (pSubMsg)
{
plProfile_BeginTiming(PythonUpdate);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_OnSubtitleMsg], fFunctionNames[kfunc_OnSubtitleMsg],
"ss", pSubMsg->GetText(), pSubMsg->GetSpeaker());
if (retVal == nil)
{
#ifndef PLASMA_EXTERNAL_RELEASE
// for some reason this function didn't, remember that and not call it again
fPyFunctionInstances[kfunc_OnSubtitleMsg] = nil;
#endif //PLASMA_EXTERNAL_RELEASE
// if there was an error make sure that the stderr gets flushed so it can be seen
ReportError();
}
Py_XDECREF(retVal);
plProfile_EndTiming(PythonUpdate);
// display any output (NOTE: this would be disabled in production)
DisplayPythonOutput();
// we handled this message (I think)
return true;
}
}
return plModifier::MsgReceive(msg); return plModifier::MsgReceive(msg);
} }

1
Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.h

@ -202,6 +202,7 @@ public:
kfunc_OnGameMgrMsg, kfunc_OnGameMgrMsg,
kfunc_OnGameCliMsg, kfunc_OnGameCliMsg,
kfunc_OnAIMsg, kfunc_OnAIMsg,
kfunc_OnSubtitleMsg,
kfunc_lastone kfunc_lastone
}; };
// array of matching Python instance where the functions are, if defined // array of matching Python instance where the functions are, if defined

16
Sources/Plasma/FeatureLib/pfPython/pyAudioControl.cpp

@ -256,6 +256,22 @@ hsBool pyAudioControl::IsMuted()
return plgAudioSys::IsMuted(); return plgAudioSys::IsMuted();
} }
// Enable or disable displaying speech subtitles
void pyAudioControl::EnableSubtitles()
{
plgAudioSys::SetEnableSubtitles(true);
}
void pyAudioControl::DisableSubtitles()
{
plgAudioSys::SetEnableSubtitles(false);
}
bool pyAudioControl::AreSubtitlesEnabled() const
{
return plgAudioSys::AreSubtitlesEnabled();
}
hsBool pyAudioControl::SupportEAX(const char *deviceName) hsBool pyAudioControl::SupportEAX(const char *deviceName)
{ {
return plgAudioSys::SupportsEAX(deviceName); return plgAudioSys::SupportsEAX(deviceName);

5
Sources/Plasma/FeatureLib/pfPython/pyAudioControl.h

@ -109,6 +109,11 @@ public:
virtual void UnmuteAll(); virtual void UnmuteAll();
virtual hsBool IsMuted(); virtual hsBool IsMuted();
// Enable or disable displaying speech subtitles
void EnableSubtitles();
void DisableSubtitles();
bool AreSubtitlesEnabled() const;
virtual void SetAudioSystemMode(int mode); // sets the current mode virtual void SetAudioSystemMode(int mode); // sets the current mode
virtual int GetAudioSystemMode(); // returns the current mode virtual int GetAudioSystemMode(); // returns the current mode
virtual int GetHighestAudioMode(); // returns the highest mode the card is capable of handling virtual int GetHighestAudioMode(); // returns the highest mode the card is capable of handling

11
Sources/Plasma/FeatureLib/pfPython/pyAudioControlGlue.cpp

@ -242,6 +242,14 @@ PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, isMuted)
PYTHON_RETURN_BOOL(self->fThis->IsMuted()); PYTHON_RETURN_BOOL(self->fThis->IsMuted());
} }
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, enableSubtitles, EnableSubtitles)
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, disableSubtitles, DisableSubtitles)
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, areSubtitlesEnabled)
{
PYTHON_RETURN_BOOL(self->fThis->AreSubtitlesEnabled());
}
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, canSetMicLevel) PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, canSetMicLevel)
{ {
PYTHON_RETURN_BOOL(self->fThis->CanSetMicLevel()); PYTHON_RETURN_BOOL(self->fThis->CanSetMicLevel());
@ -484,6 +492,9 @@ PYTHON_START_METHODS_TABLE(ptAudioControl)
PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."), PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."),
PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."), PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."),
PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."), PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."),
PYTHON_BASIC_METHOD(ptAudioControl, enableSubtitles, "Enables audio subtitles."),
PYTHON_BASIC_METHOD(ptAudioControl, disableSubtitles, "Disables audio subtitles."),
PYTHON_METHOD_NOARGS(ptAudioControl, areSubtitlesEnabled, "Are audio subtitles enabled? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD_NOARGS(ptAudioControl, canSetMicLevel, "Can the microphone level be set? Returns 1 if true otherwise returns 0."), PYTHON_METHOD_NOARGS(ptAudioControl, canSetMicLevel, "Can the microphone level be set? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD(ptAudioControl, setMicLevel, "Params: level\nSets the microphone recording level (0.0 to 1.0)."), PYTHON_METHOD(ptAudioControl, setMicLevel, "Params: level\nSets the microphone recording level (0.0 to 1.0)."),
PYTHON_METHOD_NOARGS(ptAudioControl, getMicLevel, "Returns the microphone recording level (0.0 to 1.0)."), PYTHON_METHOD_NOARGS(ptAudioControl, getMicLevel, "Returns the microphone recording level (0.0 to 1.0)."),

46
Sources/Plasma/NucleusLib/inc/plCreatableIndex.h

@ -34,9 +34,9 @@ work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at: or by snail mail at:
Cyan Worlds, Inc. Cyan Worlds, Inc.
14617 N Newport Hwy 14617 N Newport Hwy
Mead, WA 99021 Mead, WA 99021
*==LICENSE==*/ *==LICENSE==*/
@ -368,9 +368,10 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plRidingAnimatedPhysicalDetector), CLASS_INDEX(plRidingAnimatedPhysicalDetector),
CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration), CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration),
CLASS_INDEX(plPXSubWorld), CLASS_INDEX(plPXSubWorld),
//--------------------------------------------------------- CLASS_INDEX(pfConfirmationMgr),
// Keyed objects above this line, unkeyed (such as messages) below.. //---------------------------------------------------------
//--------------------------------------------------------- // Keyed objects above this line, unkeyed (such as messages) below..
//---------------------------------------------------------
CLASS_INDEX_NONKEYED_OBJ_START CLASS_INDEX_NONKEYED_OBJ_START
CLASS_INDEX(plObjRefMsg), CLASS_INDEX(plObjRefMsg),
@ -780,17 +781,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plShadowCastMsg), CLASS_INDEX(plShadowCastMsg),
CLASS_INDEX(plBoundsIsect), CLASS_INDEX(plBoundsIsect),
CLASS_INDEX(plResMgrHelperMsg), CLASS_INDEX(plResMgrHelperMsg),
CLASS_INDEX(plNetCommAuthMsg), CLASS_INDEX(plNetCommAuthMsg),
CLASS_INDEX(plNetCommFileListMsg), CLASS_INDEX(plNetCommFileListMsg),
CLASS_INDEX(plNetCommFileDownloadMsg), CLASS_INDEX(plNetCommFileDownloadMsg),
CLASS_INDEX(plNetCommLinkToAgeMsg), CLASS_INDEX(plNetCommLinkToAgeMsg),
CLASS_INDEX(plNetCommPlayerListMsg), CLASS_INDEX(plNetCommPlayerListMsg),
CLASS_INDEX(plNetCommActivePlayerMsg), CLASS_INDEX(plNetCommActivePlayerMsg),
CLASS_INDEX(plNetCommCreatePlayerMsg), CLASS_INDEX(plNetCommCreatePlayerMsg),
CLASS_INDEX(plNetCommDeletePlayerMsg), CLASS_INDEX(plNetCommDeletePlayerMsg),
CLASS_INDEX(plNetCommPublicAgeListMsg), CLASS_INDEX(plNetCommPublicAgeListMsg),
CLASS_INDEX(plNetCommPublicAgeMsg), CLASS_INDEX(plNetCommPublicAgeMsg),
CLASS_INDEX(plNetCommRegisterAgeMsg), CLASS_INDEX(plNetCommRegisterAgeMsg),
CLASS_INDEX(plVaultAdminInitializationTask), CLASS_INDEX(plVaultAdminInitializationTask),
CLASS_INDEX(plMultistageModMsg), CLASS_INDEX(plMultistageModMsg),
CLASS_INDEX(plSoundVolumeApplicator), CLASS_INDEX(plSoundVolumeApplicator),
@ -948,6 +949,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plAngularVelocityMsg), CLASS_INDEX(plAngularVelocityMsg),
CLASS_INDEX(plRideAnimatedPhysMsg), CLASS_INDEX(plRideAnimatedPhysMsg),
CLASS_INDEX(plAvBrainRideAnimatedPhysical), CLASS_INDEX(plAvBrainRideAnimatedPhysical),
CLASS_INDEX(pfGameScoreMsg),
CLASS_INDEX(pfGameScoreListMsg),
CLASS_INDEX(pfGameScoreTransferMsg),
CLASS_INDEX(pfGameScoreUpdateMsg),
CLASS_INDEX(plLoadClothingMsg),
CLASS_INDEX(plNullPipeline),
CLASS_INDEX(plGLPipeline),
CLASS_INDEX(plSDLModifierStateMsg),
CLASS_INDEX(plConfirmationMsg),
CLASS_INDEX(plLocalizedConfirmationMsg),
CLASS_INDEX(plSubtitleMsg),
CLASS_INDEX_LIST_END CLASS_INDEX_LIST_END
#endif // plCreatableIndex_inc #endif // plCreatableIndex_inc

2
Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h

@ -43,7 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef plLogicModBase_inc #ifndef plLogicModBase_inc
#define plLogicModBase_inc #define plLogicModBase_inc
#include <stdint.h> #include <cstdint>
#include "plSingleModifier.h" #include "plSingleModifier.h"
#include "../pnNetCommon/plSynchedValue.h" #include "../pnNetCommon/plSynchedValue.h"
#include "hsTemplates.h" #include "hsTemplates.h"

6
Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.cpp

@ -994,6 +994,7 @@ hsBool plgAudioSys::fInit = false;
hsBool plgAudioSys::fActive = false; hsBool plgAudioSys::fActive = false;
hsBool plgAudioSys::fUseHardware = false; hsBool plgAudioSys::fUseHardware = false;
hsBool plgAudioSys::fMuted = true; hsBool plgAudioSys::fMuted = true;
bool plgAudioSys::fEnableSubtitles = false;
hsBool plgAudioSys::fDelayedActivate = false; hsBool plgAudioSys::fDelayedActivate = false;
hsBool plgAudioSys::fEnableEAX = false; hsBool plgAudioSys::fEnableEAX = false;
hsWindowHndl plgAudioSys::fWnd = nil; hsWindowHndl plgAudioSys::fWnd = nil;
@ -1047,6 +1048,11 @@ void plgAudioSys::SetMuted( hsBool b )
SetGlobalFadeVolume(1.0); SetGlobalFadeVolume(1.0);
} }
void plgAudioSys::SetEnableSubtitles(bool b)
{
fEnableSubtitles = b;
}
void plgAudioSys::SetUseHardware(hsBool b) void plgAudioSys::SetUseHardware(hsBool b)
{ {
fUseHardware = b; fUseHardware = b;

2
Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.h

@ -193,11 +193,13 @@ public:
static void SetUseHardware(hsBool b); static void SetUseHardware(hsBool b);
static void SetActive(hsBool b); static void SetActive(hsBool b);
static void SetMuted( hsBool b ); static void SetMuted( hsBool b );
static void SetEnableSubtitles(bool b);
static void EnableEAX( hsBool b ); static void EnableEAX( hsBool b );
static hsBool Active() { return fInit; } static hsBool Active() { return fInit; }
static void Shutdown(); static void Shutdown();
static void Activate(hsBool b); static void Activate(hsBool b);
static hsBool IsMuted( void ) { return fMuted; } static hsBool IsMuted( void ) { return fMuted; }
static bool AreSubtitlesEnabled() { return fEnableSubtitles; }
static hsWindowHndl hWnd() { return fWnd; } static hsWindowHndl hWnd() { return fWnd; }
static plAudioSystem* Sys() { return fSys; } static plAudioSystem* Sys() { return fSys; }
static void Restart( void ); static void Restart( void );

29
Sources/Plasma/PubUtilLib/plAudio/plWin32Sound.cpp

@ -53,10 +53,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plWavFile.h" #include "plWavFile.h"
#include "../plAudible/plWinAudible.h" #include "../plAudible/plWinAudible.h"
#include "../plAudioCore/plSrtFileReader.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../pnMessage/plSoundMsg.h"
#include "../plMessage/plSubtitleMsg.h"
#include "../plNetMessage/plNetMessage.h" #include "../plNetMessage/plNetMessage.h"
#include "../pnNetCommon/plNetApp.h" #include "../pnNetCommon/plNetApp.h"
#include "../pnMessage/plSoundMsg.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../plPipeline/plPlates.h" #include "../plPipeline/plPlates.h"
#include "../plStatusLog/plStatusLog.h" #include "../plStatusLog/plStatusLog.h"
@ -108,6 +110,18 @@ void plWin32Sound::IFreeBuffers( void )
void plWin32Sound::Update() void plWin32Sound::Update()
{ {
plSoundBuffer* buf = GetDataBuffer();
if (plgAudioSys::AreSubtitlesEnabled() && buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
while (plSrtEntry* nextEntry = srtReader->GetNextEntryStartingBeforeTime((uint32_t)(GetActualTimeSec() * 1000.0f))) {
// add a plSubtitleMsg to go... to whoever is listening (probably the KI)
plSubtitleMsg* msg = new plSubtitleMsg(nextEntry->GetSubtitleText(), nextEntry->GetSpeakerName());
msg->Send();
}
}
}
plSound::Update(); plSound::Update();
} }
@ -120,6 +134,17 @@ void plWin32Sound::IActuallyPlay( void )
{ {
if (fDSoundBuffer && plgAudioSys::Active() ) if (fDSoundBuffer && plgAudioSys::Active() )
{ {
if (!fReallyPlaying && fSynchedStartTimeSec > 0) {
// advance past any subtitles that would end before the synched start time
// not sure when this actually happens...
plSoundBuffer* buf = GetDataBuffer();
if (buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
srtReader->AdvanceToTime(fSynchedStartTimeSec * 1000.0);
}
}
}
// Sometimes base/derived classes can be annoying // Sometimes base/derived classes can be annoying
IDerivedActuallyPlay(); IDerivedActuallyPlay();

27
Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.cpp

@ -48,6 +48,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plgDispatch.h" #include "plgDispatch.h"
#include "hsResMgr.h" #include "hsResMgr.h"
#include "plSrtFileReader.h"
#include "../pnMessage/plRefMsg.h" #include "../pnMessage/plRefMsg.h"
#include "../plFile/plFileUtils.h" #include "../plFile/plFileUtils.h"
#include "../plFile/hsFiles.h" #include "../plFile/hsFiles.h"
@ -117,20 +118,35 @@ static void LoadCallback(void *)
else else
{ {
plAudioFileReader *reader = nil; plAudioFileReader *reader = nil;
plSrtFileReader* srtReader = nullptr;
while(plSoundBuffer *buffer = templist.Head()) while(plSoundBuffer *buffer = templist.Head())
{ {
if(buffer->GetData()) if(buffer->GetData())
{ {
reader = CreateReader(true, buffer->GetFileName(), buffer->GetAudioReaderType(), buffer->GetReaderSelect()); const char* srcFilename = buffer->GetFileName();
reader = CreateReader(true, srcFilename, buffer->GetAudioReaderType(), buffer->GetReaderSelect());
if( reader ) if( reader )
{ {
unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength(); unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength();
reader->Read( readLen, buffer->GetData() ); reader->Read( readLen, buffer->GetData() );
buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later
plSrtFileReader* srtReader = buffer->GetSrtReader();
if (srtReader != nullptr && srtReader->GetCurrentAudioFileName() == srcFilename) {
// same file we were playing before, so start the SRT feed over instead of deleting and reloading
srtReader->StartOver();
} else {
std::unique_ptr<plSrtFileReader> newSrtFileReader(new plSrtFileReader(srcFilename));
if (newSrtFileReader->ReadFile())
buffer->SetSrtReader(newSrtFileReader.release());
}
} }
else else
{
buffer->SetError(); buffer->SetError();
}
} }
templist.Unlink(buffer); templist.Unlink(buffer);
@ -194,6 +210,8 @@ plSoundBuffer::~plSoundBuffer()
ASSERT(!link.IsLinked()); ASSERT(!link.IsLinked());
delete [] fFileName; delete [] fFileName;
UnLoad(); UnLoad();
delete fSrtReader;
} }
void plSoundBuffer::IInitBuffer() void plSoundBuffer::IInitBuffer()
@ -206,6 +224,7 @@ void plSoundBuffer::IInitBuffer()
fFlags = 0; fFlags = 0;
fDataRead = 0; fDataRead = 0;
fReader = nil; fReader = nil;
fSrtReader = nullptr;
fLoaded = 0; fLoaded = 0;
fLoading = false; fLoading = false;
fHeader.fFormatTag = 0; fHeader.fFormatTag = 0;
@ -458,6 +477,12 @@ void plSoundBuffer::SetLoaded(bool loaded)
fLoaded = loaded; fLoaded = loaded;
} }
void plSoundBuffer::SetSrtReader(plSrtFileReader* reader)
{
delete fSrtReader;
fSrtReader = reader;
}
/***************************************************************************** /*****************************************************************************
* *

4
Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.h

@ -61,6 +61,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
class plUnifiedTime; class plUnifiedTime;
class plAudioFileReader; class plAudioFileReader;
class plSrtFileReader;
class plSoundBuffer : public hsKeyedObject class plSoundBuffer : public hsKeyedObject
{ {
public: public:
@ -118,6 +119,8 @@ public:
plAudioFileReader * GetAudioReader(); // transfers ownership to caller plAudioFileReader * GetAudioReader(); // transfers ownership to caller
void SetAudioReader(plAudioFileReader *reader); void SetAudioReader(plAudioFileReader *reader);
void SetLoaded(bool loaded); void SetLoaded(bool loaded);
plSrtFileReader* GetSrtReader() const { return fSrtReader; } // does not transfer ownership
void SetSrtReader(plSrtFileReader* reader);
plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; } plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; }
unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; } unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; }
@ -149,6 +152,7 @@ protected:
bool fError; bool fError;
plAudioFileReader * fReader; plAudioFileReader * fReader;
plSrtFileReader* fSrtReader;
UInt8 * fData; UInt8 * fData;
plWAVHeader fHeader; plWAVHeader fHeader;
UInt32 fDataLength; UInt32 fDataLength;

192
Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.cpp

@ -0,0 +1,192 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plSrtFileReader.h"
#include "hsStream.h"
#include "../plStatusLog/plStatusLog.h"
#include "../pnUtils/Private/pnUtPath.h"
#include "../pnUtils/Private/pnUtStr.h"
#include <regex>
static const std::regex speakerTextRegex("^((([\\w.]+(\\s\\w+)?):) )?(.*)");
static const std::regex timingsRegex("^(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3}) --> (\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})$");
bool plSrtFileReader::ReadFile()
{
wchar srtPathUnicode[MAX_PATH];
StrToUnicode(srtPathUnicode, fAudioFileName, arrsize(srtPathUnicode));
PathSetExtension(srtPathUnicode, srtPathUnicode, L".sub", arrsize(srtPathUnicode));
if (PathDoesFileExist(srtPathUnicode)) {
// read sets of SRT data until end of file
hsUNIXStream srtFileStream;
// if file exists and was opened successfully
if (srtFileStream.Open(srtPathUnicode, L"r")) {
plStatusLog::AddLineS("audio.log", "Successfully opened subtitle file {}", srtPathUnicode);
uint32_t subtitleNumber = 0;
uint32_t subtitleStartTimeMs = 0;
uint32_t subtitleEndTimeMs = 0;
char* line;
std::string speakerName;
std::string subtitleText;
std::cmatch matches;
for (unsigned int lnCounter = 0; !srtFileStream.AtEnd(); lnCounter++) {
if (lnCounter % 4 == 0 && srtFileStream.ReadLn(line)) {
subtitleNumber = std::stoul(line);
}
else if (lnCounter % 4 == 1 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, timingsRegex)) {
if (matches.size() < 9) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle timings '{}' are formatted incorrectly.", line);
subtitleNumber = 0;
}
else {
// matches[0] is the entire match, we don't do anything with it
// matches[1] is the first group -- the start hour number
subtitleStartTimeMs += std::stoul(matches[1].str()) * 3600000;
// matches[2] is the second group -- the start minute number
subtitleStartTimeMs += std::stoul(matches[2].str()) * 60000;
// matches[3] is the third group -- the start seconds number
subtitleStartTimeMs += std::stoul(matches[3].str()) * 1000;
// matches[4] is the fourth group -- the start milliseconds number
subtitleStartTimeMs += std::stoul(matches[4].str());
// matches[5] is the fifth group -- the end hour number
subtitleEndTimeMs += std::stoul(matches[5].str()) * 3600000;
// matches[6] is the sixth group -- the end minute number
subtitleEndTimeMs += std::stoul(matches[6].str()) * 60000;
// matches[7] is the seventh group -- the end seconds number
subtitleEndTimeMs += std::stoul(matches[7].str()) * 1000;
// matches[8] is the eighth group -- the end milliseconds number
subtitleEndTimeMs += std::stoul(matches[8].str());
}
}
}
else if (lnCounter % 4 == 2 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, speakerTextRegex)) {
if (matches.size() < 5) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle text and/or speaker name '{}' are formatted incorrectly.", line);
subtitleNumber = 0;
}
else {
// matches[0] is the entire match, we don't do anything with it
// matches[2] is the second group (the optional subtitle speaker with colon but no space at the end)
speakerName = matches[2];
// matches[5] is the fourth group (the subtitle text)
subtitleText = matches[5];
}
}
}
else if (lnCounter % 4 == 3 && subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// entry is complete, add to the queue and reset our temp variables
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
subtitleNumber = 0;
subtitleStartTimeMs = 0;
subtitleEndTimeMs = 0;
subtitleText.clear();
speakerName.clear();
}
}
if (subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// enqueue the last subtitle from the file if we didn't have an extra blank line at the end
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
}
return true;
}
}
return false;
}
void plSrtFileReader::AdvanceToTime(uint32_t timeMs)
{
while (fCurrentEntryIndex < fEntries.size() && fEntries.at(fCurrentEntryIndex).GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
}
}
plSrtEntry* plSrtFileReader::GetNextEntryStartingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetStartTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}
plSrtEntry* plSrtFileReader::GetNextEntryEndingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}

105
Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.h

@ -0,0 +1,105 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSrtFileReader - Class for reading an SRT format file and //
// storing the read entries for access later //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSrtFileReader_h
#define _plSrtFileReader_h
#include "hsTypes.h"
#include <cstdint>
#include <vector>
class plSrtEntry
{
public:
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText, std::string speakerName)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)),
fSpeakerName(std::move(speakerName)) { }
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)) { }
std::string GetSubtitleText() const { return fSubtitleText; }
std::string GetSpeakerName() const { return fSpeakerName; }
uint32_t GetStartTimeMs() const { return fStartTimeMs; }
uint32_t GetEndTimeMs() const { return fEndTimeMs; }
protected:
uint32_t fEntryNum;
uint32_t fStartTimeMs;
uint32_t fEndTimeMs;
std::string fSubtitleText;
std::string fSpeakerName;
};
class plSrtFileReader
{
public:
plSrtFileReader(const char* audioFileName)
: fAudioFileName(std::move(audioFileName)), fEntries(), fCurrentEntryIndex() { }
bool ReadFile();
void StartOver() { fCurrentEntryIndex = 0; }
const char* GetCurrentAudioFileName() const { return fAudioFileName; }
void AdvanceToTime(uint32_t timeMs);
plSrtEntry* GetNextEntryStartingBeforeTime(uint32_t timeMs);
plSrtEntry* GetNextEntryEndingBeforeTime(uint32_t timeMs);
protected:
const char* fAudioFileName;
std::vector<plSrtEntry> fEntries;
uint32_t fCurrentEntryIndex;
};
#endif //_plSrtFileReader_h

4
Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h

@ -133,6 +133,10 @@ REGISTER_CREATABLE( plSpawnModMsg );
REGISTER_CREATABLE( plSpawnRequestMsg ); REGISTER_CREATABLE( plSpawnRequestMsg );
#include "plSubtitleMsg.h"
REGISTER_CREATABLE(plSubtitleMsg);
#include "plNodeCleanupMsg.h" #include "plNodeCleanupMsg.h"
REGISTER_CREATABLE( plNodeCleanupMsg ); REGISTER_CREATABLE( plNodeCleanupMsg );

82
Sources/Plasma/PubUtilLib/plMessage/plSubtitleMsg.h

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plSubtitleMsg_inc
#define plSubtitleMsg_inc
#include "../pnMessage/plMessage.h"
/** Show subtitle text for in-game audio */
class plSubtitleMsg : public plMessage
{
protected:
std::string fText;
std::string fSpeaker;
public:
plSubtitleMsg() : plMessage()
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText) : plMessage(), fText(std::move(msgText))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText, std::string msgSpeaker) : plMessage(), fText(std::move(msgText)),
fSpeaker(std::move(msgSpeaker))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
CLASSNAME_REGISTER(plSubtitleMsg);
GETINTERFACE_ANY(plSubtitleMsg, plMessage);
void Read(hsStream*, hsResMgr*) override { FATAL("no"); }
void Write(hsStream*, hsResMgr*) override { FATAL("no"); }
std::string GetText() const { return fText; }
std::string GetSpeaker() const { return fSpeaker; }
};
#endif // plSubtitleMsg_inc
Loading…
Cancel
Save