diff --git a/include/SFML/Audio/Sound.hpp b/include/SFML/Audio/Sound.hpp index cdfd0783..7b4ef3c5 100644 --- a/include/SFML/Audio/Sound.hpp +++ b/include/SFML/Audio/Sound.hpp @@ -201,6 +201,17 @@ public : //////////////////////////////////////////////////////////// Sound& operator =(const Sound& right); + //////////////////////////////////////////////////////////// + /// \brief Reset the internal buffer of the sound + /// + /// This function is for internal use only, you don't have + /// to use it. It is called by the sf::SoundBuffer that + /// this sound uses, when it is destroyed in order to prevent + /// the sound from using a dead buffer. + /// + //////////////////////////////////////////////////////////// + void ResetBuffer(); + private : //////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundBuffer.hpp b/include/SFML/Audio/SoundBuffer.hpp index 86318671..af9a2c65 100644 --- a/include/SFML/Audio/SoundBuffer.hpp +++ b/include/SFML/Audio/SoundBuffer.hpp @@ -32,10 +32,13 @@ #include #include #include +#include namespace sf { +class Sound; + //////////////////////////////////////////////////////////// /// \brief Storage for audio samples defining a sound /// @@ -220,12 +223,34 @@ private : //////////////////////////////////////////////////////////// bool Update(unsigned int channelsCount, unsigned int sampleRate); + //////////////////////////////////////////////////////////// + /// \brief Add a sound to the list of sounds that use this buffer + /// + /// \param sound Sound instance to attach + /// + //////////////////////////////////////////////////////////// + void AttachSound(Sound* sound) const; + + //////////////////////////////////////////////////////////// + /// \brief Remove a sound from the list of sounds that use this buffer + /// + /// \param sound Sound instance to detach + /// + //////////////////////////////////////////////////////////// + void DetachSound(Sound* sound) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::set SoundList; ///< Set of unique sound instances + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// unsigned int myBuffer; ///< OpenAL buffer identifier std::vector mySamples; ///< Samples buffer float myDuration; ///< Sound duration, in seconds + mutable SoundList mySounds; ///< List of sounds that are using this buffer }; } // namespace sf diff --git a/src/SFML/Audio/ALCheck.cpp b/src/SFML/Audio/ALCheck.cpp index fdfda895..0572abf5 100644 --- a/src/SFML/Audio/ALCheck.cpp +++ b/src/SFML/Audio/ALCheck.cpp @@ -1,94 +1,94 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include - - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -void ALCheckError(const std::string& file, unsigned int line) -{ - // Get the last error - ALenum errorCode = alGetError(); - - if (errorCode != AL_NO_ERROR) - { - std::string error, description; - - // Decode the error code - switch (errorCode) - { - case AL_INVALID_NAME : - { - error = "AL_INVALID_NAME"; - description = "an unacceptable name has been specified"; - break; - } - - case AL_INVALID_ENUM : - { - error = "AL_INVALID_ENUM"; - description = "an unacceptable value has been specified for an enumerated argument"; - break; - } - - case AL_INVALID_VALUE : - { - error = "AL_INVALID_VALUE"; - description = "a numeric argument is out of range"; - break; - } - - case AL_INVALID_OPERATION : - { - error = "AL_INVALID_OPERATION"; - description = "the specified operation is not allowed in the current state"; - break; - } - - case AL_OUT_OF_MEMORY : - { - error = "AL_OUT_OF_MEMORY"; - description = "there is not enough memory left to execute the command"; - break; - } - } - - // Log the error - std::cerr << "An internal OpenAL call failed in " - << file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : " - << error << ", " << description - << std::endl; - } -} +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +void ALCheckError(const std::string& file, unsigned int line) +{ + // Get the last error + ALenum errorCode = alGetError(); + + if (errorCode != AL_NO_ERROR) + { + std::string error, description; + + // Decode the error code + switch (errorCode) + { + case AL_INVALID_NAME : + { + error = "AL_INVALID_NAME"; + description = "an unacceptable name has been specified"; + break; + } + + case AL_INVALID_ENUM : + { + error = "AL_INVALID_ENUM"; + description = "an unacceptable value has been specified for an enumerated argument"; + break; + } + + case AL_INVALID_VALUE : + { + error = "AL_INVALID_VALUE"; + description = "a numeric argument is out of range"; + break; + } + + case AL_INVALID_OPERATION : + { + error = "AL_INVALID_OPERATION"; + description = "the specified operation is not allowed in the current state"; + break; + } + + case AL_OUT_OF_MEMORY : + { + error = "AL_OUT_OF_MEMORY"; + description = "there is not enough memory left to execute the command"; + break; + } + } + + // Log the error + std::cerr << "An internal OpenAL call failed in " + << file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : " + << error << ", " << description + << std::endl; + } +} //////////////////////////////////////////////////////////// @@ -98,11 +98,11 @@ void EnsureALInit() { // The audio device is instanciated on demand rather than at global startup, // which solves a lot of weird crashes and errors. - /// It is destroyed at global exit which is fine. + // It is destroyed at global exit which is fine. static AudioDevice globalDevice; } - -} // namespace priv - -} // namespace sf + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Audio/Sound.cpp b/src/SFML/Audio/Sound.cpp index 86baca43..f1c59ddb 100644 --- a/src/SFML/Audio/Sound.cpp +++ b/src/SFML/Audio/Sound.cpp @@ -65,6 +65,8 @@ myBuffer (NULL) Sound::~Sound() { Stop(); + if (myBuffer) + myBuffer->DetachSound(this); } @@ -92,7 +94,16 @@ void Sound::Stop() //////////////////////////////////////////////////////////// void Sound::SetBuffer(const SoundBuffer& buffer) { + // First detach from the previous buffer + if (myBuffer) + { + Stop(); + myBuffer->DetachSound(this); + } + + // Assign and use the new buffer myBuffer = &buffer; + myBuffer->AttachSound(this); ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer)); } @@ -148,12 +159,41 @@ Sound::Status Sound::GetStatus() const //////////////////////////////////////////////////////////// Sound& Sound::operator =(const Sound& right) { - Sound temp(right); + // Here we don't use the copy-and-swap idiom, because it would mess up + // the list of sound instances contained in the buffers - std::swap(mySource, temp.mySource); - std::swap(myBuffer, temp.myBuffer); + // Detach the sound instance from the previous buffer (if any) + if (myBuffer) + { + Stop(); + myBuffer->DetachSound(this); + myBuffer = NULL; + } + + // Copy the sound attributes + if (right.myBuffer) + SetBuffer(*right.myBuffer); + SetLoop(right.GetLoop()); + SetPitch(right.GetPitch()); + SetVolume(right.GetVolume()); + SetPosition(right.GetPosition()); + SetRelativeToListener(right.IsRelativeToListener()); + SetMinDistance(right.GetMinDistance()); + SetAttenuation(right.GetAttenuation()); return *this; } + +//////////////////////////////////////////////////////////// +void Sound::ResetBuffer() +{ + // First stop the sound in case it is playing + Stop(); + + // Detach the buffer + ALCheck(alSourcei(mySource, AL_BUFFER, 0)); + myBuffer = NULL; +} + } // namespace sf diff --git a/src/SFML/Audio/SoundBuffer.cpp b/src/SFML/Audio/SoundBuffer.cpp index ec498e8a..d5b56c7f 100644 --- a/src/SFML/Audio/SoundBuffer.cpp +++ b/src/SFML/Audio/SoundBuffer.cpp @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include #include @@ -49,10 +50,10 @@ myDuration(0.f) //////////////////////////////////////////////////////////// SoundBuffer::SoundBuffer(const SoundBuffer& copy) : -Resource(copy), -myBuffer (0), -mySamples (copy.mySamples), -myDuration (copy.myDuration) +myBuffer (0), +mySamples (copy.mySamples), +myDuration(copy.myDuration), +mySounds () // don't copy the attached sounds { // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); @@ -65,6 +66,11 @@ myDuration (copy.myDuration) //////////////////////////////////////////////////////////// SoundBuffer::~SoundBuffer() { + // First detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = mySounds.begin(); it != mySounds.end(); ++it) + (*it)->ResetBuffer(); + + // Destroy the buffer if (myBuffer) ALCheck(alDeleteBuffers(1, &myBuffer)); } @@ -223,9 +229,10 @@ SoundBuffer& SoundBuffer::operator =(const SoundBuffer& other) { SoundBuffer temp(other); - mySamples.swap(temp.mySamples); + std::swap(mySamples, temp.mySamples); std::swap(myBuffer, temp.myBuffer); std::swap(myDuration, temp.myDuration); + std::swap(mySounds, temp.mySounds); // swap sounds too, so that they are detached when temp is destroyed return *this; } @@ -258,4 +265,18 @@ bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate) return true; } + +//////////////////////////////////////////////////////////// +void SoundBuffer::AttachSound(Sound* sound) const +{ + mySounds.insert(sound); +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::DetachSound(Sound* sound) const +{ + mySounds.erase(sound); +} + } // namespace sf diff --git a/src/SFML/Graphics/Image.cpp b/src/SFML/Graphics/Image.cpp index 2e06fbc3..eb588301 100644 --- a/src/SFML/Graphics/Image.cpp +++ b/src/SFML/Graphics/Image.cpp @@ -59,8 +59,7 @@ myPixelsFlipped (false) //////////////////////////////////////////////////////////// /// Copy constructor //////////////////////////////////////////////////////////// -Image::Image(const Image& copy) : -Resource(copy) +Image::Image(const Image& copy) { // First make sure that the source image is up-to-date copy.EnsureArrayUpdate(); diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index 2bd74126..00cc5745 100644 --- a/src/SFML/Graphics/Text.cpp +++ b/src/SFML/Graphics/Text.cpp @@ -222,12 +222,12 @@ void Text::Render(RenderTarget&, Renderer& renderer) const renderer.SetTexture(&myFont->GetImage(myCharacterSize)); // Computes values related to the text style - bool bold = (myStyle & Bold) != 0; - bool underlined = (myStyle & Underlined) != 0; - float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees - float outlineOffset = myCharacterSize * 0.1f; - float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f); - FloatRect outlineCoords = myFont->GetImage(myCharacterSize).GetTexCoords(IntRect(1, 1, 1, 1)); + bool bold = (myStyle & Bold) != 0; + bool underlined = (myStyle & Underlined) != 0; + float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees + float underlineOffset = myCharacterSize * 0.1f; + float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f); + FloatRect underlineCoords = myFont->GetImage(myCharacterSize).GetTexCoords(IntRect(1, 1, 1, 1)); // Initialize the rendering coordinates float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); @@ -252,14 +252,14 @@ void Text::Render(RenderTarget&, Renderer& renderer) const // If we're using the underlined style and there's a new line, draw a line if (underlined && (curChar == L'\n')) { - float top = y + outlineOffset; - float bottom = top + outlineThick; + float top = y + underlineOffset; + float bottom = top + underlineThickness; renderer.Begin(Renderer::QuadList); - renderer.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top); - renderer.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top); - renderer.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom); - renderer.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom); + renderer.AddVertex(0, top, underlineCoords.Left, underlineCoords.Top); + renderer.AddVertex(x, top, underlineCoords.Right, underlineCoords.Top); + renderer.AddVertex(x, bottom, underlineCoords.Right, underlineCoords.Bottom); + renderer.AddVertex(0, bottom, underlineCoords.Left, underlineCoords.Bottom); renderer.End(); } @@ -293,14 +293,14 @@ void Text::Render(RenderTarget&, Renderer& renderer) const // If we're using the underlined style, add the last line if (underlined) { - float top = y + outlineOffset; - float bottom = top + outlineThick; + float top = y + underlineOffset; + float bottom = top + underlineThickness; renderer.Begin(Renderer::QuadList); - renderer.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top); - renderer.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top); - renderer.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom); - renderer.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom); + renderer.AddVertex(0, top, underlineCoords.Left, underlineCoords.Top); + renderer.AddVertex(x, top, underlineCoords.Right, underlineCoords.Top); + renderer.AddVertex(x, bottom, underlineCoords.Right, underlineCoords.Bottom); + renderer.AddVertex(0, bottom, underlineCoords.Left, underlineCoords.Bottom); renderer.End(); } } @@ -323,17 +323,15 @@ void Text::UpdateRect() const return; // Initial values - bool bold = (myStyle & Bold) != 0; - float outlineOffset = myCharacterSize * 0.1f; - float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f); - float charSize = static_cast(myCharacterSize); - float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); - float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); - float curWidth = 0; - float curHeight = 0; - float width = 0; - float height = 0; - Uint32 prevChar = 0; + bool bold = (myStyle & Bold) != 0; + float charSize = static_cast(myCharacterSize); + float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); + float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); + float curWidth = 0; + float curHeight = 0; + float width = 0; + float height = 0; + Uint32 prevChar = 0; // Go through each character for (std::size_t i = 0; i < myString.GetSize(); ++i) @@ -395,8 +393,11 @@ void Text::UpdateRect() const // Add a slight height if we're using the underlined style if (myStyle & Underlined) { - if (curHeight < charSize + outlineOffset + outlineThick) - height += outlineOffset + outlineThick; + float underlineOffset = myCharacterSize * 0.1f; + float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f); + + if (curHeight < charSize + underlineOffset + underlineThickness) + height += underlineOffset + underlineThickness; } // Finally update the rectangle