mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 08:39:40 +00:00
Added sound culling (experimental), and various fixes
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@27 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
e56c51b03e
commit
1e41012ff3
12 changed files with 119 additions and 84 deletions
2
Makefile
2
Makefile
|
@ -9,7 +9,7 @@ DMD=gdmd -version=Posix
|
|||
NIFFLAGS=
|
||||
|
||||
# Compiler settings for Ogre + OIS. Change as needed.
|
||||
OGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags OGRE OIS openal`
|
||||
OGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags OGRE OIS`
|
||||
|
||||
# Compiler settings for ffmpeg. Change as needed.
|
||||
AVGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags libavcodec libavformat`
|
||||
|
|
|
@ -113,7 +113,7 @@ Thanks goes out to:
|
|||
|
||||
- Bastien Jansen for continued testing on 64 bit linux.
|
||||
|
||||
- Chris Robinson for OpenAL and ALUT support
|
||||
- Chris Robinson for OpenAL and MP3 support
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -237,6 +237,8 @@ struct ConfigManager
|
|||
bind(Keys.SfxVolUp, KC.N4);
|
||||
bind(Keys.Mute, KC.M);
|
||||
|
||||
bind(Keys.Fullscreen, KC.F);
|
||||
|
||||
bind(Keys.ToggleBattleMusic, KC.SPACE);
|
||||
bind(Keys.Debug, KC.G);
|
||||
|
||||
|
|
|
@ -90,6 +90,11 @@ void toggleBattle()
|
|||
}
|
||||
}
|
||||
|
||||
void toggleFullscreen()
|
||||
{
|
||||
cpp_toggleFullscreen();
|
||||
}
|
||||
|
||||
const float volDiff = 0.05;
|
||||
|
||||
void musVolume(bool increase)
|
||||
|
@ -212,6 +217,7 @@ extern(C) void d_handleKey(KC keycode, dchar text = 0)
|
|||
case Keys.SfxVolUp: sfxVolume(true); break;
|
||||
case Keys.SfxVolDown: sfxVolume(false); break;
|
||||
case Keys.Mute: toggleMute(); break;
|
||||
case Keys.Fullscreen: toggleFullscreen(); break;
|
||||
|
||||
case Keys.Debug: cpp_debug(0); break;
|
||||
case Keys.ScreenShot: takeScreenShot(); break;
|
||||
|
@ -265,16 +271,14 @@ bool isPressed(Keys key)
|
|||
|
||||
extern(C) int d_frameStarted(float time)
|
||||
{
|
||||
/*
|
||||
tmpTime += time;
|
||||
cnt++;
|
||||
if(tmpTime >= 1.0)
|
||||
if(tmpTime >= 1.5)
|
||||
{
|
||||
writefln("\nfps: ", cnt/tmpTime);
|
||||
writefln("fps: ", cnt/tmpTime);
|
||||
cnt = 0;
|
||||
tmpTime = 0;
|
||||
}
|
||||
//*/
|
||||
|
||||
if(doExit) return 0;
|
||||
|
||||
|
|
|
@ -62,7 +62,8 @@ enum Keys
|
|||
SfxVolUp, SfxVolDown,
|
||||
Mute,
|
||||
|
||||
// This will not be part of the finished product :)
|
||||
// These will not be part of the finished product
|
||||
Fullscreen,
|
||||
ToggleBattleMusic,
|
||||
Debug,
|
||||
|
||||
|
@ -245,6 +246,7 @@ struct KeyBindings
|
|||
keyToString[Keys.SfxVolDown] = "Decrease SFX Volume";
|
||||
keyToString[Keys.Mute] = "Mute Sound";
|
||||
|
||||
keyToString[Keys.Fullscreen] = "Toggle Fullscreen Mode";
|
||||
keyToString[Keys.ToggleBattleMusic] = "Toggle Battle Music";
|
||||
keyToString[Keys.Debug] = "OGRE Test Action";
|
||||
|
||||
|
|
|
@ -137,6 +137,9 @@ void cpp_createMesh(
|
|||
NodePtr owner // Scene node to attach to.
|
||||
);
|
||||
|
||||
// Toggle fullscreen mode
|
||||
void cpp_toggleFullscreen();
|
||||
|
||||
// Save a screen shot to the given file name
|
||||
void cpp_screenshot(char *filename);
|
||||
|
||||
|
|
|
@ -215,9 +215,8 @@ extern "C" Light* cpp_attachLight(char *name, SceneNode* base,
|
|||
|
||||
l->setDiffuseColour(r,g,b);
|
||||
|
||||
// Pulled these numbers out of nowhere. Looks OK-ish. I can polish
|
||||
// it later.
|
||||
l->setAttenuation(8*radius, 0, 0.008, 0.0);
|
||||
// This seems to look reasonably ok.
|
||||
l->setAttenuation(3*radius, 0, 0, 12.0/(radius*radius));
|
||||
|
||||
// base might be null, sometimes lights don't have meshes
|
||||
if(base) base->attachObject(l);
|
||||
|
@ -225,6 +224,12 @@ extern "C" Light* cpp_attachLight(char *name, SceneNode* base,
|
|||
return l;
|
||||
}
|
||||
|
||||
// Toggle between fullscreen and windowed mode.
|
||||
extern "C" void cpp_toggleFullscreen()
|
||||
{
|
||||
std::cout << "Not implemented yet\n";
|
||||
}
|
||||
|
||||
extern "C" void cpp_setAmbient(float r, float g, float b, // Ambient light
|
||||
float rs, float gs, float bs) // "Sunlight"
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ Decrease Music Volume=1
|
|||
Increase SFX Volume=4
|
||||
Decrease SFX Volume=3
|
||||
Mute Sound=m
|
||||
Toggle Fullscreen Mode=f
|
||||
Toggle Battle Music=space
|
||||
OGRE Test Action=g
|
||||
Pause=pause,p
|
||||
|
|
|
@ -73,6 +73,10 @@ struct SoundList
|
|||
float upx, float upy, float upz)
|
||||
{
|
||||
SoundInstance.setPlayerPos(x,y,z,frontx,fronty,frontz,upx,upy,upz);
|
||||
foreach(ref s; list)
|
||||
{
|
||||
if(s.owner) s.updateSound();
|
||||
}
|
||||
}
|
||||
|
||||
void kill()
|
||||
|
|
|
@ -54,11 +54,6 @@ void initializeSound()
|
|||
|
||||
alcMakeContextCurrent(Context);
|
||||
|
||||
// Gross HACK: We should use the default model (inverse distance clamped).
|
||||
// But without a proper rolloff factor, distance attenuation is completely
|
||||
// wrong. This at least makes sure the max distance is the 'silence' point
|
||||
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
|
||||
|
||||
jukebox.initialize("Main");
|
||||
battleMusic.initialize("Battle");
|
||||
}
|
||||
|
@ -75,11 +70,14 @@ void shutdownSound()
|
|||
Device = null;
|
||||
}
|
||||
|
||||
ALenum checkALError()
|
||||
bool checkALError(char[] what = "")
|
||||
{
|
||||
ALenum err = alGetError();
|
||||
if(what.length) what = " while " ~ what;
|
||||
if(err != AL_NO_ERROR)
|
||||
writefln("WARNING: Received AL error (%x): %s", err,
|
||||
toString(alGetString(err)));
|
||||
return err;
|
||||
writefln("WARNING: OpenAL error%s: (%x) %s", what, err,
|
||||
toString(alGetString(err)));
|
||||
|
||||
|
||||
return err != AL_NO_ERROR;
|
||||
}
|
||||
|
|
102
sound/music.d
102
sound/music.d
|
@ -151,17 +151,19 @@ struct MusicManager
|
|||
if(!sID)
|
||||
{
|
||||
alGenSources(1, &sID);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
return;
|
||||
if(checkALError())
|
||||
fail("Couldn't generate music sources");
|
||||
alSourcei(sID, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
}
|
||||
|
||||
// Kill current track
|
||||
alSourceStop(sID);
|
||||
alSourcei(sID, AL_BUFFER, 0);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
checkALError();
|
||||
else
|
||||
{
|
||||
// Kill current track
|
||||
alSourceStop(sID);
|
||||
alSourcei(sID, AL_BUFFER, 0);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
bIDs[] = 0;
|
||||
checkALError("killing current track");
|
||||
}
|
||||
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
fileHandle = null;
|
||||
|
@ -175,35 +177,42 @@ struct MusicManager
|
|||
}
|
||||
|
||||
alGenBuffers(bIDs.length, bIDs.ptr);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
|
||||
// If something fails, clean everything up.
|
||||
scope(failure)
|
||||
{
|
||||
writefln("Unable to create %d buffers", bIDs.length);
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
|
||||
alSourceStop(sID);
|
||||
alDeleteSources(1, &sID);
|
||||
checkALError();
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
|
||||
checkALError("cleaning up after music failure");
|
||||
|
||||
sID = 0;
|
||||
return;
|
||||
bIDs[] = 0;
|
||||
|
||||
// Try the next track if playNext is called again
|
||||
index++;
|
||||
}
|
||||
|
||||
if(checkALError())
|
||||
fail("Couldn't generate buffers");
|
||||
|
||||
fileHandle = cpp_openAVFile(toStringz(playlist[index]));
|
||||
if(!fileHandle)
|
||||
{
|
||||
writefln("Unable to open %s", playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
fail("Unable to open " ~ playlist[index]);
|
||||
|
||||
audioHandle = cpp_getAVAudioStream(fileHandle, 0);
|
||||
if(!audioHandle)
|
||||
{
|
||||
writefln("Unable to load music track %s", playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
fail("Unable to load music track " ~ playlist[index]);
|
||||
|
||||
int ch, bits, rate;
|
||||
if(cpp_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
|
||||
{
|
||||
writefln("Unable to get info for music track %s", playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
fail("Unable to get info for music track " ~ playlist[index]);
|
||||
|
||||
bufRate = rate;
|
||||
bufFormat = 0;
|
||||
|
@ -221,24 +230,19 @@ struct MusicManager
|
|||
}
|
||||
|
||||
if(bufFormat == 0)
|
||||
{
|
||||
writefln("Unhandled format (%d channels, %d bits) for music track %s", ch, bits, playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
fail(format("Unhandled format (%d channels, %d bits) for music track %s", ch, bits, playlist[index]));
|
||||
|
||||
foreach(int i, ref b; bIDs)
|
||||
{
|
||||
int length = cpp_getAVAudioData(audioHandle, outData.ptr, outData.length);
|
||||
if(length) alBufferData(b, bufFormat, outData.ptr, length, bufRate);
|
||||
if(length == 0 || checkALError() != AL_NO_ERROR)
|
||||
if(length == 0 || checkALError())
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
writefln("No audio data in music track %s", playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
fail("No audio data in music track " ~ playlist[index]);
|
||||
|
||||
alDeleteBuffers(bIDs.length-i, bIDs.ptr+i);
|
||||
checkALError();
|
||||
checkALError("running alDeleteBuffers");
|
||||
bIDs[i..$] = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -246,25 +250,11 @@ struct MusicManager
|
|||
|
||||
alSourceQueueBuffers(sID, bIDs.length, bIDs.ptr);
|
||||
alSourcePlay(sID);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
{
|
||||
writefln("Unable to start music track %s", playlist[index]);
|
||||
goto errclose;
|
||||
}
|
||||
if(checkALError())
|
||||
fail("Unable to start music track " ~ playlist[index]);
|
||||
|
||||
index++;
|
||||
return;
|
||||
errclose:
|
||||
if(fileHandle) cpp_closeAVFile(fileHandle);
|
||||
fileHandle = null;
|
||||
audioHandle = null;
|
||||
alSourceStop(sID);
|
||||
alDeleteSources(1, &sID);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
checkALError();
|
||||
sID = 0;
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
index++;
|
||||
}
|
||||
|
||||
// Start playing the jukebox
|
||||
|
@ -289,13 +279,13 @@ struct MusicManager
|
|||
{
|
||||
alSourceStop(sID);
|
||||
alDeleteSources(1, &sID);
|
||||
checkALError();
|
||||
checkALError("disabling music");
|
||||
sID = 0;
|
||||
}
|
||||
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
checkALError();
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
checkALError("deleting music buffers");
|
||||
bIDs[] = 0;
|
||||
|
||||
musicOn = false;
|
||||
}
|
||||
|
@ -326,7 +316,7 @@ struct MusicManager
|
|||
|
||||
ALint count;
|
||||
alGetSourcei(sID, AL_BUFFERS_PROCESSED, &count);
|
||||
if(checkALError() != AL_NO_ERROR) return false;
|
||||
if(checkALError("in isPlaying()")) return false;
|
||||
|
||||
for(int i = 0;i < count;i++)
|
||||
{
|
||||
|
@ -337,7 +327,7 @@ struct MusicManager
|
|||
{
|
||||
ALint state;
|
||||
alGetSourcei(sID, AL_SOURCE_STATE, &state);
|
||||
if(checkALError() != AL_NO_ERROR || state == AL_STOPPED)
|
||||
if(checkALError() || state == AL_STOPPED)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
44
sound/sfx.d
44
sound/sfx.d
|
@ -119,7 +119,7 @@ struct SoundFile
|
|||
{
|
||||
alGenBuffers(1, &bID);
|
||||
alBufferData(bID, fmt, outData.ptr, total, rate);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
if(checkALError())
|
||||
{
|
||||
writefln("Unable to load sound %s", file);
|
||||
alDeleteBuffers(1, &bID);
|
||||
|
@ -143,11 +143,11 @@ struct SoundFile
|
|||
SoundInstance si;
|
||||
si.owner = this;
|
||||
alGenSources(1, &si.inst);
|
||||
if(checkALError() != AL_NO_ERROR || !si.inst)
|
||||
if(checkALError() || !si.inst)
|
||||
fail("Failed to instantiate sound resource");
|
||||
|
||||
alSourcei(si.inst, AL_BUFFER, cast(ALint)bID);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
if(checkALError())
|
||||
{
|
||||
alDeleteSources(1, &si.inst);
|
||||
fail("Failed to load sound resource");
|
||||
|
@ -177,6 +177,7 @@ struct SoundFile
|
|||
struct SoundInstance
|
||||
{
|
||||
ALuint inst;
|
||||
ALfloat volume;
|
||||
SoundFile *owner;
|
||||
|
||||
// Return this instance to the owner
|
||||
|
@ -190,14 +191,14 @@ struct SoundInstance
|
|||
void play()
|
||||
{
|
||||
alSourcePlay(inst);
|
||||
checkALError();
|
||||
checkALError("playing sound instance");
|
||||
}
|
||||
|
||||
// Go buy a cookie
|
||||
void stop()
|
||||
{
|
||||
alSourceStop(inst);
|
||||
checkALError();
|
||||
checkALError("stopping sound instance");
|
||||
}
|
||||
|
||||
// Set parameters such as max volume and range
|
||||
|
@ -208,12 +209,13 @@ struct SoundInstance
|
|||
}
|
||||
body
|
||||
{
|
||||
alSourcef(inst, AL_GAIN, volume);
|
||||
this.volume = volume;
|
||||
alSourcef(inst, AL_GAIN, 0);
|
||||
alSourcef(inst, AL_REFERENCE_DISTANCE, minRange);
|
||||
alSourcef(inst, AL_MAX_DISTANCE, maxRange);
|
||||
alSourcei(inst, AL_LOOPING, repeat ? AL_TRUE : AL_FALSE);
|
||||
alSourcePlay(inst);
|
||||
checkALError();
|
||||
checkALError("setting sound parameters");
|
||||
}
|
||||
|
||||
// Set 3D position of sounds. Need to convert from app's world coords to
|
||||
|
@ -221,7 +223,31 @@ struct SoundInstance
|
|||
void setPos(float x, float y, float z)
|
||||
{
|
||||
alSource3f(inst, AL_POSITION, x, z, -y);
|
||||
checkALError();
|
||||
checkALError("setting sound position");
|
||||
}
|
||||
|
||||
// TODO: This should probably be merged in setPos. All active sounds
|
||||
// should respecify their position after the listener does, which would
|
||||
// be ideal for keeping moving sounds moving while handling distance
|
||||
// culling for moving and stationary sounds
|
||||
void updateSound()
|
||||
{
|
||||
ALfloat lp[3];
|
||||
ALfloat p[3];
|
||||
ALfloat dist;
|
||||
alGetSourcef(inst, AL_MAX_DISTANCE, &dist);
|
||||
alGetSourcefv(inst, AL_POSITION, p.ptr);
|
||||
alGetListenerfv(AL_POSITION, lp.ptr);
|
||||
if(!checkALError("updating sound position"))
|
||||
{
|
||||
p[0] -= lp[0];
|
||||
p[1] -= lp[1];
|
||||
p[2] -= lp[2];
|
||||
if((p[0]*p[0] + p[1]*p[1] + p[2]*p[2]) > dist*dist)
|
||||
alSourcef(inst, AL_GAIN, 0);
|
||||
else
|
||||
alSourcef(inst, AL_GAIN, volume);
|
||||
}
|
||||
}
|
||||
|
||||
static void setPlayerPos(float x, float y, float z,
|
||||
|
@ -237,6 +263,6 @@ struct SoundInstance
|
|||
orient[5] =-upy;
|
||||
alListener3f(AL_POSITION, x, z, -y);
|
||||
alListenerfv(AL_ORIENTATION, orient.ptr);
|
||||
checkALError();
|
||||
checkALError("setting player position");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue