ddnet/src/game/client/components/mapsounds.cpp

248 lines
6.5 KiB
C++
Raw Normal View History

#include <engine/demo.h>
2014-10-10 17:10:57 +00:00
#include <engine/sound.h>
#include <game/client/components/camera.h>
2014-10-12 14:12:13 +00:00
#include <game/client/components/maplayers.h> // envelope
2014-10-10 17:10:57 +00:00
#include <game/client/components/sounds.h>
2021-07-12 09:29:59 +00:00
#include <game/client/gameclient.h>
#include <game/layers.h>
2014-10-10 17:10:57 +00:00
#include "mapsounds.h"
CMapSounds::CMapSounds()
{
m_Count = 0;
}
void CMapSounds::OnMapLoad()
{
IMap *pMap = Kernel()->RequestInterface<IMap>();
2014-10-18 13:21:13 +00:00
Clear();
2014-10-11 11:38:08 +00:00
// load samples
int Start;
pMap->GetType(MAPITEMTYPE_SOUND, &Start, &m_Count);
// load new samples
for(int i = 0; i < m_Count; i++)
{
m_aSounds[i] = 0;
CMapItemSound *pSound = (CMapItemSound *)pMap->GetItem(Start + i, 0, 0);
2014-10-11 11:38:08 +00:00
if(pSound->m_External)
{
2021-09-13 09:47:47 +00:00
char aBuf[IO_MAX_PATH_LENGTH];
2014-10-11 11:38:08 +00:00
char *pName = (char *)pMap->GetData(pSound->m_SoundName);
2021-09-13 09:47:47 +00:00
str_format(aBuf, sizeof(aBuf), "mapres/%s.opus", pName);
m_aSounds[i] = Sound()->LoadOpus(aBuf);
2014-10-11 11:38:08 +00:00
}
else
{
2014-10-11 12:50:16 +00:00
void *pData = pMap->GetData(pSound->m_SoundData);
m_aSounds[i] = Sound()->LoadOpusFromMem(pData, pSound->m_SoundDataSize);
2014-10-11 12:50:16 +00:00
pMap->UnloadData(pSound->m_SoundData);
2014-10-11 11:38:08 +00:00
}
}
2014-10-10 17:10:57 +00:00
// enqueue sound sources
m_vSourceQueue.clear();
2014-10-10 17:10:57 +00:00
for(int g = 0; g < Layers()->NumGroups(); g++)
{
CMapItemGroup *pGroup = Layers()->GetGroup(g);
if(!pGroup)
continue;
for(int l = 0; l < pGroup->m_NumLayers; l++)
{
CMapItemLayer *pLayer = Layers()->GetLayer(pGroup->m_StartLayer + l);
2014-10-10 17:10:57 +00:00
if(!pLayer)
continue;
if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
CMapItemLayerSounds *pSoundLayer = (CMapItemLayerSounds *)pLayer;
2014-10-11 11:38:08 +00:00
if(pSoundLayer->m_Version < 1 || pSoundLayer->m_Version > CMapItemLayerSounds::CURRENT_VERSION)
continue;
2014-10-11 11:38:08 +00:00
if(pSoundLayer->m_Sound == -1)
continue;
2014-10-10 17:10:57 +00:00
CSoundSource *pSources = (CSoundSource *)Layers()->Map()->GetDataSwapped(pSoundLayer->m_Data);
if(!pSources)
continue;
for(int i = 0; i < pSoundLayer->m_NumSources; i++)
{
2014-10-18 13:21:13 +00:00
CSourceQueueEntry source;
source.m_Sound = pSoundLayer->m_Sound;
source.m_pSource = &pSources[i];
source.m_HighDetail = pLayer->m_Flags & LAYERFLAG_DETAIL;
2014-10-18 13:21:13 +00:00
if(!source.m_pSource || source.m_Sound == -1)
continue;
m_vSourceQueue.push_back(source);
}
2014-10-10 17:10:57 +00:00
}
}
}
}
void CMapSounds::OnRender()
{
if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
return;
bool DemoPlayerPaused = Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->BaseInfo()->m_Paused;
2014-10-10 17:10:57 +00:00
// enqueue sounds
for(auto &Source : m_vSourceQueue)
2014-10-10 17:10:57 +00:00
{
2014-10-18 13:21:13 +00:00
static float s_Time = 0.0f;
if(m_pClient->m_Snap.m_pGameInfoObj) // && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
2014-10-10 17:10:57 +00:00
{
s_Time = mix((Client()->PrevGameTick(g_Config.m_ClDummy) - m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)Client()->GameTickSpeed(),
(Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)Client()->GameTickSpeed(),
Client()->IntraGameTick(g_Config.m_ClDummy));
2014-10-10 17:10:57 +00:00
}
float Offset = s_Time - Source.m_pSource->m_TimeDelay;
if(!DemoPlayerPaused && Offset >= 0.0f && g_Config.m_SndEnable && (g_Config.m_GfxHighDetail || !Source.m_HighDetail))
2014-10-10 17:10:57 +00:00
{
if(Source.m_Voice.IsValid())
2014-10-18 13:21:13 +00:00
{
// currently playing, set offset
Sound()->SetVoiceTimeOffset(Source.m_Voice, Offset);
2014-10-18 13:21:13 +00:00
}
else
{
// need to enqueue
int Flags = 0;
if(Source.m_pSource->m_Loop)
Flags |= ISound::FLAG_LOOP;
if(!Source.m_pSource->m_Pan)
Flags |= ISound::FLAG_NO_PANNING;
2014-10-12 14:12:13 +00:00
Source.m_Voice = m_pClient->m_Sounds.PlaySampleAt(CSounds::CHN_MAPSOUND, m_aSounds[Source.m_Sound], 1.0f, vec2(fx2f(Source.m_pSource->m_Position.x), fx2f(Source.m_pSource->m_Position.y)), Flags);
Sound()->SetVoiceTimeOffset(Source.m_Voice, Offset);
Sound()->SetVoiceFalloff(Source.m_Voice, Source.m_pSource->m_Falloff / 255.0f);
switch(Source.m_pSource->m_Shape.m_Type)
{
case CSoundShape::SHAPE_CIRCLE:
{
Sound()->SetVoiceCircle(Source.m_Voice, Source.m_pSource->m_Shape.m_Circle.m_Radius);
break;
}
case CSoundShape::SHAPE_RECTANGLE:
{
Sound()->SetVoiceRectangle(Source.m_Voice, fx2f(Source.m_pSource->m_Shape.m_Rectangle.m_Width), fx2f(Source.m_pSource->m_Shape.m_Rectangle.m_Height));
break;
}
};
2014-10-18 13:21:13 +00:00
}
}
else
{
// stop voice
Sound()->StopVoice(Source.m_Voice);
Source.m_Voice = ISound::CVoiceHandle();
2014-10-12 14:12:13 +00:00
}
}
2014-10-10 17:50:39 +00:00
2021-07-12 09:43:56 +00:00
vec2 Center = m_pClient->m_Camera.m_Center;
for(int g = 0; g < Layers()->NumGroups(); g++)
2014-10-12 14:12:13 +00:00
{
CMapItemGroup *pGroup = Layers()->GetGroup(g);
2014-10-12 14:12:13 +00:00
if(!pGroup)
2014-10-12 14:12:13 +00:00
continue;
for(int l = 0; l < pGroup->m_NumLayers; l++)
2014-10-12 14:12:13 +00:00
{
CMapItemLayer *pLayer = Layers()->GetLayer(pGroup->m_StartLayer + l);
2014-10-12 14:12:13 +00:00
if(!pLayer)
continue;
2014-10-12 14:43:33 +00:00
if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
CMapItemLayerSounds *pSoundLayer = (CMapItemLayerSounds *)pLayer;
2015-07-09 00:08:14 +00:00
if(pSoundLayer->m_Version < 1 || pSoundLayer->m_Version > CMapItemLayerSounds::CURRENT_VERSION)
continue;
2014-10-12 14:43:33 +00:00
CSoundSource *pSources = (CSoundSource *)Layers()->Map()->GetDataSwapped(pSoundLayer->m_Data);
if(!pSources)
continue;
for(int s = 0; s < pSoundLayer->m_NumSources; s++)
{
for(auto &Voice : m_vSourceQueue)
{
if(Voice.m_pSource != &pSources[s])
continue;
if(!Voice.m_Voice.IsValid())
continue;
float OffsetX = 0, OffsetY = 0;
if(Voice.m_pSource->m_PosEnv >= 0)
{
float aChannels[4];
CMapLayers::EnvelopeEval(Voice.m_pSource->m_PosEnvOffset, Voice.m_pSource->m_PosEnv, aChannels, &m_pClient->m_MapLayersBackGround);
OffsetX = aChannels[0];
OffsetY = aChannels[1];
}
float x = fx2f(Voice.m_pSource->m_Position.x) + OffsetX;
float y = fx2f(Voice.m_pSource->m_Position.y) + OffsetY;
x += Center.x * (1.0f - pGroup->m_ParallaxX / 100.0f);
y += Center.y * (1.0f - pGroup->m_ParallaxY / 100.0f);
x -= pGroup->m_OffsetX;
y -= pGroup->m_OffsetY;
Sound()->SetVoiceLocation(Voice.m_Voice, x, y);
if(Voice.m_pSource->m_SoundEnv >= 0)
{
float aChannels[4];
CMapLayers::EnvelopeEval(Voice.m_pSource->m_SoundEnvOffset, Voice.m_pSource->m_SoundEnv, aChannels, &m_pClient->m_MapLayersBackGround);
float Volume = clamp(aChannels[0], 0.0f, 1.0f);
Sound()->SetVoiceVolume(Voice.m_Voice, Volume);
}
2015-07-09 00:08:14 +00:00
}
}
}
2014-10-12 14:43:33 +00:00
}
2014-10-10 17:10:57 +00:00
}
2014-10-18 13:21:13 +00:00
}
void CMapSounds::Clear()
{
// unload all samples
for(int i = 0; i < m_Count; i++)
{
Sound()->UnloadSample(m_aSounds[i]);
m_aSounds[i] = -1;
}
m_Count = 0;
}
void CMapSounds::OnStateChange(int NewState, int OldState)
{
if(NewState < IClient::STATE_ONLINE)
Clear();
2014-10-23 13:53:23 +00:00
}