Synchronized with trunk

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1372 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2010-01-26 10:52:36 +00:00
commit 57194f4d4b
7 changed files with 234 additions and 137 deletions

View File

@ -201,6 +201,17 @@ public :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Sound& operator =(const Sound& right); 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 : private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -32,10 +32,13 @@
#include <SFML/System/Resource.hpp> #include <SFML/System/Resource.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
namespace sf namespace sf
{ {
class Sound;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Storage for audio samples defining a sound /// \brief Storage for audio samples defining a sound
/// ///
@ -220,12 +223,34 @@ private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Update(unsigned int channelsCount, unsigned int sampleRate); 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<Sound*> SoundList; ///< Set of unique sound instances
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int myBuffer; ///< OpenAL buffer identifier unsigned int myBuffer; ///< OpenAL buffer identifier
std::vector<Int16> mySamples; ///< Samples buffer std::vector<Int16> mySamples; ///< Samples buffer
float myDuration; ///< Sound duration, in seconds float myDuration; ///< Sound duration, in seconds
mutable SoundList mySounds; ///< List of sounds that are using this buffer
}; };
} // namespace sf } // namespace sf

View File

@ -1,94 +1,94 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// SFML - Simple and Fast Multimedia Library // SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
// //
// This software is provided 'as-is', without any express or implied warranty. // 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. // 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, // Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely, // including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions: // subject to the following restrictions:
// //
// 1. The origin of this software must not be misrepresented; // 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software. // you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment // If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required. // in the product documentation would be appreciated but is not required.
// //
// 2. Altered source versions must be plainly marked as such, // 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software. // and must not be misrepresented as being the original software.
// //
// 3. This notice may not be removed or altered from any source distribution. // 3. This notice may not be removed or altered from any source distribution.
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp> #include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/AudioDevice.hpp> #include <SFML/Audio/AudioDevice.hpp>
namespace sf namespace sf
{ {
namespace priv namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void ALCheckError(const std::string& file, unsigned int line) void ALCheckError(const std::string& file, unsigned int line)
{ {
// Get the last error // Get the last error
ALenum errorCode = alGetError(); ALenum errorCode = alGetError();
if (errorCode != AL_NO_ERROR) if (errorCode != AL_NO_ERROR)
{ {
std::string error, description; std::string error, description;
// Decode the error code // Decode the error code
switch (errorCode) switch (errorCode)
{ {
case AL_INVALID_NAME : case AL_INVALID_NAME :
{ {
error = "AL_INVALID_NAME"; error = "AL_INVALID_NAME";
description = "an unacceptable name has been specified"; description = "an unacceptable name has been specified";
break; break;
} }
case AL_INVALID_ENUM : case AL_INVALID_ENUM :
{ {
error = "AL_INVALID_ENUM"; error = "AL_INVALID_ENUM";
description = "an unacceptable value has been specified for an enumerated argument"; description = "an unacceptable value has been specified for an enumerated argument";
break; break;
} }
case AL_INVALID_VALUE : case AL_INVALID_VALUE :
{ {
error = "AL_INVALID_VALUE"; error = "AL_INVALID_VALUE";
description = "a numeric argument is out of range"; description = "a numeric argument is out of range";
break; break;
} }
case AL_INVALID_OPERATION : case AL_INVALID_OPERATION :
{ {
error = "AL_INVALID_OPERATION"; error = "AL_INVALID_OPERATION";
description = "the specified operation is not allowed in the current state"; description = "the specified operation is not allowed in the current state";
break; break;
} }
case AL_OUT_OF_MEMORY : case AL_OUT_OF_MEMORY :
{ {
error = "AL_OUT_OF_MEMORY"; error = "AL_OUT_OF_MEMORY";
description = "there is not enough memory left to execute the command"; description = "there is not enough memory left to execute the command";
break; break;
} }
} }
// Log the error // Log the error
std::cerr << "An internal OpenAL call failed in " std::cerr << "An internal OpenAL call failed in "
<< file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : " << file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : "
<< error << ", " << description << error << ", " << description
<< std::endl; << std::endl;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -98,11 +98,11 @@ void EnsureALInit()
{ {
// The audio device is instanciated on demand rather than at global startup, // The audio device is instanciated on demand rather than at global startup,
// which solves a lot of weird crashes and errors. // 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; static AudioDevice globalDevice;
} }
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -65,6 +65,8 @@ myBuffer (NULL)
Sound::~Sound() Sound::~Sound()
{ {
Stop(); Stop();
if (myBuffer)
myBuffer->DetachSound(this);
} }
@ -92,7 +94,16 @@ void Sound::Stop()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::SetBuffer(const SoundBuffer& buffer) 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 = &buffer;
myBuffer->AttachSound(this);
ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer)); ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer));
} }
@ -148,12 +159,41 @@ Sound::Status Sound::GetStatus() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Sound& Sound::operator =(const Sound& right) 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); // Detach the sound instance from the previous buffer (if any)
std::swap(myBuffer, temp.myBuffer); 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; 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 } // namespace sf

View File

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundBuffer.hpp> #include <SFML/Audio/SoundBuffer.hpp>
#include <SFML/Audio/SoundFile.hpp> #include <SFML/Audio/SoundFile.hpp>
#include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/AudioDevice.hpp> #include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/ALCheck.hpp> #include <SFML/Audio/ALCheck.hpp>
#include <iostream> #include <iostream>
@ -49,10 +50,10 @@ myDuration(0.f)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const SoundBuffer& copy) : SoundBuffer::SoundBuffer(const SoundBuffer& copy) :
Resource<SoundBuffer>(copy), myBuffer (0),
myBuffer (0), mySamples (copy.mySamples),
mySamples (copy.mySamples), myDuration(copy.myDuration),
myDuration (copy.myDuration) mySounds () // don't copy the attached sounds
{ {
// Create the buffer // Create the buffer
ALCheck(alGenBuffers(1, &myBuffer)); ALCheck(alGenBuffers(1, &myBuffer));
@ -65,6 +66,11 @@ myDuration (copy.myDuration)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundBuffer::~SoundBuffer() 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) if (myBuffer)
ALCheck(alDeleteBuffers(1, &myBuffer)); ALCheck(alDeleteBuffers(1, &myBuffer));
} }
@ -223,9 +229,10 @@ SoundBuffer& SoundBuffer::operator =(const SoundBuffer& other)
{ {
SoundBuffer temp(other); SoundBuffer temp(other);
mySamples.swap(temp.mySamples); std::swap(mySamples, temp.mySamples);
std::swap(myBuffer, temp.myBuffer); std::swap(myBuffer, temp.myBuffer);
std::swap(myDuration, temp.myDuration); std::swap(myDuration, temp.myDuration);
std::swap(mySounds, temp.mySounds); // swap sounds too, so that they are detached when temp is destroyed
return *this; return *this;
} }
@ -258,4 +265,18 @@ bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate)
return true; return true;
} }
////////////////////////////////////////////////////////////
void SoundBuffer::AttachSound(Sound* sound) const
{
mySounds.insert(sound);
}
////////////////////////////////////////////////////////////
void SoundBuffer::DetachSound(Sound* sound) const
{
mySounds.erase(sound);
}
} // namespace sf } // namespace sf

View File

@ -59,8 +59,7 @@ myPixelsFlipped (false)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Copy constructor /// Copy constructor
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Image::Image(const Image& copy) : Image::Image(const Image& copy)
Resource<Image>(copy)
{ {
// First make sure that the source image is up-to-date // First make sure that the source image is up-to-date
copy.EnsureArrayUpdate(); copy.EnsureArrayUpdate();

View File

@ -222,12 +222,12 @@ void Text::Render(RenderTarget&, Renderer& renderer) const
renderer.SetTexture(&myFont->GetImage(myCharacterSize)); renderer.SetTexture(&myFont->GetImage(myCharacterSize));
// Computes values related to the text style // Computes values related to the text style
bool bold = (myStyle & Bold) != 0; bool bold = (myStyle & Bold) != 0;
bool underlined = (myStyle & Underlined) != 0; bool underlined = (myStyle & Underlined) != 0;
float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
float outlineOffset = myCharacterSize * 0.1f; float underlineOffset = myCharacterSize * 0.1f;
float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f); float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f);
FloatRect outlineCoords = myFont->GetImage(myCharacterSize).GetTexCoords(IntRect(1, 1, 1, 1)); FloatRect underlineCoords = myFont->GetImage(myCharacterSize).GetTexCoords(IntRect(1, 1, 1, 1));
// Initialize the rendering coordinates // Initialize the rendering coordinates
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); float space = static_cast<float>(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 we're using the underlined style and there's a new line, draw a line
if (underlined && (curChar == L'\n')) if (underlined && (curChar == L'\n'))
{ {
float top = y + outlineOffset; float top = y + underlineOffset;
float bottom = top + outlineThick; float bottom = top + underlineThickness;
renderer.Begin(Renderer::QuadList); renderer.Begin(Renderer::QuadList);
renderer.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top); renderer.AddVertex(0, top, underlineCoords.Left, underlineCoords.Top);
renderer.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top); renderer.AddVertex(x, top, underlineCoords.Right, underlineCoords.Top);
renderer.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom); renderer.AddVertex(x, bottom, underlineCoords.Right, underlineCoords.Bottom);
renderer.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom); renderer.AddVertex(0, bottom, underlineCoords.Left, underlineCoords.Bottom);
renderer.End(); 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 we're using the underlined style, add the last line
if (underlined) if (underlined)
{ {
float top = y + outlineOffset; float top = y + underlineOffset;
float bottom = top + outlineThick; float bottom = top + underlineThickness;
renderer.Begin(Renderer::QuadList); renderer.Begin(Renderer::QuadList);
renderer.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top); renderer.AddVertex(0, top, underlineCoords.Left, underlineCoords.Top);
renderer.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top); renderer.AddVertex(x, top, underlineCoords.Right, underlineCoords.Top);
renderer.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom); renderer.AddVertex(x, bottom, underlineCoords.Right, underlineCoords.Bottom);
renderer.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom); renderer.AddVertex(0, bottom, underlineCoords.Left, underlineCoords.Bottom);
renderer.End(); renderer.End();
} }
} }
@ -323,17 +323,15 @@ void Text::UpdateRect() const
return; return;
// Initial values // Initial values
bool bold = (myStyle & Bold) != 0; bool bold = (myStyle & Bold) != 0;
float outlineOffset = myCharacterSize * 0.1f; float charSize = static_cast<float>(myCharacterSize);
float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f); float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
float charSize = static_cast<float>(myCharacterSize); float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); float curWidth = 0;
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize)); float curHeight = 0;
float curWidth = 0; float width = 0;
float curHeight = 0; float height = 0;
float width = 0; Uint32 prevChar = 0;
float height = 0;
Uint32 prevChar = 0;
// Go through each character // Go through each character
for (std::size_t i = 0; i < myString.GetSize(); ++i) 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 // Add a slight height if we're using the underlined style
if (myStyle & Underlined) if (myStyle & Underlined)
{ {
if (curHeight < charSize + outlineOffset + outlineThick) float underlineOffset = myCharacterSize * 0.1f;
height += outlineOffset + outlineThick; float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f);
if (curHeight < charSize + underlineOffset + underlineThickness)
height += underlineOffset + underlineThickness;
} }
// Finally update the rectangle // Finally update the rectangle