dhewm3/neo/sound/snd_shader.cpp
dhewg 736ec20d4d Untangle the epic precompiled.h mess
Don't include the lazy precompiled.h everywhere, only what's
required for the compilation unit.
platform.h needs to be included instead to provide all essential
defines and types.
All includes use the relative path to the neo or the game
specific root.
Move all idlib related includes from idlib/Lib.h to precompiled.h.
precompiled.h still exists for the MFC stuff in tools/.
Add some missing header guards.
2011-12-19 23:21:47 +01:00

509 lines
12 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code 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.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "sys/platform.h"
#include "framework/FileSystem.h"
#include "sound/snd_local.h"
/*
===============
idSoundShader::Init
===============
*/
void idSoundShader::Init( void ) {
desc = "<no description>";
errorDuringParse = false;
onDemand = false;
numEntries = 0;
numLeadins = 0;
leadinVolume = 0;
altSound = NULL;
}
/*
===============
idSoundShader::idSoundShader
===============
*/
idSoundShader::idSoundShader( void ) {
Init();
}
/*
===============
idSoundShader::~idSoundShader
===============
*/
idSoundShader::~idSoundShader( void ) {
}
/*
=================
idSoundShader::Size
=================
*/
size_t idSoundShader::Size( void ) const {
return sizeof( idSoundShader );
}
/*
===============
idSoundShader::idSoundShader::FreeData
===============
*/
void idSoundShader::FreeData() {
numEntries = 0;
numLeadins = 0;
}
/*
===================
idSoundShader::SetDefaultText
===================
*/
bool idSoundShader::SetDefaultText( void ) {
idStr wavname;
wavname = GetName();
wavname.DefaultFileExtension( ".wav" ); // if the name has .ogg in it, that will stay
// if there exists a wav file with the same name
if ( 1 ) { //fileSystem->ReadFile( wavname, NULL ) != -1 ) {
char generated[2048];
idStr::snPrintf( generated, sizeof( generated ),
"sound %s // IMPLICITLY GENERATED\n"
"{\n"
"%s\n"
"}\n", GetName(), wavname.c_str() );
SetText( generated );
return true;
} else {
return false;
}
}
/*
===================
DefaultDefinition
===================
*/
const char *idSoundShader::DefaultDefinition() const {
return
"{\n"
"\t" "_default.wav\n"
"}";
}
/*
===============
idSoundShader::Parse
this is called by the declManager
===============
*/
bool idSoundShader::Parse( const char *text, const int textLength ) {
idLexer src;
src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
src.SetFlags( DECL_LEXER_FLAGS );
src.SkipUntilString( "{" );
// deeper functions can set this, which will cause MakeDefault() to be called at the end
errorDuringParse = false;
if ( !ParseShader( src ) || errorDuringParse ) {
MakeDefault();
return false;
}
return true;
}
/*
===============
idSoundShader::ParseShader
===============
*/
bool idSoundShader::ParseShader( idLexer &src ) {
int i;
idToken token;
parms.minDistance = 1;
parms.maxDistance = 10;
parms.volume = 1;
parms.shakes = 0;
parms.soundShaderFlags = 0;
parms.soundClass = 0;
speakerMask = 0;
altSound = NULL;
for( i = 0; i < SOUND_MAX_LIST_WAVS; i++ ) {
leadins[i] = NULL;
entries[i] = NULL;
}
numEntries = 0;
numLeadins = 0;
int maxSamples = idSoundSystemLocal::s_maxSoundsPerShader.GetInteger();
if ( com_makingBuild.GetBool() || maxSamples <= 0 || maxSamples > SOUND_MAX_LIST_WAVS ) {
maxSamples = SOUND_MAX_LIST_WAVS;
}
while ( 1 ) {
if ( !src.ExpectAnyToken( &token ) ) {
return false;
}
// end of definition
else if ( token == "}" ) {
break;
}
// minimum number of sounds
else if ( !token.Icmp( "minSamples" ) ) {
maxSamples = idMath::ClampInt( src.ParseInt(), SOUND_MAX_LIST_WAVS, maxSamples );
}
// description
else if ( !token.Icmp( "description" ) ) {
src.ReadTokenOnLine( &token );
desc = token.c_str();
}
// mindistance
else if ( !token.Icmp( "mindistance" ) ) {
parms.minDistance = src.ParseFloat();
}
// maxdistance
else if ( !token.Icmp( "maxdistance" ) ) {
parms.maxDistance = src.ParseFloat();
}
// shakes screen
else if ( !token.Icmp( "shakes" ) ) {
src.ExpectAnyToken( &token );
if ( token.type == TT_NUMBER ) {
parms.shakes = token.GetFloatValue();
} else {
src.UnreadToken( &token );
parms.shakes = 1.0f;
}
}
// reverb
else if ( !token.Icmp( "reverb" ) ) {
src.ParseFloat();
if ( !src.ExpectTokenString( "," ) ) {
src.FreeSource();
return false;
}
src.ParseFloat();
// no longer supported
}
// volume
else if ( !token.Icmp( "volume" ) ) {
parms.volume = src.ParseFloat();
}
// leadinVolume is used to allow light breaking leadin sounds to be much louder than the broken loop
else if ( !token.Icmp( "leadinVolume" ) ) {
leadinVolume = src.ParseFloat();
}
// speaker mask
else if ( !token.Icmp( "mask_center" ) ) {
speakerMask |= 1<<SPEAKER_CENTER;
}
// speaker mask
else if ( !token.Icmp( "mask_left" ) ) {
speakerMask |= 1<<SPEAKER_LEFT;
}
// speaker mask
else if ( !token.Icmp( "mask_right" ) ) {
speakerMask |= 1<<SPEAKER_RIGHT;
}
// speaker mask
else if ( !token.Icmp( "mask_backright" ) ) {
speakerMask |= 1<<SPEAKER_BACKRIGHT;
}
// speaker mask
else if ( !token.Icmp( "mask_backleft" ) ) {
speakerMask |= 1<<SPEAKER_BACKLEFT;
}
// speaker mask
else if ( !token.Icmp( "mask_lfe" ) ) {
speakerMask |= 1<<SPEAKER_LFE;
}
// soundClass
else if ( !token.Icmp( "soundClass" ) ) {
parms.soundClass = src.ParseInt();
if ( parms.soundClass < 0 || parms.soundClass >= SOUND_MAX_CLASSES ) {
src.Warning( "SoundClass out of range" );
return false;
}
}
// altSound
else if ( !token.Icmp( "altSound" ) ) {
if ( !src.ExpectAnyToken( &token ) ) {
return false;
}
altSound = declManager->FindSound( token.c_str() );
}
// ordered
else if ( !token.Icmp( "ordered" ) ) {
// no longer supported
}
// no_dups
else if ( !token.Icmp( "no_dups" ) ) {
parms.soundShaderFlags |= SSF_NO_DUPS;
}
// no_flicker
else if ( !token.Icmp( "no_flicker" ) ) {
parms.soundShaderFlags |= SSF_NO_FLICKER;
}
// plain
else if ( !token.Icmp( "plain" ) ) {
// no longer supported
}
// looping
else if ( !token.Icmp( "looping" ) ) {
parms.soundShaderFlags |= SSF_LOOPING;
}
// no occlusion
else if ( !token.Icmp( "no_occlusion" ) ) {
parms.soundShaderFlags |= SSF_NO_OCCLUSION;
}
// private
else if ( !token.Icmp( "private" ) ) {
parms.soundShaderFlags |= SSF_PRIVATE_SOUND;
}
// antiPrivate
else if ( !token.Icmp( "antiPrivate" ) ) {
parms.soundShaderFlags |= SSF_ANTI_PRIVATE_SOUND;
}
// once
else if ( !token.Icmp( "playonce" ) ) {
parms.soundShaderFlags |= SSF_PLAY_ONCE;
}
// global
else if ( !token.Icmp( "global" ) ) {
parms.soundShaderFlags |= SSF_GLOBAL;
}
// unclamped
else if ( !token.Icmp( "unclamped" ) ) {
parms.soundShaderFlags |= SSF_UNCLAMPED;
}
// omnidirectional
else if ( !token.Icmp( "omnidirectional" ) ) {
parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL;
}
// onDemand can't be a parms, because we must track all references and overrides would confuse it
else if ( !token.Icmp( "onDemand" ) ) {
// no longer loading sounds on demand
//onDemand = true;
}
// the wave files
else if ( !token.Icmp( "leadin" ) ) {
// add to the leadin list
if ( !src.ReadToken( &token ) ) {
src.Warning( "Expected sound after leadin" );
return false;
}
if ( soundSystemLocal.soundCache && numLeadins < maxSamples ) {
leadins[ numLeadins ] = soundSystemLocal.soundCache->FindSound( token.c_str(), onDemand );
numLeadins++;
}
} else if ( token.Find( ".wav", false ) != -1 || token.Find( ".ogg", false ) != -1 ) {
// add to the wav list
if ( soundSystemLocal.soundCache && numEntries < maxSamples ) {
token.BackSlashesToSlashes();
idStr lang = cvarSystem->GetCVarString( "sys_lang" );
if ( lang.Icmp( "english" ) != 0 && token.Find( "sound/vo/", false ) >= 0 ) {
idStr work = token;
work.ToLower();
work.StripLeading( "sound/vo/" );
work = va( "sound/vo/%s/%s", lang.c_str(), work.c_str() );
if ( fileSystem->ReadFile( work, NULL, NULL ) > 0 ) {
token = work;
} else {
// also try to find it with the .ogg extension
work.SetFileExtension( ".ogg" );
if ( fileSystem->ReadFile( work, NULL, NULL ) > 0 ) {
token = work;
}
}
}
entries[ numEntries ] = soundSystemLocal.soundCache->FindSound( token.c_str(), onDemand );
numEntries++;
}
} else {
src.Warning( "unknown token '%s'", token.c_str() );
return false;
}
}
if ( parms.shakes > 0.0f ) {
CheckShakesAndOgg();
}
return true;
}
/*
===============
idSoundShader::CheckShakesAndOgg
===============
*/
bool idSoundShader::CheckShakesAndOgg( void ) const {
int i;
bool ret = false;
for ( i = 0; i < numLeadins; i++ ) {
if ( leadins[ i ]->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) {
common->Warning( "sound shader '%s' has shakes and uses OGG file '%s'",
GetName(), leadins[ i ]->name.c_str() );
ret = true;
}
}
for ( i = 0; i < numEntries; i++ ) {
if ( entries[ i ]->objectInfo.wFormatTag == WAVE_FORMAT_TAG_OGG ) {
common->Warning( "sound shader '%s' has shakes and uses OGG file '%s'",
GetName(), entries[ i ]->name.c_str() );
ret = true;
}
}
return ret;
}
/*
===============
idSoundShader::List
===============
*/
void idSoundShader::List() const {
idStrList shaders;
common->Printf( "%4i: %s\n", Index(), GetName() );
if ( idStr::Icmp( GetDescription(), "<no description>" ) != 0 ) {
common->Printf( " description: %s\n", GetDescription() );
}
for( int k = 0; k < numLeadins ; k++ ) {
const idSoundSample *objectp = leadins[k];
if ( objectp ) {
common->Printf( " %5dms %4dKb %s (LEADIN)\n", soundSystemLocal.SamplesToMilliseconds(objectp->LengthIn44kHzSamples()), (objectp->objectMemSize/1024)
,objectp->name.c_str() );
}
}
for( int k = 0; k < numEntries; k++ ) {
const idSoundSample *objectp = entries[k];
if ( objectp ) {
common->Printf( " %5dms %4dKb %s\n", soundSystemLocal.SamplesToMilliseconds(objectp->LengthIn44kHzSamples()), (objectp->objectMemSize/1024)
,objectp->name.c_str() );
}
}
}
/*
===============
idSoundShader::GetAltSound
===============
*/
const idSoundShader *idSoundShader::GetAltSound( void ) const {
return altSound;
}
/*
===============
idSoundShader::GetMinDistance
===============
*/
float idSoundShader::GetMinDistance() const {
return parms.minDistance;
}
/*
===============
idSoundShader::GetMaxDistance
===============
*/
float idSoundShader::GetMaxDistance() const {
return parms.maxDistance;
}
/*
===============
idSoundShader::GetDescription
===============
*/
const char *idSoundShader::GetDescription() const {
return desc;
}
/*
===============
idSoundShader::HasDefaultSound
===============
*/
bool idSoundShader::HasDefaultSound() const {
for ( int i = 0; i < numEntries; i++ ) {
if ( entries[i] && entries[i]->defaultSound ) {
return true;
}
}
return false;
}
/*
===============
idSoundShader::GetParms
===============
*/
const soundShaderParms_t *idSoundShader::GetParms() const {
return &parms;
}
/*
===============
idSoundShader::GetNumSounds
===============
*/
int idSoundShader::GetNumSounds() const {
return numLeadins + numEntries;
}
/*
===============
idSoundShader::GetSound
===============
*/
const char *idSoundShader::GetSound( int index ) const {
if ( index >= 0 ) {
if ( index < numLeadins ) {
return leadins[index]->name.c_str();
}
index -= numLeadins;
if ( index < numEntries ) {
return entries[index]->name.c_str();
}
}
return "";
}