From c1d5470baf3d6fbdff821b934f7b30c430c2ab9e Mon Sep 17 00:00:00 2001 From: ParadoxZero Date: Mon, 19 Dec 2016 13:39:21 +0530 Subject: [PATCH 01/10] Linux build failing due to weird reason --- Examples/Most_simple_menu.cpp | 31 +++++++++++++++++++ GameMenu.sln | 6 ++++ GameMenu.vcxproj | 33 +++++++++++++++++++- include/GameMenu/GameMenu.h | 56 ++++++++++++++++++++++++++-------- lib/libGameMenu.a | Bin 377544 -> 377462 bytes src/GameMenu/GameMenu.cpp | 25 ++++++--------- tests/sample_menu.cpp | 29 ++++++++++++++++++ 7 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 Examples/Most_simple_menu.cpp create mode 100644 tests/sample_menu.cpp diff --git a/Examples/Most_simple_menu.cpp b/Examples/Most_simple_menu.cpp new file mode 100644 index 0000000..7164781 --- /dev/null +++ b/Examples/Most_simple_menu.cpp @@ -0,0 +1,31 @@ +#include "GameMenu\GameMenu.h" +#include + +namespace test { + class testAction : public gmenu::Action { + public: + bool start() { + return true; + } + }; +} + +void main() { + sf::RenderWindow w( sf::VideoMode( 800, 800 ), "Test", sf::Style::Close ); + gmenu::MenuItem item[3]; + std::string text[3] = { "Hello", "World","!!!" }; + sf::Font font; + font.loadFromFile( "sansation.ttf" ); + for ( int i = 0; i < 3; ++i ) { + item[i].title = text[i]; + item[i].action = new test::testAction(); + } + gmenu::Style style; + style.TitleFont = font; + style.ItemFont = font; + style.ItemColor = sf::Color::Blue; + style.Selected = sf::Color::Yellow; + style.ItemFontSize = 30; + gmenu::Menu menu( &w, "Sample Menu", item, 3, style ); + menu.createMenu(); +} diff --git a/GameMenu.sln b/GameMenu.sln index d23161e..cfbacf0 100644 --- a/GameMenu.sln +++ b/GameMenu.sln @@ -11,6 +11,8 @@ Global Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 + Test|x64 = Test|x64 + Test|x86 = Test|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Debug|x64.ActiveCfg = Debug|x64 @@ -21,6 +23,10 @@ Global {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x64.Build.0 = Release|x64 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.ActiveCfg = Release|Win32 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.Build.0 = Release|Win32 + {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x64.ActiveCfg = Test|x64 + {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x64.Build.0 = Test|x64 + {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x86.ActiveCfg = Test|Win32 + {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x86.Build.0 = Test|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GameMenu.vcxproj b/GameMenu.vcxproj index 3ec6633..6a4bb80 100644 --- a/GameMenu.vcxproj +++ b/GameMenu.vcxproj @@ -17,6 +17,14 @@ Release x64 + + Test + Win32 + + + Test + x64 + {02870BF4-F128-4D1D-AB7C-6720D328CBDC} @@ -51,6 +59,12 @@ true Unicode + + v140 + + + v140 + @@ -69,7 +83,12 @@ - + + C:\Users\sidhi\libraries\SFML-2.4.1\include;C:\Users\sidhi\Desktop\Projects\GameMenu\include;$(IncludePath) + + + C:\Users\sidhi\libraries\SFML-2.4.1\include;C:\Users\sidhi\Desktop\Projects\GameMenu\include;$(IncludePath) + @@ -134,6 +153,18 @@ true + + + C:\Users\sidhi\Desktop\Projects\GameMenu\lib;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) + sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;%(AdditionalDependencies) + + + + + C:\Users\sidhi\Desktop\Projects\GameMenu\lib;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) + sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;%(AdditionalDependencies) + + diff --git a/include/GameMenu/GameMenu.h b/include/GameMenu/GameMenu.h index d13fafe..1d94725 100644 --- a/include/GameMenu/GameMenu.h +++ b/include/GameMenu/GameMenu.h @@ -30,18 +30,51 @@ namespace gmenu { struct MenuItem { Action *action; std::string title; - sf::Font font; }; + enum Layout { + TitleCentre, + TitleRight, + TitleLeft, + + ItemCentre, + ItemRight, + ItemLeft, + + }; + + struct Style { + sf::Font TitleFont; + sf::Font ItemFont; + sf::Color TitleColor; + sf::Color ItemColor; + sf::Color Selected; + unsigned int TitleFontSize; + unsigned int ItemFontSize; + Layout layout; + Style() { + TitleColor = sf::Color::Green; + ItemColor = sf::Color::Red; + Selected = sf::Color::Blue; + ItemFontSize = 20; + TitleFontSize = 50; + } + }; + + + + + class Menu { /* Generic Menu - can be instantiated to generate a custom menu as needed over a sf::RenderWindow */ public: /* Only accesible constructor */ - Menu(sf::RenderWindow *window, std::string title,sf::Font titleFont, MenuItem* items, int8_t length) - : Menu(window, title, titleFont) { + Menu(sf::RenderWindow *window, std::string title, MenuItem* items, int8_t length, Style style) + : Menu(window, title) { setMenuItems(items, length); + this->style = style; } @@ -58,7 +91,7 @@ namespace gmenu { void setMenuItems(MenuItem *, int8_t); /* In case the title needs to be changed */ - void setTitle(std::string title, sf::Font font); + void setTitle(std::string title); private: @@ -68,12 +101,12 @@ namespace gmenu { } - Menu( sf::RenderWindow *window, std::string title, sf::Font titleFont ) : Menu( window ) { - setTitle( title, titleFont ); + Menu( sf::RenderWindow *window, std::string title ) : Menu( window ) { + setTitle( title); } void writeText( std::string string, sf::Font font, unsigned int size, float x, float y, - const sf::Color &color = sf::Color::White ); + const sf::Color &color); void setMenu(); @@ -91,12 +124,11 @@ namespace gmenu { struct coordinates { coordinates() { - x = y = 0.f; size = 0; + x = y = 0.f; } float x; float y; - int size; - } *menu_location, title_location; + } *item_location, title_location; /*==================================================* @@ -105,8 +137,8 @@ namespace gmenu { int currently_selected_item = 0; - sf::Font MenuItemFont; - sf::Font MenuTitleFont; + Style style; + sf::RenderWindow *window; std::string menu_title; diff --git a/lib/libGameMenu.a b/lib/libGameMenu.a index 46625773a8b4bf51387dda61a5efe1cc37c86b9a..4209e3f5bb0dca0e2536c6206dc1527205c52829 100644 GIT binary patch delta 101754 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%0AyM$fT&VVur1+IgGgy#@3M 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 lLsD$@&f21h1a$HJmHms{||>$EYSb} delta 87773 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

S=uO5dK1lF2RLItYepYz0z{{zO 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 LFMSj;E%^Tc!EkHn diff --git a/src/GameMenu/GameMenu.cpp b/src/GameMenu/GameMenu.cpp index 00d9747..382475c 100644 --- a/src/GameMenu/GameMenu.cpp +++ b/src/GameMenu/GameMenu.cpp @@ -13,9 +13,8 @@ namespace gmenu { * public functions * *===================================================*/ - void Menu::setTitle(std::string title, sf::Font font) { + void Menu::setTitle(std::string title) { menu_title = title; - MenuTitleFont = font; } void Menu::setMenuItems(MenuItem *items, int8_t length) { @@ -70,7 +69,7 @@ namespace gmenu { sf::Text text; text.setString(str); text.setFont(font); - //text.setFillColor(color); + text.setFillColor(color); text.setCharacterSize(size); sf::FloatRect textRect = text.getLocalBounds(); text.setOrigin(textRect.width / 2.0f,0); @@ -84,38 +83,34 @@ namespace gmenu { { /* Small scope just to be able to freely use the variable names */ float x = (float) window->getSize().x / 2, y = 0; - int size = (int) window->getSize().y * MenuTitleScaleFactor; title_location.x = x; title_location.y = y; - title_location.size = size; } unsigned int menu_screen_height =(int) window->getSize().y * (1 - MenuTitleScaleFactor); unsigned int block_height = (int) menu_screen_height / menu_items.size * MenuItemScaleFactor; - unsigned int fontSize = (int) block_height * 3/4; float x = (float)window->getSize().x / 2; float y = (float)window->getSize().y - 0.75 * menu_screen_height + block_height * 1 / 8; - menu_location = new coordinates[menu_items.size]; + item_location = new coordinates[menu_items.size]; /* Calculating Menu item locations */ for (int8_t i = 0; i < menu_items.size; ++i) { - menu_location[i].x = x; - menu_location[i].y = y; - menu_location[i].size = fontSize; + item_location[i].x = x; + item_location[i].y = y; y += block_height; } } //setMenu() void Menu::drawMenu() { - writeText(menu_title, MenuTitleFont, title_location.size, title_location.x, title_location.y); - sf::Color color = sf::Color::White; + writeText(menu_title, style.TitleFont, style.TitleFontSize, title_location.x, title_location.y, style.TitleColor); + sf::Color color = style.ItemColor; for (int i = 0; i < menu_items.size; ++i) { if (i == currently_selected_item) { - color = sf::Color::Yellow; + color = style.Selected; } - writeText(menu_items.entries[i].title, menu_items.entries[i].font, menu_location[i].size, menu_location[i].x, menu_location[i].y, color); - color = sf::Color::White; + writeText(menu_items.entries[i].title, style.ItemFont, style.ItemFontSize, item_location[i].x, item_location[i].y, color); + color = style.ItemColor; } } //drawMenu() diff --git a/tests/sample_menu.cpp b/tests/sample_menu.cpp new file mode 100644 index 0000000..ba1e82c --- /dev/null +++ b/tests/sample_menu.cpp @@ -0,0 +1,29 @@ +#include "GameMenu\GameMenu.h" +#include + +namespace test { + class testAction : public gmenu::Action { + public: + bool start() { + return false; + } + }; +} + +void main() { + sf::RenderWindow w( sf::VideoMode( 800, 400 ), "Test", sf::Style::Close); + gmenu::MenuItem item[2]; + std::string text[2] = { "Hello", "World" }; + sf::Font font; + font.loadFromFile( "sansation.ttf" ); + for ( int i = 0; i < 2; ++i ) { + item[i].title = text[i]; + item[i].action = new test::testAction(); + } + gmenu::Style style; + style.TitleFont = font; + style.ItemFont = font; + gmenu::Menu menu( &w, "Sample Menu", item, 2,style ); + menu.createMenu(); +} + From 70dc0f600492c92865277ef39a5210829c4014c9 Mon Sep 17 00:00:00 2001 From: ParadoxZero Date: Mon, 19 Dec 2016 14:43:15 +0530 Subject: [PATCH 02/10] Added the SFML to include, instead of relying on external source. That fixed the Build error --- .travis.yml | 2 +- GameMenu.vcxproj | 4 +- include/SFML/Audio.hpp | 56 ++ include/SFML/Audio/AlResource.hpp | 70 ++ include/SFML/Audio/Export.hpp | 48 ++ include/SFML/Audio/InputSoundFile.hpp | 256 ++++++ include/SFML/Audio/Listener.hpp | 234 ++++++ include/SFML/Audio/Music.hpp | 229 ++++++ include/SFML/Audio/OutputSoundFile.hpp | 133 ++++ include/SFML/Audio/Sound.hpp | 264 +++++++ include/SFML/Audio/SoundBuffer.hpp | 352 +++++++++ include/SFML/Audio/SoundBufferRecorder.hpp | 144 ++++ include/SFML/Audio/SoundFileFactory.hpp | 197 +++++ include/SFML/Audio/SoundFileFactory.inl | 100 +++ include/SFML/Audio/SoundFileReader.hpp | 164 ++++ include/SFML/Audio/SoundFileWriter.hpp | 125 +++ include/SFML/Audio/SoundRecorder.hpp | 408 ++++++++++ include/SFML/Audio/SoundSource.hpp | 297 +++++++ include/SFML/Audio/SoundStream.hpp | 386 +++++++++ include/SFML/Config.hpp | 231 ++++++ include/SFML/Graphics.hpp | 67 ++ include/SFML/Graphics/BlendMode.hpp | 215 +++++ include/SFML/Graphics/CircleShape.hpp | 154 ++++ include/SFML/Graphics/Color.hpp | 275 +++++++ include/SFML/Graphics/ConvexShape.hpp | 153 ++++ include/SFML/Graphics/Drawable.hpp | 126 +++ include/SFML/Graphics/Export.hpp | 48 ++ include/SFML/Graphics/Font.hpp | 439 +++++++++++ include/SFML/Graphics/Glsl.hpp | 227 ++++++ include/SFML/Graphics/Glsl.inl | 155 ++++ include/SFML/Graphics/Glyph.hpp | 79 ++ include/SFML/Graphics/Image.hpp | 327 ++++++++ include/SFML/Graphics/PrimitiveType.hpp | 58 ++ include/SFML/Graphics/Rect.hpp | 254 ++++++ include/SFML/Graphics/Rect.inl | 159 ++++ include/SFML/Graphics/RectangleShape.hpp | 132 ++++ include/SFML/Graphics/RenderStates.hpp | 174 ++++ include/SFML/Graphics/RenderTarget.hpp | 451 +++++++++++ include/SFML/Graphics/RenderTexture.hpp | 296 +++++++ include/SFML/Graphics/RenderWindow.hpp | 278 +++++++ include/SFML/Graphics/Shader.hpp | 875 +++++++++++++++++++++ include/SFML/Graphics/Shape.hpp | 355 +++++++++ include/SFML/Graphics/Sprite.hpp | 279 +++++++ include/SFML/Graphics/Text.hpp | 456 +++++++++++ include/SFML/Graphics/Texture.hpp | 686 ++++++++++++++++ include/SFML/Graphics/Transform.hpp | 450 +++++++++++ include/SFML/Graphics/Transformable.hpp | 429 ++++++++++ include/SFML/Graphics/Vertex.hpp | 148 ++++ include/SFML/Graphics/VertexArray.hpp | 223 ++++++ include/SFML/Graphics/View.hpp | 343 ++++++++ include/SFML/Main.hpp | 43 + include/SFML/Network.hpp | 53 ++ include/SFML/Network/Export.hpp | 48 ++ include/SFML/Network/Ftp.hpp | 612 ++++++++++++++ include/SFML/Network/Http.hpp | 482 ++++++++++++ include/SFML/Network/IpAddress.hpp | 328 ++++++++ include/SFML/Network/Packet.hpp | 412 ++++++++++ include/SFML/Network/Socket.hpp | 219 ++++++ include/SFML/Network/SocketHandle.hpp | 57 ++ include/SFML/Network/SocketSelector.hpp | 263 +++++++ include/SFML/Network/TcpListener.hpp | 164 ++++ include/SFML/Network/TcpSocket.hpp | 315 ++++++++ include/SFML/Network/UdpSocket.hpp | 286 +++++++ include/SFML/OpenGL.hpp | 77 ++ include/SFML/System.hpp | 60 ++ include/SFML/System/Clock.hpp | 117 +++ include/SFML/System/Err.hpp | 80 ++ include/SFML/System/Export.hpp | 48 ++ include/SFML/System/FileInputStream.hpp | 169 ++++ include/SFML/System/InputStream.hpp | 152 ++++ include/SFML/System/Lock.hpp | 139 ++++ include/SFML/System/MemoryInputStream.hpp | 148 ++++ include/SFML/System/Mutex.hpp | 148 ++++ include/SFML/System/NativeActivity.hpp | 62 ++ include/SFML/System/NonCopyable.hpp | 119 +++ include/SFML/System/Sleep.hpp | 52 ++ include/SFML/System/String.hpp | 669 ++++++++++++++++ include/SFML/System/String.inl | 53 ++ include/SFML/System/Thread.hpp | 282 +++++++ include/SFML/System/Thread.inl | 90 +++ include/SFML/System/ThreadLocal.hpp | 103 +++ include/SFML/System/ThreadLocalPtr.hpp | 158 ++++ include/SFML/System/ThreadLocalPtr.inl | 77 ++ include/SFML/System/Time.hpp | 488 ++++++++++++ include/SFML/System/Utf.hpp | 763 ++++++++++++++++++ include/SFML/System/Utf.inl | 752 ++++++++++++++++++ include/SFML/System/Vector2.hpp | 301 +++++++ include/SFML/System/Vector2.inl | 161 ++++ include/SFML/System/Vector3.hpp | 302 +++++++ include/SFML/System/Vector3.inl | 168 ++++ include/SFML/Window.hpp | 56 ++ include/SFML/Window/Context.hpp | 180 +++++ include/SFML/Window/ContextSettings.hpp | 148 ++++ include/SFML/Window/Event.hpp | 284 +++++++ include/SFML/Window/Export.hpp | 48 ++ include/SFML/Window/GlResource.hpp | 103 +++ include/SFML/Window/Joystick.hpp | 227 ++++++ include/SFML/Window/Keyboard.hpp | 224 ++++++ include/SFML/Window/Mouse.hpp | 177 +++++ include/SFML/Window/Sensor.hpp | 150 ++++ include/SFML/Window/Touch.hpp | 137 ++++ include/SFML/Window/VideoMode.hpp | 228 ++++++ include/SFML/Window/Window.hpp | 594 ++++++++++++++ include/SFML/Window/WindowHandle.hpp | 101 +++ include/SFML/Window/WindowStyle.hpp | 53 ++ lib/libGameMenu.a | Bin 377462 -> 389190 bytes 106 files changed, 23738 insertions(+), 3 deletions(-) create mode 100644 include/SFML/Audio.hpp create mode 100644 include/SFML/Audio/AlResource.hpp create mode 100644 include/SFML/Audio/Export.hpp create mode 100644 include/SFML/Audio/InputSoundFile.hpp create mode 100644 include/SFML/Audio/Listener.hpp create mode 100644 include/SFML/Audio/Music.hpp create mode 100644 include/SFML/Audio/OutputSoundFile.hpp create mode 100644 include/SFML/Audio/Sound.hpp create mode 100644 include/SFML/Audio/SoundBuffer.hpp create mode 100644 include/SFML/Audio/SoundBufferRecorder.hpp create mode 100644 include/SFML/Audio/SoundFileFactory.hpp create mode 100644 include/SFML/Audio/SoundFileFactory.inl create mode 100644 include/SFML/Audio/SoundFileReader.hpp create mode 100644 include/SFML/Audio/SoundFileWriter.hpp create mode 100644 include/SFML/Audio/SoundRecorder.hpp create mode 100644 include/SFML/Audio/SoundSource.hpp create mode 100644 include/SFML/Audio/SoundStream.hpp create mode 100644 include/SFML/Config.hpp create mode 100644 include/SFML/Graphics.hpp create mode 100644 include/SFML/Graphics/BlendMode.hpp create mode 100644 include/SFML/Graphics/CircleShape.hpp create mode 100644 include/SFML/Graphics/Color.hpp create mode 100644 include/SFML/Graphics/ConvexShape.hpp create mode 100644 include/SFML/Graphics/Drawable.hpp create mode 100644 include/SFML/Graphics/Export.hpp create mode 100644 include/SFML/Graphics/Font.hpp create mode 100644 include/SFML/Graphics/Glsl.hpp create mode 100644 include/SFML/Graphics/Glsl.inl create mode 100644 include/SFML/Graphics/Glyph.hpp create mode 100644 include/SFML/Graphics/Image.hpp create mode 100644 include/SFML/Graphics/PrimitiveType.hpp create mode 100644 include/SFML/Graphics/Rect.hpp create mode 100644 include/SFML/Graphics/Rect.inl create mode 100644 include/SFML/Graphics/RectangleShape.hpp create mode 100644 include/SFML/Graphics/RenderStates.hpp create mode 100644 include/SFML/Graphics/RenderTarget.hpp create mode 100644 include/SFML/Graphics/RenderTexture.hpp create mode 100644 include/SFML/Graphics/RenderWindow.hpp create mode 100644 include/SFML/Graphics/Shader.hpp create mode 100644 include/SFML/Graphics/Shape.hpp create mode 100644 include/SFML/Graphics/Sprite.hpp create mode 100644 include/SFML/Graphics/Text.hpp create mode 100644 include/SFML/Graphics/Texture.hpp create mode 100644 include/SFML/Graphics/Transform.hpp create mode 100644 include/SFML/Graphics/Transformable.hpp create mode 100644 include/SFML/Graphics/Vertex.hpp create mode 100644 include/SFML/Graphics/VertexArray.hpp create mode 100644 include/SFML/Graphics/View.hpp create mode 100644 include/SFML/Main.hpp create mode 100644 include/SFML/Network.hpp create mode 100644 include/SFML/Network/Export.hpp create mode 100644 include/SFML/Network/Ftp.hpp create mode 100644 include/SFML/Network/Http.hpp create mode 100644 include/SFML/Network/IpAddress.hpp create mode 100644 include/SFML/Network/Packet.hpp create mode 100644 include/SFML/Network/Socket.hpp create mode 100644 include/SFML/Network/SocketHandle.hpp create mode 100644 include/SFML/Network/SocketSelector.hpp create mode 100644 include/SFML/Network/TcpListener.hpp create mode 100644 include/SFML/Network/TcpSocket.hpp create mode 100644 include/SFML/Network/UdpSocket.hpp create mode 100644 include/SFML/OpenGL.hpp create mode 100644 include/SFML/System.hpp create mode 100644 include/SFML/System/Clock.hpp create mode 100644 include/SFML/System/Err.hpp create mode 100644 include/SFML/System/Export.hpp create mode 100644 include/SFML/System/FileInputStream.hpp create mode 100644 include/SFML/System/InputStream.hpp create mode 100644 include/SFML/System/Lock.hpp create mode 100644 include/SFML/System/MemoryInputStream.hpp create mode 100644 include/SFML/System/Mutex.hpp create mode 100644 include/SFML/System/NativeActivity.hpp create mode 100644 include/SFML/System/NonCopyable.hpp create mode 100644 include/SFML/System/Sleep.hpp create mode 100644 include/SFML/System/String.hpp create mode 100644 include/SFML/System/String.inl create mode 100644 include/SFML/System/Thread.hpp create mode 100644 include/SFML/System/Thread.inl create mode 100644 include/SFML/System/ThreadLocal.hpp create mode 100644 include/SFML/System/ThreadLocalPtr.hpp create mode 100644 include/SFML/System/ThreadLocalPtr.inl create mode 100644 include/SFML/System/Time.hpp create mode 100644 include/SFML/System/Utf.hpp create mode 100644 include/SFML/System/Utf.inl create mode 100644 include/SFML/System/Vector2.hpp create mode 100644 include/SFML/System/Vector2.inl create mode 100644 include/SFML/System/Vector3.hpp create mode 100644 include/SFML/System/Vector3.inl create mode 100644 include/SFML/Window.hpp create mode 100644 include/SFML/Window/Context.hpp create mode 100644 include/SFML/Window/ContextSettings.hpp create mode 100644 include/SFML/Window/Event.hpp create mode 100644 include/SFML/Window/Export.hpp create mode 100644 include/SFML/Window/GlResource.hpp create mode 100644 include/SFML/Window/Joystick.hpp create mode 100644 include/SFML/Window/Keyboard.hpp create mode 100644 include/SFML/Window/Mouse.hpp create mode 100644 include/SFML/Window/Sensor.hpp create mode 100644 include/SFML/Window/Touch.hpp create mode 100644 include/SFML/Window/VideoMode.hpp create mode 100644 include/SFML/Window/Window.hpp create mode 100644 include/SFML/Window/WindowHandle.hpp create mode 100644 include/SFML/Window/WindowStyle.hpp diff --git a/.travis.yml b/.travis.yml index a7ec15f..2a3ecda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,6 @@ before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo add-apt-repository ppa:sonkun/sfml-development -y - sudo apt-get update -q - - sudo apt-get install gcc-4.8 g++-4.8 libsfml-dev -y + - sudo apt-get install gcc-4.8 g++-4.8 -y script: make CC='g++-4.8' diff --git a/GameMenu.vcxproj b/GameMenu.vcxproj index 6a4bb80..9c4cbf3 100644 --- a/GameMenu.vcxproj +++ b/GameMenu.vcxproj @@ -97,7 +97,7 @@ Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true - C:\Users\sidhi\Desktop\Projects\GameMenu\include;C:\Users\sidhi\libraries\SFML-2.4.1\include;%(AdditionalIncludeDirectories) + C:\Users\sidhi\Desktop\Projects\GameMenu\include;%(AdditionalIncludeDirectories) Windows @@ -111,7 +111,7 @@ Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) true - C:\Users\sidhi\Desktop\Projects\GameMenu\include;C:\Users\sidhi\libraries\SFML-2.4.1\include;%(AdditionalIncludeDirectories) + C:\Users\sidhi\Desktop\Projects\GameMenu\include;%(AdditionalIncludeDirectories) Windows diff --git a/include/SFML/Audio.hpp b/include/SFML/Audio.hpp new file mode 100644 index 0000000..43a4a75 --- /dev/null +++ b/include/SFML/Audio.hpp @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_AUDIO_HPP +#define SFML_AUDIO_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif // SFML_AUDIO_HPP + +//////////////////////////////////////////////////////////// +/// \defgroup audio Audio module +/// +/// Sounds, streaming (musics or custom sources), recording, +/// spatialization. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/AlResource.hpp b/include/SFML/Audio/AlResource.hpp new file mode 100644 index 0000000..d925314 --- /dev/null +++ b/include/SFML/Audio/AlResource.hpp @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_ALRESOURCE_HPP +#define SFML_ALRESOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Base class for classes that require an OpenAL context +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API AlResource +{ +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + AlResource(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~AlResource(); +}; + +} // namespace sf + + +#endif // SFML_ALRESOURCE_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::AlResource +/// \ingroup audio +/// +/// This class is for internal use only, it must be the base +/// of every class that requires a valid OpenAL context in +/// order to work. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/Export.hpp b/include/SFML/Audio/Export.hpp new file mode 100644 index 0000000..3269041 --- /dev/null +++ b/include/SFML/Audio/Export.hpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_AUDIO_EXPORT_HPP +#define SFML_AUDIO_EXPORT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_AUDIO_EXPORTS) + + #define SFML_AUDIO_API SFML_API_EXPORT + +#else + + #define SFML_AUDIO_API SFML_API_IMPORT + +#endif + + +#endif // SFML_AUDIO_EXPORT_HPP diff --git a/include/SFML/Audio/InputSoundFile.hpp b/include/SFML/Audio/InputSoundFile.hpp new file mode 100644 index 0000000..e59f2a2 --- /dev/null +++ b/include/SFML/Audio/InputSoundFile.hpp @@ -0,0 +1,256 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_INPUTSOUNDFILE_HPP +#define SFML_INPUTSOUNDFILE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +class InputStream; +class SoundFileReader; + +//////////////////////////////////////////////////////////// +/// \brief Provide read access to sound files +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API InputSoundFile : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + InputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~InputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file from the disk for reading + /// + /// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. + /// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. + /// + /// \param filename Path of the sound file to load + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file in memory for reading + /// + /// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. + /// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file from a custom stream for reading + /// + /// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. + /// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. + /// + /// \param stream Source stream to read from + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Open the sound file from the disk for writing + /// + /// \param filename Path of the sound file to write + /// \param channelCount Number of channels in the sound + /// \param sampleRate Sample rate of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openForWriting(const std::string& filename, unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Get the total number of audio samples in the file + /// + /// \return Number of samples + /// + //////////////////////////////////////////////////////////// + Uint64 getSampleCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by the sound + /// + /// \return Number of channels (1 = mono, 2 = stereo) + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate of the sound + /// + /// \return Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the sound file + /// + /// This function is provided for convenience, the duration is + /// deduced from the other sound file attributes. + /// + /// \return Duration of the sound file + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// This function takes a sample offset to provide maximum + /// precision. If you need to jump to a given time, use the + /// other overload. + /// + /// The sample offset takes the channels into account. + /// Offsets can be calculated like this: + /// `sampleNumber * sampleRate * channelCount` + /// If the given offset exceeds to total number of samples, + /// this function jumps to the end of the sound file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + void seek(Uint64 sampleOffset); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given time offset + /// + /// Using a time offset is handy but imprecise. If you need an accurate + /// result, consider using the overload which takes a sample offset. + /// + /// If the given time exceeds to total duration, this function jumps + /// to the end of the sound file. + /// + /// \param timeOffset Time to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + void seek(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + Uint64 read(Int16* samples, Uint64 maxCount); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Close the current file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SoundFileReader* m_reader; ///< Reader that handles I/O on the file's format + InputStream* m_stream; ///< Input stream used to access the file's data + bool m_streamOwned; ///< Is the stream internal or external? + Uint64 m_sampleCount; ///< Total number of samples in the file + unsigned int m_channelCount; ///< Number of channels of the sound + unsigned int m_sampleRate; ///< Number of samples per second +}; + +} // namespace sf + + +#endif // SFML_INPUTSOUNDFILE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::InputSoundFile +/// \ingroup audio +/// +/// This class decodes audio samples from a sound file. It is +/// used internally by higher-level classes such as sf::SoundBuffer +/// and sf::Music, but can also be useful if you want to process +/// or analyze audio files without playing them, or if you want to +/// implement your own version of sf::Music with more specific +/// features. +/// +/// Usage example: +/// \code +/// // Open a sound file +/// sf::InputSoundFile file; +/// if (!file.openFromFile("music.ogg")) +/// /* error */; +/// +/// // Print the sound attributes +/// std::cout << "duration: " << file.getDuration().asSeconds() << std::endl; +/// std::cout << "channels: " << file.getChannelCount() << std::endl; +/// std::cout << "sample rate: " << file.getSampleRate() << std::endl; +/// std::cout << "sample count: " << file.getSampleCount() << std::endl; +/// +/// // Read and process batches of samples until the end of file is reached +/// sf::Int16 samples[1024]; +/// sf::Uint64 count; +/// do +/// { +/// count = file.read(samples, 1024); +/// +/// // process, analyze, play, convert, or whatever +/// // you want to do with the samples... +/// } +/// while (count > 0); +/// \endcode +/// +/// \see sf::SoundFileReader, sf::OutputSoundFile +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/Listener.hpp b/include/SFML/Audio/Listener.hpp new file mode 100644 index 0000000..a9b1817 --- /dev/null +++ b/include/SFML/Audio/Listener.hpp @@ -0,0 +1,234 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_LISTENER_HPP +#define SFML_LISTENER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief The audio listener is the point in the scene +/// from where all the sounds are heard +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API Listener +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Change the global volume of all the sounds and musics + /// + /// The volume is a number between 0 and 100; it is combined with + /// the individual volume of each sound / music. + /// The default value for the volume is 100 (maximum). + /// + /// \param volume New global volume, in the range [0, 100] + /// + /// \see getGlobalVolume + /// + //////////////////////////////////////////////////////////// + static void setGlobalVolume(float volume); + + //////////////////////////////////////////////////////////// + /// \brief Get the current value of the global volume + /// + /// \return Current global volume, in the range [0, 100] + /// + /// \see setGlobalVolume + /// + //////////////////////////////////////////////////////////// + static float getGlobalVolume(); + + //////////////////////////////////////////////////////////// + /// \brief Set the position of the listener in the scene + /// + /// The default listener's position is (0, 0, 0). + /// + /// \param x X coordinate of the listener's position + /// \param y Y coordinate of the listener's position + /// \param z Z coordinate of the listener's position + /// + /// \see getPosition, setDirection + /// + //////////////////////////////////////////////////////////// + static void setPosition(float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Set the position of the listener in the scene + /// + /// The default listener's position is (0, 0, 0). + /// + /// \param position New listener's position + /// + /// \see getPosition, setDirection + /// + //////////////////////////////////////////////////////////// + static void setPosition(const Vector3f& position); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of the listener in the scene + /// + /// \return Listener's position + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + static Vector3f getPosition(); + + //////////////////////////////////////////////////////////// + /// \brief Set the forward vector of the listener in the scene + /// + /// The direction (also called "at vector") is the vector + /// pointing forward from the listener's perspective. Together + /// with the up vector, it defines the 3D orientation of the + /// listener in the scene. The direction vector doesn't + /// have to be normalized. + /// The default listener's direction is (0, 0, -1). + /// + /// \param x X coordinate of the listener's direction + /// \param y Y coordinate of the listener's direction + /// \param z Z coordinate of the listener's direction + /// + /// \see getDirection, setUpVector, setPosition + /// + //////////////////////////////////////////////////////////// + static void setDirection(float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Set the forward vector of the listener in the scene + /// + /// The direction (also called "at vector") is the vector + /// pointing forward from the listener's perspective. Together + /// with the up vector, it defines the 3D orientation of the + /// listener in the scene. The direction vector doesn't + /// have to be normalized. + /// The default listener's direction is (0, 0, -1). + /// + /// \param direction New listener's direction + /// + /// \see getDirection, setUpVector, setPosition + /// + //////////////////////////////////////////////////////////// + static void setDirection(const Vector3f& direction); + + //////////////////////////////////////////////////////////// + /// \brief Get the current forward vector of the listener in the scene + /// + /// \return Listener's forward vector (not normalized) + /// + /// \see setDirection + /// + //////////////////////////////////////////////////////////// + static Vector3f getDirection(); + + //////////////////////////////////////////////////////////// + /// \brief Set the upward vector of the listener in the scene + /// + /// The up vector is the vector that points upward from the + /// listener's perspective. Together with the direction, it + /// defines the 3D orientation of the listener in the scene. + /// The up vector doesn't have to be normalized. + /// The default listener's up vector is (0, 1, 0). It is usually + /// not necessary to change it, especially in 2D scenarios. + /// + /// \param x X coordinate of the listener's up vector + /// \param y Y coordinate of the listener's up vector + /// \param z Z coordinate of the listener's up vector + /// + /// \see getUpVector, setDirection, setPosition + /// + //////////////////////////////////////////////////////////// + static void setUpVector(float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Set the upward vector of the listener in the scene + /// + /// The up vector is the vector that points upward from the + /// listener's perspective. Together with the direction, it + /// defines the 3D orientation of the listener in the scene. + /// The up vector doesn't have to be normalized. + /// The default listener's up vector is (0, 1, 0). It is usually + /// not necessary to change it, especially in 2D scenarios. + /// + /// \param upVector New listener's up vector + /// + /// \see getUpVector, setDirection, setPosition + /// + //////////////////////////////////////////////////////////// + static void setUpVector(const Vector3f& upVector); + + //////////////////////////////////////////////////////////// + /// \brief Get the current upward vector of the listener in the scene + /// + /// \return Listener's upward vector (not normalized) + /// + /// \see setUpVector + /// + //////////////////////////////////////////////////////////// + static Vector3f getUpVector(); +}; + +} // namespace sf + + +#endif // SFML_LISTENER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Listener +/// \ingroup audio +/// +/// The audio listener defines the global properties of the +/// audio environment, it defines where and how sounds and musics +/// are heard. If sf::View is the eyes of the user, then sf::Listener +/// is his ears (by the way, they are often linked together -- +/// same position, orientation, etc.). +/// +/// sf::Listener is a simple interface, which allows to setup the +/// listener in the 3D audio environment (position, direction and +/// up vector), and to adjust the global volume. +/// +/// Because the listener is unique in the scene, sf::Listener only +/// contains static functions and doesn't have to be instantiated. +/// +/// Usage example: +/// \code +/// // Move the listener to the position (1, 0, -5) +/// sf::Listener::setPosition(1, 0, -5); +/// +/// // Make it face the right axis (1, 0, 0) +/// sf::Listener::setDirection(1, 0, 0); +/// +/// // Reduce the global volume +/// sf::Listener::setGlobalVolume(50); +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/Music.hpp b/include/SFML/Audio/Music.hpp new file mode 100644 index 0000000..1dc0e0c --- /dev/null +++ b/include/SFML/Audio/Music.hpp @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_MUSIC_HPP +#define SFML_MUSIC_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Streamed music played from an audio file +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API Music : public SoundStream +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Music(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Music(); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \warning Since the music is not loaded at once but rather + /// streamed continuously, the file must remain accessible until + /// the sf::Music object loads a new music or is destroyed. + /// + /// \param filename Path of the music file to open + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromMemory, openFromStream + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file in memory + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \warning Since the music is not loaded at once but rather streamed + /// continuously, the \a data buffer must remain accessible until + /// the sf::Music object loads a new music or is destroyed. That is, + /// you can't deallocate the buffer right after calling this function. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromFile, openFromStream + /// + //////////////////////////////////////////////////////////// + bool openFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file in a custom stream + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \warning Since the music is not loaded at once but rather + /// streamed continuously, the \a stream must remain accessible + /// until the sf::Music object loads a new music or is destroyed. + /// + /// \param stream Source stream to read from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromFile, openFromMemory + /// + //////////////////////////////////////////////////////////// + bool openFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the music + /// + /// \return Music duration + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Request a new chunk of audio samples from the stream source + /// + /// This function fills the chunk from the next samples + /// to read from the audio file. + /// + /// \param data Chunk of data to fill + /// + /// \return True to continue playback, false to stop + /// + //////////////////////////////////////////////////////////// + virtual bool onGetData(Chunk& data); + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position in the stream source + /// + /// \param timeOffset New playing position, from the beginning of the music + /// + //////////////////////////////////////////////////////////// + virtual void onSeek(Time timeOffset); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Initialize the internal state after loading a new music + /// + //////////////////////////////////////////////////////////// + void initialize(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + InputSoundFile m_file; ///< The streamed music file + Time m_duration; ///< Music duration + std::vector m_samples; ///< Temporary buffer of samples + Mutex m_mutex; ///< Mutex protecting the data +}; + +} // namespace sf + + +#endif // SFML_MUSIC_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Music +/// \ingroup audio +/// +/// Musics are sounds that are streamed rather than completely +/// loaded in memory. This is especially useful for compressed +/// musics that usually take hundreds of MB when they are +/// uncompressed: by streaming it instead of loading it entirely, +/// you avoid saturating the memory and have almost no loading delay. +/// This implies that the underlying resource (file, stream or +/// memory buffer) must remain valid for the lifetime of the +/// sf::Music object. +/// +/// Apart from that, a sf::Music has almost the same features as +/// the sf::SoundBuffer / sf::Sound pair: you can play/pause/stop +/// it, request its parameters (channels, sample rate), change +/// the way it is played (pitch, volume, 3D position, ...), etc. +/// +/// As a sound stream, a music is played in its own thread in order +/// not to block the rest of the program. This means that you can +/// leave the music alone after calling play(), it will manage itself +/// very well. +/// +/// Usage example: +/// \code +/// // Declare a new music +/// sf::Music music; +/// +/// // Open it from an audio file +/// if (!music.openFromFile("music.ogg")) +/// { +/// // error... +/// } +/// +/// // Change some parameters +/// music.setPosition(0, 1, 10); // change its 3D position +/// music.setPitch(2); // increase the pitch +/// music.setVolume(50); // reduce the volume +/// music.setLoop(true); // make it loop +/// +/// // Play it +/// music.play(); +/// \endcode +/// +/// \see sf::Sound, sf::SoundStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/OutputSoundFile.hpp b/include/SFML/Audio/OutputSoundFile.hpp new file mode 100644 index 0000000..8c50bd1 --- /dev/null +++ b/include/SFML/Audio/OutputSoundFile.hpp @@ -0,0 +1,133 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_OUTPUTSOUNDFILE_HPP +#define SFML_OUTPUTSOUNDFILE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class SoundFileWriter; + +//////////////////////////////////////////////////////////// +/// \brief Provide write access to sound files +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API OutputSoundFile : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + OutputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Closes the file if it was still open. + /// + //////////////////////////////////////////////////////////// + ~OutputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Open the sound file from the disk for writing + /// + /// The supported audio formats are: WAV, OGG/Vorbis, FLAC. + /// + /// \param filename Path of the sound file to write + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels in the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename, unsigned int sampleRate, unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + void write(const Int16* samples, Uint64 count); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Close the current file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SoundFileWriter* m_writer; ///< Writer that handles I/O on the file's format +}; + +} // namespace sf + + +#endif // SFML_OUTPUTSOUNDFILE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::OutputSoundFile +/// \ingroup audio +/// +/// This class encodes audio samples to a sound file. It is +/// used internally by higher-level classes such as sf::SoundBuffer, +/// but can also be useful if you want to create audio files from +/// custom data sources, like generated audio samples. +/// +/// Usage example: +/// \code +/// // Create a sound file, ogg/vorbis format, 44100 Hz, stereo +/// sf::OutputSoundFile file; +/// if (!file.openFromFile("music.ogg", 44100, 2)) +/// /* error */; +/// +/// while (...) +/// { +/// // Read or generate audio samples from your custom source +/// std::vector samples = ...; +/// +/// // Write them to the file +/// file.write(samples.data(), samples.size()); +/// } +/// \endcode +/// +/// \see sf::SoundFileWriter, sf::InputSoundFile +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/Sound.hpp b/include/SFML/Audio/Sound.hpp new file mode 100644 index 0000000..fb78677 --- /dev/null +++ b/include/SFML/Audio/Sound.hpp @@ -0,0 +1,264 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUND_HPP +#define SFML_SOUND_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +class SoundBuffer; + +//////////////////////////////////////////////////////////// +/// \brief Regular sound that can be played in the audio environment +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API Sound : public SoundSource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Sound(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the sound with a buffer + /// + /// \param buffer Sound buffer containing the audio data to play with the sound + /// + //////////////////////////////////////////////////////////// + explicit Sound(const SoundBuffer& buffer); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + Sound(const Sound& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Sound(); + + //////////////////////////////////////////////////////////// + /// \brief Start or resume playing the sound + /// + /// This function starts the stream if it was stopped, resumes + /// it if it was paused, and restarts it from beginning if it + /// was it already playing. + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the sound is played. + /// + /// \see pause, stop + /// + //////////////////////////////////////////////////////////// + void play(); + + //////////////////////////////////////////////////////////// + /// \brief Pause the sound + /// + /// This function pauses the sound if it was playing, + /// otherwise (sound already paused or stopped) it has no effect. + /// + /// \see play, stop + /// + //////////////////////////////////////////////////////////// + void pause(); + + //////////////////////////////////////////////////////////// + /// \brief stop playing the sound + /// + /// This function stops the sound if it was playing or paused, + /// and does nothing if it was already stopped. + /// It also resets the playing position (unlike pause()). + /// + /// \see play, pause + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Set the source buffer containing the audio data to play + /// + /// It is important to note that the sound buffer is not copied, + /// thus the sf::SoundBuffer instance must remain alive as long + /// as it is attached to the sound. + /// + /// \param buffer Sound buffer to attach to the sound + /// + /// \see getBuffer + /// + //////////////////////////////////////////////////////////// + void setBuffer(const SoundBuffer& buffer); + + //////////////////////////////////////////////////////////// + /// \brief Set whether or not the sound should loop after reaching the end + /// + /// If set, the sound will restart from beginning after + /// reaching the end and so on, until it is stopped or + /// setLoop(false) is called. + /// The default looping state for sound is false. + /// + /// \param loop True to play in loop, false to play once + /// + /// \see getLoop + /// + //////////////////////////////////////////////////////////// + void setLoop(bool loop); + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position of the sound + /// + /// The playing position can be changed when the sound is + /// either paused or playing. Changing the playing position + /// when the sound is stopped has no effect, since playing + /// the sound will reset its position. + /// + /// \param timeOffset New playing position, from the beginning of the sound + /// + /// \see getPlayingOffset + /// + //////////////////////////////////////////////////////////// + void setPlayingOffset(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Get the audio buffer attached to the sound + /// + /// \return Sound buffer attached to the sound (can be NULL) + /// + //////////////////////////////////////////////////////////// + const SoundBuffer* getBuffer() const; + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the sound is in loop mode + /// + /// \return True if the sound is looping, false otherwise + /// + /// \see setLoop + /// + //////////////////////////////////////////////////////////// + bool getLoop() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current playing position of the sound + /// + /// \return Current playing position, from the beginning of the sound + /// + /// \see setPlayingOffset + /// + //////////////////////////////////////////////////////////// + Time getPlayingOffset() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the sound (stopped, paused, playing) + /// + /// \return Current status of the sound + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + 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: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + const SoundBuffer* m_buffer; ///< Sound buffer bound to the source +}; + +} // namespace sf + + +#endif // SFML_SOUND_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Sound +/// \ingroup audio +/// +/// sf::Sound is the class to use to play sounds. +/// It provides: +/// \li Control (play, pause, stop) +/// \li Ability to modify output parameters in real-time (pitch, volume, ...) +/// \li 3D spatial features (position, attenuation, ...). +/// +/// sf::Sound is perfect for playing short sounds that can +/// fit in memory and require no latency, like foot steps or +/// gun shots. For longer sounds, like background musics +/// or long speeches, rather see sf::Music (which is based +/// on streaming). +/// +/// In order to work, a sound must be given a buffer of audio +/// data to play. Audio data (samples) is stored in sf::SoundBuffer, +/// and attached to a sound with the setBuffer() function. +/// The buffer object attached to a sound must remain alive +/// as long as the sound uses it. Note that multiple sounds +/// can use the same sound buffer at the same time. +/// +/// Usage example: +/// \code +/// sf::SoundBuffer buffer; +/// buffer.loadFromFile("sound.wav"); +/// +/// sf::Sound sound; +/// sound.setBuffer(buffer); +/// sound.play(); +/// \endcode +/// +/// \see sf::SoundBuffer, sf::Music +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundBuffer.hpp b/include/SFML/Audio/SoundBuffer.hpp new file mode 100644 index 0000000..0a155ab --- /dev/null +++ b/include/SFML/Audio/SoundBuffer.hpp @@ -0,0 +1,352 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDBUFFER_HPP +#define SFML_SOUNDBUFFER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class Sound; +class InputSoundFile; +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Storage for audio samples defining a sound +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundBuffer : AlResource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundBuffer(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SoundBuffer(const SoundBuffer& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundBuffer(); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a file + /// + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \param filename Path of the sound file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream, loadFromSamples, saveToFile + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a file in memory + /// + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a custom stream + /// + /// See the documentation of sf::InputSoundFile for the list + /// of supported formats. + /// + /// \param stream Source stream to read from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from an array of audio samples + /// + /// The assumed format of the audio samples is 16 bits signed integer + /// (sf::Int16). + /// + /// \param samples Pointer to the array of samples in memory + /// \param sampleCount Number of samples in the array + /// \param channelCount Number of channels (1 = mono, 2 = stereo, ...) + /// \param sampleRate Sample rate (number of samples to play per second) + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, saveToFile + /// + //////////////////////////////////////////////////////////// + bool loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Save the sound buffer to an audio file + /// + /// See the documentation of sf::OutputSoundFile for the list + /// of supported formats. + /// + /// \param filename Path of the sound file to write + /// + /// \return True if saving succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool saveToFile(const std::string& filename) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the array of audio samples stored in the buffer + /// + /// The format of the returned samples is 16 bits signed integer + /// (sf::Int16). The total number of samples in this array + /// is given by the getSampleCount() function. + /// + /// \return Read-only pointer to the array of sound samples + /// + /// \see getSampleCount + /// + //////////////////////////////////////////////////////////// + const Int16* getSamples() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of samples stored in the buffer + /// + /// The array of samples can be accessed with the getSamples() + /// function. + /// + /// \return Number of samples + /// + /// \see getSamples + /// + //////////////////////////////////////////////////////////// + Uint64 getSampleCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate of the sound + /// + /// The sample rate is the number of samples played per second. + /// The higher, the better the quality (for example, 44100 + /// samples/s is CD quality). + /// + /// \return Sample rate (number of samples per second) + /// + /// \see getChannelCount, getDuration + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by the sound + /// + /// If the sound is mono then the number of channels will + /// be 1, 2 for stereo, etc. + /// + /// \return Number of channels + /// + /// \see getSampleRate, getDuration + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the sound + /// + /// \return Sound duration + /// + /// \see getSampleRate, getChannelCount + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + SoundBuffer& operator =(const SoundBuffer& right); + +private: + + friend class Sound; + + //////////////////////////////////////////////////////////// + /// \brief Initialize the internal state after loading a new sound + /// + /// \param file Sound file providing access to the new loaded sound + /// + /// \return True on successful initialization, false on failure + /// + //////////////////////////////////////////////////////////// + bool initialize(InputSoundFile& file); + + //////////////////////////////////////////////////////////// + /// \brief Update the internal buffer with the cached audio samples + /// + /// \param channelCount Number of channels + /// \param sampleRate Sample rate (number of samples per second) + /// + /// \return True on success, false if any error happened + /// + //////////////////////////////////////////////////////////// + bool update(unsigned int channelCount, 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 m_buffer; ///< OpenAL buffer identifier + std::vector m_samples; ///< Samples buffer + Time m_duration; ///< Sound duration + mutable SoundList m_sounds; ///< List of sounds that are using this buffer +}; + +} // namespace sf + + +#endif // SFML_SOUNDBUFFER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundBuffer +/// \ingroup audio +/// +/// A sound buffer holds the data of a sound, which is +/// an array of audio samples. A sample is a 16 bits signed integer +/// that defines the amplitude of the sound at a given time. +/// The sound is then reconstituted by playing these samples at +/// a high rate (for example, 44100 samples per second is the +/// standard rate used for playing CDs). In short, audio samples +/// are like texture pixels, and a sf::SoundBuffer is similar to +/// a sf::Texture. +/// +/// A sound buffer can be loaded from a file (see loadFromFile() +/// for the complete list of supported formats), from memory, from +/// a custom stream (see sf::InputStream) or directly from an array +/// of samples. It can also be saved back to a file. +/// +/// Sound buffers alone are not very useful: they hold the audio data +/// but cannot be played. To do so, you need to use the sf::Sound class, +/// which provides functions to play/pause/stop the sound as well as +/// changing the way it is outputted (volume, pitch, 3D position, ...). +/// This separation allows more flexibility and better performances: +/// indeed a sf::SoundBuffer is a heavy resource, and any operation on it +/// is slow (often too slow for real-time applications). On the other +/// side, a sf::Sound is a lightweight object, which can use the audio data +/// of a sound buffer and change the way it is played without actually +/// modifying that data. Note that it is also possible to bind +/// several sf::Sound instances to the same sf::SoundBuffer. +/// +/// It is important to note that the sf::Sound instance doesn't +/// copy the buffer that it uses, it only keeps a reference to it. +/// Thus, a sf::SoundBuffer must not be destructed while it is +/// used by a sf::Sound (i.e. never write a function that +/// uses a local sf::SoundBuffer instance for loading a sound). +/// +/// Usage example: +/// \code +/// // Declare a new sound buffer +/// sf::SoundBuffer buffer; +/// +/// // Load it from a file +/// if (!buffer.loadFromFile("sound.wav")) +/// { +/// // error... +/// } +/// +/// // Create a sound source and bind it to the buffer +/// sf::Sound sound1; +/// sound1.setBuffer(buffer); +/// +/// // Play the sound +/// sound1.play(); +/// +/// // Create another sound source bound to the same buffer +/// sf::Sound sound2; +/// sound2.setBuffer(buffer); +/// +/// // Play it with a higher pitch -- the first sound remains unchanged +/// sound2.setPitch(2); +/// sound2.play(); +/// \endcode +/// +/// \see sf::Sound, sf::SoundBufferRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundBufferRecorder.hpp b/include/SFML/Audio/SoundBufferRecorder.hpp new file mode 100644 index 0000000..cb27afc --- /dev/null +++ b/include/SFML/Audio/SoundBufferRecorder.hpp @@ -0,0 +1,144 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDBUFFERRECORDER_HPP +#define SFML_SOUNDBUFFERRECORDER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized SoundRecorder which stores the captured +/// audio data into a sound buffer +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundBufferRecorder : public SoundRecorder +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief destructor + /// + //////////////////////////////////////////////////////////// + ~SoundBufferRecorder(); + + //////////////////////////////////////////////////////////// + /// \brief Get the sound buffer containing the captured audio data + /// + /// The sound buffer is valid only after the capture has ended. + /// This function provides a read-only access to the internal + /// sound buffer, but it can be copied if you need to + /// make any modification to it. + /// + /// \return Read-only access to the sound buffer + /// + //////////////////////////////////////////////////////////// + const SoundBuffer& getBuffer() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Start capturing audio data + /// + /// \return True to start the capture, or false to abort it + /// + //////////////////////////////////////////////////////////// + virtual bool onStart(); + + //////////////////////////////////////////////////////////// + /// \brief Process a new chunk of recorded samples + /// + /// \param samples Pointer to the new chunk of recorded samples + /// \param sampleCount Number of samples pointed by \a samples + /// + /// \return True to continue the capture, or false to stop it + /// + //////////////////////////////////////////////////////////// + virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount); + + //////////////////////////////////////////////////////////// + /// \brief Stop capturing audio data + /// + //////////////////////////////////////////////////////////// + virtual void onStop(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_samples; ///< Temporary sample buffer to hold the recorded data + SoundBuffer m_buffer; ///< Sound buffer that will contain the recorded data +}; + +} // namespace sf + +#endif // SFML_SOUNDBUFFERRECORDER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundBufferRecorder +/// \ingroup audio +/// +/// sf::SoundBufferRecorder allows to access a recorded sound +/// through a sf::SoundBuffer, so that it can be played, saved +/// to a file, etc. +/// +/// It has the same simple interface as its base class (start(), stop()) +/// and adds a function to retrieve the recorded sound buffer +/// (getBuffer()). +/// +/// As usual, don't forget to call the isAvailable() function +/// before using this class (see sf::SoundRecorder for more details +/// about this). +/// +/// Usage example: +/// \code +/// if (sf::SoundBufferRecorder::isAvailable()) +/// { +/// // Record some audio data +/// sf::SoundBufferRecorder recorder; +/// recorder.start(); +/// ... +/// recorder.stop(); +/// +/// // Get the buffer containing the captured audio data +/// const sf::SoundBuffer& buffer = recorder.getBuffer(); +/// +/// // Save it to a file (for example...) +/// buffer.saveToFile("my_record.ogg"); +/// } +/// \endcode +/// +/// \see sf::SoundRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundFileFactory.hpp b/include/SFML/Audio/SoundFileFactory.hpp new file mode 100644 index 0000000..be8dd56 --- /dev/null +++ b/include/SFML/Audio/SoundFileFactory.hpp @@ -0,0 +1,197 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDFILEFACTORY_HPP +#define SFML_SOUNDFILEFACTORY_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class InputStream; +class SoundFileReader; +class SoundFileWriter; + +//////////////////////////////////////////////////////////// +/// \brief Manages and instantiates sound file readers and writers +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundFileFactory +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Register a new reader + /// + /// \see unregisterReader + /// + //////////////////////////////////////////////////////////// + template + static void registerReader(); + + //////////////////////////////////////////////////////////// + /// \brief Unregister a reader + /// + /// \see registerReader + /// + //////////////////////////////////////////////////////////// + template + static void unregisterReader(); + + //////////////////////////////////////////////////////////// + /// \brief Register a new writer + /// + /// \see unregisterWriter + /// + //////////////////////////////////////////////////////////// + template + static void registerWriter(); + + //////////////////////////////////////////////////////////// + /// \brief Unregister a writer + /// + /// \see registerWriter + /// + //////////////////////////////////////////////////////////// + template + static void unregisterWriter(); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right reader for the given file on disk + /// + /// It's up to the caller to release the returned reader + /// + /// \param filename Path of the sound file + /// + /// \return A new sound file reader that can read the given file, or null if no reader can handle it + /// + /// \see createReaderFromMemory, createReaderFromStream + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromFilename(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right codec for the given file in memory + /// + /// It's up to the caller to release the returned reader + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Total size of the file data, in bytes + /// + /// \return A new sound file codec that can read the given file, or null if no codec can handle it + /// + /// \see createReaderFromFilename, createReaderFromStream + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right codec for the given file in stream + /// + /// It's up to the caller to release the returned reader + /// + /// \param stream Source stream to read from + /// + /// \return A new sound file codec that can read the given file, or null if no codec can handle it + /// + /// \see createReaderFromFilename, createReaderFromMemory + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right writer for the given file on disk + /// + /// It's up to the caller to release the returned writer + /// + /// \param filename Path of the sound file + /// + /// \return A new sound file writer that can write given file, or null if no writer can handle it + /// + //////////////////////////////////////////////////////////// + static SoundFileWriter* createWriterFromFilename(const std::string& filename); + +private: + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + struct ReaderFactory + { + bool (*check)(InputStream&); + SoundFileReader* (*create)(); + }; + typedef std::vector ReaderFactoryArray; + + struct WriterFactory + { + bool (*check)(const std::string&); + SoundFileWriter* (*create)(); + }; + typedef std::vector WriterFactoryArray; + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static ReaderFactoryArray s_readers; ///< List of all registered readers + static WriterFactoryArray s_writers; ///< List of all registered writers +}; + +} // namespace sf + +#include + +#endif // SFML_SOUNDFILEFACTORY_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundFileFactory +/// \ingroup audio +/// +/// This class is where all the sound file readers and writers are +/// registered. You should normally only need to use its registration +/// and unregistration functions; readers/writers creation and manipulation +/// are wrapped into the higher-level classes sf::InputSoundFile and +/// sf::OutputSoundFile. +/// +/// To register a new reader (writer) use the sf::SoundFileFactory::registerReader +/// (registerWriter) static function. You don't have to call the unregisterReader +/// (unregisterWriter) function, unless you want to unregister a format before your +/// application ends (typically, when a plugin is unloaded). +/// +/// Usage example: +/// \code +/// sf::SoundFileFactory::registerReader(); +/// sf::SoundFileFactory::registerWriter(); +/// \endcode +/// +/// \see sf::InputSoundFile, sf::OutputSoundFile, sf::SoundFileReader, sf::SoundFileWriter +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundFileFactory.inl b/include/SFML/Audio/SoundFileFactory.inl new file mode 100644 index 0000000..c5bba65 --- /dev/null +++ b/include/SFML/Audio/SoundFileFactory.inl @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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 +//////////////////////////////////////////////////////////// + + +namespace sf +{ +namespace priv +{ + template SoundFileReader* createReader() {return new T;} + template SoundFileWriter* createWriter() {return new T;} +} + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::registerReader() +{ + // Make sure the same class won't be registered twice + unregisterReader(); + + // Create a new factory with the functions provided by the class + ReaderFactory factory; + factory.check = &T::check; + factory.create = &priv::createReader; + + // Add it + s_readers.push_back(factory); +} + + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::unregisterReader() +{ + // Remove the instance(s) of the reader from the array of factories + for (ReaderFactoryArray::iterator it = s_readers.begin(); it != s_readers.end(); ) + { + if (it->create == &priv::createReader) + it = s_readers.erase(it); + else + ++it; + } +} + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::registerWriter() +{ + // Make sure the same class won't be registered twice + unregisterWriter(); + + // Create a new factory with the functions provided by the class + WriterFactory factory; + factory.check = &T::check; + factory.create = &priv::createWriter; + + // Add it + s_writers.push_back(factory); +} + + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::unregisterWriter() +{ + // Remove the instance(s) of the writer from the array of factories + for (WriterFactoryArray::iterator it = s_writers.begin(); it != s_writers.end(); ) + { + if (it->create == &priv::createWriter) + it = s_writers.erase(it); + else + ++it; + } +} + +} // namespace sf diff --git a/include/SFML/Audio/SoundFileReader.hpp b/include/SFML/Audio/SoundFileReader.hpp new file mode 100644 index 0000000..84aa606 --- /dev/null +++ b/include/SFML/Audio/SoundFileReader.hpp @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDFILEREADER_HPP +#define SFML_SOUNDFILEREADER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for sound file decoding +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundFileReader +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Structure holding the audio properties of a sound file + /// + //////////////////////////////////////////////////////////// + struct Info + { + Uint64 sampleCount; ///< Total number of samples in the file + unsigned int channelCount; ///< Number of channels of the sound + unsigned int sampleRate; ///< Samples rate of the sound, in samples per second + }; + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundFileReader() {} + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// The provided stream reference is valid as long as the + /// SoundFileReader is alive, so it is safe to use/store it + /// during the whole lifetime of the reader. + /// + /// \param stream Source stream to read from + /// \param info Structure to fill with the properties of the loaded sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(InputStream& stream, Info& info) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// The sample offset takes the channels into account. + /// Offsets can be calculated like this: + /// `sampleNumber * sampleRate * channelCount` + /// If the given offset exceeds to total number of samples, + /// this function must jump to the end of the file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + virtual void seek(Uint64 sampleOffset) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + virtual Uint64 read(Int16* samples, Uint64 maxCount) = 0; +}; + +} // namespace sf + + +#endif // SFML_SOUNDFILEREADER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundFileReader +/// \ingroup audio +/// +/// This class allows users to read audio file formats not natively +/// supported by SFML, and thus extend the set of supported readable +/// audio formats. +/// +/// A valid sound file reader must override the open, seek and write functions, +/// as well as providing a static check function; the latter is used by +/// SFML to find a suitable writer for a given input file. +/// +/// To register a new reader, use the sf::SoundFileFactory::registerReader +/// template function. +/// +/// Usage example: +/// \code +/// class MySoundFileReader : public sf::SoundFileReader +/// { +/// public: +/// +/// static bool check(sf::InputStream& stream) +/// { +/// // typically, read the first few header bytes and check fields that identify the format +/// // return true if the reader can handle the format +/// } +/// +/// virtual bool open(sf::InputStream& stream, Info& info) +/// { +/// // read the sound file header and fill the sound attributes +/// // (channel count, sample count and sample rate) +/// // return true on success +/// } +/// +/// virtual void seek(sf::Uint64 sampleOffset) +/// { +/// // advance to the sampleOffset-th sample from the beginning of the sound +/// } +/// +/// virtual sf::Uint64 read(sf::Int16* samples, sf::Uint64 maxCount) +/// { +/// // read up to 'maxCount' samples into the 'samples' array, +/// // convert them (for example from normalized float) if they are not stored +/// // as 16-bits signed integers in the file +/// // return the actual number of samples read +/// } +/// }; +/// +/// sf::SoundFileFactory::registerReader(); +/// \endcode +/// +/// \see sf::InputSoundFile, sf::SoundFileFactory, sf::SoundFileWriter +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundFileWriter.hpp b/include/SFML/Audio/SoundFileWriter.hpp new file mode 100644 index 0000000..72b99ea --- /dev/null +++ b/include/SFML/Audio/SoundFileWriter.hpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDFILEWRITER_HPP +#define SFML_SOUNDFILEWRITER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for sound file encoding +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundFileWriter +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundFileWriter() {} + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for writing + /// + /// \param filename Path of the file to open + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the open file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + virtual void write(const Int16* samples, Uint64 count) = 0; +}; + +} // namespace sf + + +#endif // SFML_SOUNDFILEWRITER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundFileWriter +/// \ingroup audio +/// +/// This class allows users to write audio file formats not natively +/// supported by SFML, and thus extend the set of supported writable +/// audio formats. +/// +/// A valid sound file writer must override the open and write functions, +/// as well as providing a static check function; the latter is used by +/// SFML to find a suitable writer for a given filename. +/// +/// To register a new writer, use the sf::SoundFileFactory::registerWriter +/// template function. +/// +/// Usage example: +/// \code +/// class MySoundFileWriter : public sf::SoundFileWriter +/// { +/// public: +/// +/// static bool check(const std::string& filename) +/// { +/// // typically, check the extension +/// // return true if the writer can handle the format +/// } +/// +/// virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) +/// { +/// // open the file 'filename' for writing, +/// // write the given sample rate and channel count to the file header +/// // return true on success +/// } +/// +/// virtual void write(const sf::Int16* samples, sf::Uint64 count) +/// { +/// // write 'count' samples stored at address 'samples', +/// // convert them (for example to normalized float) if the format requires it +/// } +/// }; +/// +/// sf::SoundFileFactory::registerWriter(); +/// \endcode +/// +/// \see sf::OutputSoundFile, sf::SoundFileFactory, sf::SoundFileReader +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundRecorder.hpp b/include/SFML/Audio/SoundRecorder.hpp new file mode 100644 index 0000000..d23e3e5 --- /dev/null +++ b/include/SFML/Audio/SoundRecorder.hpp @@ -0,0 +1,408 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDRECORDER_HPP +#define SFML_SOUNDRECORDER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for capturing sound data +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundRecorder : AlResource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundRecorder(); + + //////////////////////////////////////////////////////////// + /// \brief Start the capture + /// + /// The \a sampleRate parameter defines the number of audio samples + /// captured per second. The higher, the better the quality + /// (for example, 44100 samples/sec is CD quality). + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the capture runs. + /// Please note that only one capture can happen at the same time. + /// You can select which capture device will be used, by passing + /// the name to the setDevice() method. If none was selected + /// before, the default capture device will be used. You can get a + /// list of the names of all available capture devices by calling + /// getAvailableDevices(). + /// + /// \param sampleRate Desired capture rate, in number of samples per second + /// + /// \return True, if start of capture was successful + /// + /// \see stop, getAvailableDevices + /// + //////////////////////////////////////////////////////////// + bool start(unsigned int sampleRate = 44100); + + //////////////////////////////////////////////////////////// + /// \brief Stop the capture + /// + /// \see start + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate + /// + /// The sample rate defines the number of audio samples + /// captured per second. The higher, the better the quality + /// (for example, 44100 samples/sec is CD quality). + /// + /// \return Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a list of the names of all available audio capture devices + /// + /// This function returns a vector of strings, containing + /// the names of all available audio capture devices. + /// + /// \return A vector of strings containing the names + /// + //////////////////////////////////////////////////////////// + static std::vector getAvailableDevices(); + + //////////////////////////////////////////////////////////// + /// \brief Get the name of the default audio capture device + /// + /// This function returns the name of the default audio + /// capture device. If none is available, an empty string + /// is returned. + /// + /// \return The name of the default audio capture device + /// + //////////////////////////////////////////////////////////// + static std::string getDefaultDevice(); + + //////////////////////////////////////////////////////////// + /// \brief Set the audio capture device + /// + /// This function sets the audio capture device to the device + /// with the given \a name. It can be called on the fly (i.e: + /// while recording). If you do so while recording and + /// opening the device fails, it stops the recording. + /// + /// \param name The name of the audio capture device + /// + /// \return True, if it was able to set the requested device + /// + /// \see getAvailableDevices, getDefaultDevice + /// + //////////////////////////////////////////////////////////// + bool setDevice(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief Get the name of the current audio capture device + /// + /// \return The name of the current audio capture device + /// + //////////////////////////////////////////////////////////// + const std::string& getDevice() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the channel count of the audio capture device + /// + /// This method allows you to specify the number of channels + /// used for recording. Currently only 16-bit mono and + /// 16-bit stereo are supported. + /// + /// \param channelCount Number of channels. Currently only + /// mono (1) and stereo (2) are supported. + /// + /// \see getChannelCount + /// + //////////////////////////////////////////////////////////// + void setChannelCount(unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by this recorder + /// + /// Currently only mono and stereo are supported, so the + /// value is either 1 (for mono) or 2 (for stereo). + /// + /// \return Number of channels + /// + /// \see setChannelCount + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Check if the system supports audio capture + /// + /// This function should always be called before using + /// the audio capture features. If it returns false, then + /// any attempt to use sf::SoundRecorder or one of its derived + /// classes will fail. + /// + /// \return True if audio capture is supported, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isAvailable(); + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is only meant to be called by derived classes. + /// + //////////////////////////////////////////////////////////// + SoundRecorder(); + + //////////////////////////////////////////////////////////// + /// \brief Set the processing interval + /// + /// The processing interval controls the period + /// between calls to the onProcessSamples function. You may + /// want to use a small interval if you want to process the + /// recorded data in real time, for example. + /// + /// Note: this is only a hint, the actual period may vary. + /// So don't rely on this parameter to implement precise timing. + /// + /// The default processing interval is 100 ms. + /// + /// \param interval Processing interval + /// + //////////////////////////////////////////////////////////// + void setProcessingInterval(Time interval); + + //////////////////////////////////////////////////////////// + /// \brief Start capturing audio data + /// + /// This virtual function may be overridden by a derived class + /// if something has to be done every time a new capture + /// starts. If not, this function can be ignored; the default + /// implementation does nothing. + /// + /// \return True to start the capture, or false to abort it + /// + //////////////////////////////////////////////////////////// + virtual bool onStart(); + + //////////////////////////////////////////////////////////// + /// \brief Process a new chunk of recorded samples + /// + /// This virtual function is called every time a new chunk of + /// recorded data is available. The derived class can then do + /// whatever it wants with it (storing it, playing it, sending + /// it over the network, etc.). + /// + /// \param samples Pointer to the new chunk of recorded samples + /// \param sampleCount Number of samples pointed by \a samples + /// + /// \return True to continue the capture, or false to stop it + /// + //////////////////////////////////////////////////////////// + virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Stop capturing audio data + /// + /// This virtual function may be overridden by a derived class + /// if something has to be done every time the capture + /// ends. If not, this function can be ignored; the default + /// implementation does nothing. + /// + //////////////////////////////////////////////////////////// + virtual void onStop(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Function called as the entry point of the thread + /// + /// This function starts the recording loop, and returns + /// only when the capture is stopped. + /// + //////////////////////////////////////////////////////////// + void record(); + + //////////////////////////////////////////////////////////// + /// \brief Get the new available audio samples and process them + /// + /// This function is called continuously during the + /// capture loop. It retrieves the captured samples and + /// forwards them to the derived class. + /// + //////////////////////////////////////////////////////////// + void processCapturedSamples(); + + //////////////////////////////////////////////////////////// + /// \brief Clean up the recorder's internal resources + /// + /// This function is called when the capture stops. + /// + //////////////////////////////////////////////////////////// + void cleanup(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Thread m_thread; ///< Thread running the background recording task + std::vector m_samples; ///< Buffer to store captured samples + unsigned int m_sampleRate; ///< Sample rate + Time m_processingInterval; ///< Time period between calls to onProcessSamples + bool m_isCapturing; ///< Capturing state + std::string m_deviceName; ///< Name of the audio capture device + unsigned int m_channelCount; ///< Number of recording channels +}; + +} // namespace sf + + +#endif // SFML_SOUNDRECORDER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundRecorder +/// \ingroup audio +/// +/// sf::SoundBuffer provides a simple interface to access +/// the audio recording capabilities of the computer +/// (the microphone). As an abstract base class, it only cares +/// about capturing sound samples, the task of making something +/// useful with them is left to the derived class. Note that +/// SFML provides a built-in specialization for saving the +/// captured data to a sound buffer (see sf::SoundBufferRecorder). +/// +/// A derived class has only one virtual function to override: +/// \li onProcessSamples provides the new chunks of audio samples while the capture happens +/// +/// Moreover, two additional virtual functions can be overridden +/// as well if necessary: +/// \li onStart is called before the capture happens, to perform custom initializations +/// \li onStop is called after the capture ends, to perform custom cleanup +/// +/// A derived class can also control the frequency of the onProcessSamples +/// calls, with the setProcessingInterval protected function. The default +/// interval is chosen so that recording thread doesn't consume too much +/// CPU, but it can be changed to a smaller value if you need to process +/// the recorded data in real time, for example. +/// +/// The audio capture feature may not be supported or activated +/// on every platform, thus it is recommended to check its +/// availability with the isAvailable() function. If it returns +/// false, then any attempt to use an audio recorder will fail. +/// +/// If you have multiple sound input devices connected to your +/// computer (for example: microphone, external soundcard, webcam mic, ...) +/// you can get a list of all available devices through the +/// getAvailableDevices() function. You can then select a device +/// by calling setDevice() with the appropriate device. Otherwise +/// the default capturing device will be used. +/// +/// By default the recording is in 16-bit mono. Using the +/// setChannelCount method you can change the number of channels +/// used by the audio capture device to record. Note that you +/// have to decide whether you want to record in mono or stereo +/// before starting the recording. +/// +/// It is important to note that the audio capture happens in a +/// separate thread, so that it doesn't block the rest of the +/// program. In particular, the onProcessSamples virtual function +/// (but not onStart and not onStop) will be called +/// from this separate thread. It is important to keep this in +/// mind, because you may have to take care of synchronization +/// issues if you share data between threads. +/// Another thing to bear in mind is that you must call stop() +/// in the destructor of your derived class, so that the recording +/// thread finishes before your object is destroyed. +/// +/// Usage example: +/// \code +/// class CustomRecorder : public sf::SoundRecorder +/// { +/// ~CustomRecorder() +/// { +/// // Make sure to stop the recording thread +/// stop(); +/// } +/// +/// virtual bool onStart() // optional +/// { +/// // Initialize whatever has to be done before the capture starts +/// ... +/// +/// // Return true to start playing +/// return true; +/// } +/// +/// virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount) +/// { +/// // Do something with the new chunk of samples (store them, send them, ...) +/// ... +/// +/// // Return true to continue playing +/// return true; +/// } +/// +/// virtual void onStop() // optional +/// { +/// // Clean up whatever has to be done after the capture ends +/// ... +/// } +/// } +/// +/// // Usage +/// if (CustomRecorder::isAvailable()) +/// { +/// CustomRecorder recorder; +/// +/// if (!recorder.start()) +/// return -1; +/// +/// ... +/// recorder.stop(); +/// } +/// \endcode +/// +/// \see sf::SoundBufferRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundSource.hpp b/include/SFML/Audio/SoundSource.hpp new file mode 100644 index 0000000..83d5e8c --- /dev/null +++ b/include/SFML/Audio/SoundSource.hpp @@ -0,0 +1,297 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDSOURCE_HPP +#define SFML_SOUNDSOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Base class defining a sound's properties +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundSource : AlResource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the sound source states + /// + //////////////////////////////////////////////////////////// + enum Status + { + Stopped, ///< Sound is not playing + Paused, ///< Sound is paused + Playing ///< Sound is playing + }; + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SoundSource(const SoundSource& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundSource(); + + //////////////////////////////////////////////////////////// + /// \brief Set the pitch of the sound + /// + /// The pitch represents the perceived fundamental frequency + /// of a sound; thus you can make a sound more acute or grave + /// by changing its pitch. A side effect of changing the pitch + /// is to modify the playing speed of the sound as well. + /// The default value for the pitch is 1. + /// + /// \param pitch New pitch to apply to the sound + /// + /// \see getPitch + /// + //////////////////////////////////////////////////////////// + void setPitch(float pitch); + + //////////////////////////////////////////////////////////// + /// \brief Set the volume of the sound + /// + /// The volume is a value between 0 (mute) and 100 (full volume). + /// The default value for the volume is 100. + /// + /// \param volume Volume of the sound + /// + /// \see getVolume + /// + //////////////////////////////////////////////////////////// + void setVolume(float volume); + + //////////////////////////////////////////////////////////// + /// \brief Set the 3D position of the sound in the audio scene + /// + /// Only sounds with one channel (mono sounds) can be + /// spatialized. + /// The default position of a sound is (0, 0, 0). + /// + /// \param x X coordinate of the position of the sound in the scene + /// \param y Y coordinate of the position of the sound in the scene + /// \param z Z coordinate of the position of the sound in the scene + /// + /// \see getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Set the 3D position of the sound in the audio scene + /// + /// Only sounds with one channel (mono sounds) can be + /// spatialized. + /// The default position of a sound is (0, 0, 0). + /// + /// \param position Position of the sound in the scene + /// + /// \see getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(const Vector3f& position); + + //////////////////////////////////////////////////////////// + /// \brief Make the sound's position relative to the listener or absolute + /// + /// Making a sound relative to the listener will ensure that it will always + /// be played the same way regardless of the position of the listener. + /// This can be useful for non-spatialized sounds, sounds that are + /// produced by the listener, or sounds attached to it. + /// The default value is false (position is absolute). + /// + /// \param relative True to set the position relative, false to set it absolute + /// + /// \see isRelativeToListener + /// + //////////////////////////////////////////////////////////// + void setRelativeToListener(bool relative); + + //////////////////////////////////////////////////////////// + /// \brief Set the minimum distance of the sound + /// + /// The "minimum distance" of a sound is the maximum + /// distance at which it is heard at its maximum volume. Further + /// than the minimum distance, it will start to fade out according + /// to its attenuation factor. A value of 0 ("inside the head + /// of the listener") is an invalid value and is forbidden. + /// The default value of the minimum distance is 1. + /// + /// \param distance New minimum distance of the sound + /// + /// \see getMinDistance, setAttenuation + /// + //////////////////////////////////////////////////////////// + void setMinDistance(float distance); + + //////////////////////////////////////////////////////////// + /// \brief Set the attenuation factor of the sound + /// + /// The attenuation is a multiplicative factor which makes + /// the sound more or less loud according to its distance + /// from the listener. An attenuation of 0 will produce a + /// non-attenuated sound, i.e. its volume will always be the same + /// whether it is heard from near or from far. On the other hand, + /// an attenuation value such as 100 will make the sound fade out + /// very quickly as it gets further from the listener. + /// The default value of the attenuation is 1. + /// + /// \param attenuation New attenuation factor of the sound + /// + /// \see getAttenuation, setMinDistance + /// + //////////////////////////////////////////////////////////// + void setAttenuation(float attenuation); + + //////////////////////////////////////////////////////////// + /// \brief Get the pitch of the sound + /// + /// \return Pitch of the sound + /// + /// \see setPitch + /// + //////////////////////////////////////////////////////////// + float getPitch() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the volume of the sound + /// + /// \return Volume of the sound, in the range [0, 100] + /// + /// \see setVolume + /// + //////////////////////////////////////////////////////////// + float getVolume() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the 3D position of the sound in the audio scene + /// + /// \return Position of the sound + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + Vector3f getPosition() const; + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the sound's position is relative to the + /// listener or is absolute + /// + /// \return True if the position is relative, false if it's absolute + /// + /// \see setRelativeToListener + /// + //////////////////////////////////////////////////////////// + bool isRelativeToListener() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the minimum distance of the sound + /// + /// \return Minimum distance of the sound + /// + /// \see setMinDistance, getAttenuation + /// + //////////////////////////////////////////////////////////// + float getMinDistance() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the attenuation factor of the sound + /// + /// \return Attenuation factor of the sound + /// + /// \see setAttenuation, getMinDistance + /// + //////////////////////////////////////////////////////////// + float getAttenuation() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + SoundSource& operator =(const SoundSource& right); + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is meant to be called by derived classes only. + /// + //////////////////////////////////////////////////////////// + SoundSource(); + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the sound (stopped, paused, playing) + /// + /// \return Current status of the sound + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int m_source; ///< OpenAL source identifier +}; + +} // namespace sf + + +#endif // SFML_SOUNDSOURCE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundSource +/// \ingroup audio +/// +/// sf::SoundSource is not meant to be used directly, it +/// only serves as a common base for all audio objects +/// that can live in the audio environment. +/// +/// It defines several properties for the sound: pitch, +/// volume, position, attenuation, etc. All of them can be +/// changed at any time with no impact on performances. +/// +/// \see sf::Sound, sf::SoundStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundStream.hpp b/include/SFML/Audio/SoundStream.hpp new file mode 100644 index 0000000..a2d7cb9 --- /dev/null +++ b/include/SFML/Audio/SoundStream.hpp @@ -0,0 +1,386 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOUNDSTREAM_HPP +#define SFML_SOUNDSTREAM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for streamed audio sources +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API SoundStream : public SoundSource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Structure defining a chunk of audio data to stream + /// + //////////////////////////////////////////////////////////// + struct Chunk + { + const Int16* samples; ///< Pointer to the audio samples + std::size_t sampleCount; ///< Number of samples pointed by Samples + }; + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundStream(); + + //////////////////////////////////////////////////////////// + /// \brief Start or resume playing the audio stream + /// + /// This function starts the stream if it was stopped, resumes + /// it if it was paused, and restarts it from the beginning if + /// it was already playing. + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the stream is played. + /// + /// \see pause, stop + /// + //////////////////////////////////////////////////////////// + void play(); + + //////////////////////////////////////////////////////////// + /// \brief Pause the audio stream + /// + /// This function pauses the stream if it was playing, + /// otherwise (stream already paused or stopped) it has no effect. + /// + /// \see play, stop + /// + //////////////////////////////////////////////////////////// + void pause(); + + //////////////////////////////////////////////////////////// + /// \brief Stop playing the audio stream + /// + /// This function stops the stream if it was playing or paused, + /// and does nothing if it was already stopped. + /// It also resets the playing position (unlike pause()). + /// + /// \see play, pause + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Return the number of channels of the stream + /// + /// 1 channel means a mono sound, 2 means stereo, etc. + /// + /// \return Number of channels + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the stream sample rate of the stream + /// + /// The sample rate is the number of audio samples played per + /// second. The higher, the better the quality. + /// + /// \return Sample rate, in number of samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the stream (stopped, paused, playing) + /// + /// \return Current status + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position of the stream + /// + /// The playing position can be changed when the stream is + /// either paused or playing. Changing the playing position + /// when the stream is stopped has no effect, since playing + /// the stream would reset its position. + /// + /// \param timeOffset New playing position, from the beginning of the stream + /// + /// \see getPlayingOffset + /// + //////////////////////////////////////////////////////////// + void setPlayingOffset(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Get the current playing position of the stream + /// + /// \return Current playing position, from the beginning of the stream + /// + /// \see setPlayingOffset + /// + //////////////////////////////////////////////////////////// + Time getPlayingOffset() const; + + //////////////////////////////////////////////////////////// + /// \brief Set whether or not the stream should loop after reaching the end + /// + /// If set, the stream will restart from beginning after + /// reaching the end and so on, until it is stopped or + /// setLoop(false) is called. + /// The default looping state for streams is false. + /// + /// \param loop True to play in loop, false to play once + /// + /// \see getLoop + /// + //////////////////////////////////////////////////////////// + void setLoop(bool loop); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the stream is in loop mode + /// + /// \return True if the stream is looping, false otherwise + /// + /// \see setLoop + /// + //////////////////////////////////////////////////////////// + bool getLoop() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is only meant to be called by derived classes. + /// + //////////////////////////////////////////////////////////// + SoundStream(); + + //////////////////////////////////////////////////////////// + /// \brief Define the audio stream parameters + /// + /// This function must be called by derived classes as soon + /// as they know the audio settings of the stream to play. + /// Any attempt to manipulate the stream (play(), ...) before + /// calling this function will fail. + /// It can be called multiple times if the settings of the + /// audio stream change, but only when the stream is stopped. + /// + /// \param channelCount Number of channels of the stream + /// \param sampleRate Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + void initialize(unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Request a new chunk of audio samples from the stream source + /// + /// This function must be overridden by derived classes to provide + /// the audio samples to play. It is called continuously by the + /// streaming loop, in a separate thread. + /// The source can choose to stop the streaming loop at any time, by + /// returning false to the caller. + /// If you return true (i.e. continue streaming) it is important that + /// the returned array of samples is not empty; this would stop the stream + /// due to an internal limitation. + /// + /// \param data Chunk of data to fill + /// + /// \return True to continue playback, false to stop + /// + //////////////////////////////////////////////////////////// + virtual bool onGetData(Chunk& data) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position in the stream source + /// + /// This function must be overridden by derived classes to + /// allow random seeking into the stream source. + /// + /// \param timeOffset New playing position, relative to the beginning of the stream + /// + //////////////////////////////////////////////////////////// + virtual void onSeek(Time timeOffset) = 0; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Function called as the entry point of the thread + /// + /// This function starts the streaming loop, and returns + /// only when the sound is stopped. + /// + //////////////////////////////////////////////////////////// + void streamData(); + + //////////////////////////////////////////////////////////// + /// \brief Fill a new buffer with audio samples, and append + /// it to the playing queue + /// + /// This function is called as soon as a buffer has been fully + /// consumed; it fills it again and inserts it back into the + /// playing queue. + /// + /// \param bufferNum Number of the buffer to fill (in [0, BufferCount]) + /// + /// \return True if the stream source has requested to stop, false otherwise + /// + //////////////////////////////////////////////////////////// + bool fillAndPushBuffer(unsigned int bufferNum); + + //////////////////////////////////////////////////////////// + /// \brief Fill the audio buffers and put them all into the playing queue + /// + /// This function is called when playing starts and the + /// playing queue is empty. + /// + /// \return True if the derived class has requested to stop, false otherwise + /// + //////////////////////////////////////////////////////////// + bool fillQueue(); + + //////////////////////////////////////////////////////////// + /// \brief Clear all the audio buffers and empty the playing queue + /// + /// This function is called when the stream is stopped. + /// + //////////////////////////////////////////////////////////// + void clearQueue(); + + enum + { + BufferCount = 3 ///< Number of audio buffers used by the streaming loop + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Thread m_thread; ///< Thread running the background tasks + mutable Mutex m_threadMutex; ///< Thread mutex + Status m_threadStartState; ///< State the thread starts in (Playing, Paused, Stopped) + bool m_isStreaming; ///< Streaming state (true = playing, false = stopped) + unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data + unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...) + unsigned int m_sampleRate; ///< Frequency (samples / second) + Uint32 m_format; ///< Format of the internal sound buffers + bool m_loop; ///< Loop flag (true to loop, false to play once) + Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream + bool m_endBuffers[BufferCount]; ///< Each buffer is marked as "end buffer" or not, for proper duration calculation +}; + +} // namespace sf + + +#endif // SFML_SOUNDSTREAM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SoundStream +/// \ingroup audio +/// +/// Unlike audio buffers (see sf::SoundBuffer), audio streams +/// are never completely loaded in memory. Instead, the audio +/// data is acquired continuously while the stream is playing. +/// This behavior allows to play a sound with no loading delay, +/// and keeps the memory consumption very low. +/// +/// Sound sources that need to be streamed are usually big files +/// (compressed audio musics that would eat hundreds of MB in memory) +/// or files that would take a lot of time to be received +/// (sounds played over the network). +/// +/// sf::SoundStream is a base class that doesn't care about the +/// stream source, which is left to the derived class. SFML provides +/// a built-in specialization for big files (see sf::Music). +/// No network stream source is provided, but you can write your own +/// by combining this class with the network module. +/// +/// A derived class has to override two virtual functions: +/// \li onGetData fills a new chunk of audio data to be played +/// \li onSeek changes the current playing position in the source +/// +/// It is important to note that each SoundStream is played in its +/// own separate thread, so that the streaming loop doesn't block the +/// rest of the program. In particular, the OnGetData and OnSeek +/// virtual functions may sometimes be called from this separate thread. +/// It is important to keep this in mind, because you may have to take +/// care of synchronization issues if you share data between threads. +/// +/// Usage example: +/// \code +/// class CustomStream : public sf::SoundStream +/// { +/// public: +/// +/// bool open(const std::string& location) +/// { +/// // Open the source and get audio settings +/// ... +/// unsigned int channelCount = ...; +/// unsigned int sampleRate = ...; +/// +/// // Initialize the stream -- important! +/// initialize(channelCount, sampleRate); +/// } +/// +/// private: +/// +/// virtual bool onGetData(Chunk& data) +/// { +/// // Fill the chunk with audio data from the stream source +/// // (note: must not be empty if you want to continue playing) +/// data.samples = ...; +/// data.sampleCount = ...; +/// +/// // Return true to continue playing +/// return true; +/// } +/// +/// virtual void onSeek(Uint32 timeOffset) +/// { +/// // Change the current position in the stream source +/// ... +/// } +/// } +/// +/// // Usage +/// CustomStream stream; +/// stream.open("path/to/stream"); +/// stream.play(); +/// \endcode +/// +/// \see sf::Music +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp new file mode 100644 index 0000000..9c68d84 --- /dev/null +++ b/include/SFML/Config.hpp @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONFIG_HPP +#define SFML_CONFIG_HPP + + +//////////////////////////////////////////////////////////// +// Define the SFML version +//////////////////////////////////////////////////////////// +#define SFML_VERSION_MAJOR 2 +#define SFML_VERSION_MINOR 4 +#define SFML_VERSION_PATCH 1 + + +//////////////////////////////////////////////////////////// +// Identify the operating system +// see http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system +//////////////////////////////////////////////////////////// +#if defined(_WIN32) + + // Windows + #define SFML_SYSTEM_WINDOWS + #ifndef NOMINMAX + #define NOMINMAX + #endif + +#elif defined(__APPLE__) && defined(__MACH__) + + // Apple platform, see which one it is + #include "TargetConditionals.h" + + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + + // iOS + #define SFML_SYSTEM_IOS + + #elif TARGET_OS_MAC + + // MacOS + #define SFML_SYSTEM_MACOS + + #else + + // Unsupported Apple system + #error This Apple operating system is not supported by SFML library + + #endif + +#elif defined(__unix__) + + // UNIX system, see which one it is + #if defined(__ANDROID__) + + // Android + #define SFML_SYSTEM_ANDROID + + #elif defined(__linux__) + + // Linux + #define SFML_SYSTEM_LINUX + + #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + + // FreeBSD + #define SFML_SYSTEM_FREEBSD + + #else + + // Unsupported UNIX system + #error This UNIX operating system is not supported by SFML library + + #endif + +#else + + // Unsupported system + #error This operating system is not supported by SFML library + +#endif + + +//////////////////////////////////////////////////////////// +// Define a portable debug macro +//////////////////////////////////////////////////////////// +#if !defined(NDEBUG) + + #define SFML_DEBUG + +#endif + + +//////////////////////////////////////////////////////////// +// Define helpers to create portable import / export macros for each module +//////////////////////////////////////////////////////////// +#if !defined(SFML_STATIC) + + #if defined(SFML_SYSTEM_WINDOWS) + + // Windows compilers need specific (and different) keywords for export and import + #define SFML_API_EXPORT __declspec(dllexport) + #define SFML_API_IMPORT __declspec(dllimport) + + // For Visual C++ compilers, we also need to turn off this annoying C4251 warning + #ifdef _MSC_VER + + #pragma warning(disable: 4251) + + #endif + + #else // Linux, FreeBSD, Mac OS X + + #if __GNUC__ >= 4 + + // GCC 4 has special keywords for showing/hidding symbols, + // the same keyword is used for both importing and exporting + #define SFML_API_EXPORT __attribute__ ((__visibility__ ("default"))) + #define SFML_API_IMPORT __attribute__ ((__visibility__ ("default"))) + + #else + + // GCC < 4 has no mechanism to explicitely hide symbols, everything's exported + #define SFML_API_EXPORT + #define SFML_API_IMPORT + + #endif + + #endif + +#else + + // Static build doesn't need import/export macros + #define SFML_API_EXPORT + #define SFML_API_IMPORT + +#endif + + +//////////////////////////////////////////////////////////// +// Cross-platform warning for deprecated functions and classes +// +// Usage: +// class SFML_DEPRECATED MyClass +// { +// SFML_DEPRECATED void memberFunc(); +// }; +// +// SFML_DEPRECATED void globalFunc(); +//////////////////////////////////////////////////////////// +#if defined(SFML_NO_DEPRECATED_WARNINGS) + + // User explicitly requests to disable deprecation warnings + #define SFML_DEPRECATED + +#elif defined(_MSC_VER) + + // Microsoft C++ compiler + // Note: On newer MSVC versions, using deprecated functions causes a compiler error. In order to + // trigger a warning instead of an error, the compiler flag /sdl- (instead of /sdl) must be specified. + #define SFML_DEPRECATED __declspec(deprecated) + +#elif defined(__GNUC__) + + // g++ and Clang + #define SFML_DEPRECATED __attribute__ ((deprecated)) + +#else + + // Other compilers are not supported, leave class or function as-is. + // With a bit of luck, the #pragma directive works, otherwise users get a warning (no error!) for unrecognized #pragma. + #pragma message("SFML_DEPRECATED is not supported for your compiler, please contact the SFML team") + #define SFML_DEPRECATED + +#endif + + +//////////////////////////////////////////////////////////// +// Define portable fixed-size types +//////////////////////////////////////////////////////////// +namespace sf +{ + // All "common" platforms use the same size for char, short and int + // (basically there are 3 types for 3 sizes, so no other match is possible), + // we can use them without doing any kind of check + + // 8 bits integer types + typedef signed char Int8; + typedef unsigned char Uint8; + + // 16 bits integer types + typedef signed short Int16; + typedef unsigned short Uint16; + + // 32 bits integer types + typedef signed int Int32; + typedef unsigned int Uint32; + + // 64 bits integer types + #if defined(_MSC_VER) + typedef signed __int64 Int64; + typedef unsigned __int64 Uint64; + #else + typedef signed long long Int64; + typedef unsigned long long Uint64; + #endif + +} // namespace sf + + +#endif // SFML_CONFIG_HPP diff --git a/include/SFML/Graphics.hpp b/include/SFML/Graphics.hpp new file mode 100644 index 0000000..6bcf299 --- /dev/null +++ b/include/SFML/Graphics.hpp @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GRAPHICS_HPP +#define SFML_GRAPHICS_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif // SFML_GRAPHICS_HPP + +//////////////////////////////////////////////////////////// +/// \defgroup graphics Graphics module +/// +/// 2D graphics module: sprites, text, shapes, ... +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/BlendMode.hpp b/include/SFML/Graphics/BlendMode.hpp new file mode 100644 index 0000000..76aa72c --- /dev/null +++ b/include/SFML/Graphics/BlendMode.hpp @@ -0,0 +1,215 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_BLENDMODE_HPP +#define SFML_BLENDMODE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ + +//////////////////////////////////////////////////////////// +/// \brief Blending modes for drawing +/// +//////////////////////////////////////////////////////////// +struct SFML_GRAPHICS_API BlendMode +{ + //////////////////////////////////////////////////////// + /// \brief Enumeration of the blending factors + /// + /// The factors are mapped directly to their OpenGL equivalents, + /// specified by glBlendFunc() or glBlendFuncSeparate(). + //////////////////////////////////////////////////////// + enum Factor + { + Zero, ///< (0, 0, 0, 0) + One, ///< (1, 1, 1, 1) + SrcColor, ///< (src.r, src.g, src.b, src.a) + OneMinusSrcColor, ///< (1, 1, 1, 1) - (src.r, src.g, src.b, src.a) + DstColor, ///< (dst.r, dst.g, dst.b, dst.a) + OneMinusDstColor, ///< (1, 1, 1, 1) - (dst.r, dst.g, dst.b, dst.a) + SrcAlpha, ///< (src.a, src.a, src.a, src.a) + OneMinusSrcAlpha, ///< (1, 1, 1, 1) - (src.a, src.a, src.a, src.a) + DstAlpha, ///< (dst.a, dst.a, dst.a, dst.a) + OneMinusDstAlpha ///< (1, 1, 1, 1) - (dst.a, dst.a, dst.a, dst.a) + }; + + //////////////////////////////////////////////////////// + /// \brief Enumeration of the blending equations + /// + /// The equations are mapped directly to their OpenGL equivalents, + /// specified by glBlendEquation() or glBlendEquationSeparate(). + //////////////////////////////////////////////////////// + enum Equation + { + Add, ///< Pixel = Src * SrcFactor + Dst * DstFactor + Subtract, ///< Pixel = Src * SrcFactor - Dst * DstFactor + ReverseSubtract ///< Pixel = Dst * DstFactor - Src * SrcFactor + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs a blending mode that does alpha blending. + /// + //////////////////////////////////////////////////////////// + BlendMode(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the blend mode given the factors and equation. + /// + /// This constructor uses the same factors and equation for both + /// color and alpha components. It also defaults to the Add equation. + /// + /// \param sourceFactor Specifies how to compute the source factor for the color and alpha channels. + /// \param destinationFactor Specifies how to compute the destination factor for the color and alpha channels. + /// \param blendEquation Specifies how to combine the source and destination colors and alpha. + /// + //////////////////////////////////////////////////////////// + BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation = Add); + + //////////////////////////////////////////////////////////// + /// \brief Construct the blend mode given the factors and equation. + /// + /// \param colorSourceFactor Specifies how to compute the source factor for the color channels. + /// \param colorDestinationFactor Specifies how to compute the destination factor for the color channels. + /// \param colorBlendEquation Specifies how to combine the source and destination colors. + /// \param alphaSourceFactor Specifies how to compute the source factor. + /// \param alphaDestinationFactor Specifies how to compute the destination factor. + /// \param alphaBlendEquation Specifies how to combine the source and destination alphas. + /// + //////////////////////////////////////////////////////////// + BlendMode(Factor colorSourceFactor, Factor colorDestinationFactor, + Equation colorBlendEquation, Factor alphaSourceFactor, + Factor alphaDestinationFactor, Equation alphaBlendEquation); + + //////////////////////////////////////////////////////////// + // Member Data + //////////////////////////////////////////////////////////// + Factor colorSrcFactor; ///< Source blending factor for the color channels + Factor colorDstFactor; ///< Destination blending factor for the color channels + Equation colorEquation; ///< Blending equation for the color channels + Factor alphaSrcFactor; ///< Source blending factor for the alpha channel + Factor alphaDstFactor; ///< Destination blending factor for the alpha channel + Equation alphaEquation; ///< Blending equation for the alpha channel +}; + +//////////////////////////////////////////////////////////// +/// \relates BlendMode +/// \brief Overload of the == operator +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if blending modes are equal, false if they are different +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator ==(const BlendMode& left, const BlendMode& right); + +//////////////////////////////////////////////////////////// +/// \relates BlendMode +/// \brief Overload of the != operator +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if blending modes are different, false if they are equal +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator !=(const BlendMode& left, const BlendMode& right); + +//////////////////////////////////////////////////////////// +// Commonly used blending modes +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API extern const BlendMode BlendAlpha; ///< Blend source and dest according to dest alpha +SFML_GRAPHICS_API extern const BlendMode BlendAdd; ///< Add source to dest +SFML_GRAPHICS_API extern const BlendMode BlendMultiply; ///< Multiply source and dest +SFML_GRAPHICS_API extern const BlendMode BlendNone; ///< Overwrite dest with source + +} // namespace sf + + +#endif // SFML_BLENDMODE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::BlendMode +/// \ingroup graphics +/// +/// sf::BlendMode is a class that represents a blend mode. A blend +/// mode determines how the colors of an object you draw are +/// mixed with the colors that are already in the buffer. +/// +/// The class is composed of 6 components, each of which has its +/// own public member variable: +/// \li %Color Source Factor (@ref colorSrcFactor) +/// \li %Color Destination Factor (@ref colorDstFactor) +/// \li %Color Blend Equation (@ref colorEquation) +/// \li Alpha Source Factor (@ref alphaSrcFactor) +/// \li Alpha Destination Factor (@ref alphaDstFactor) +/// \li Alpha Blend Equation (@ref alphaEquation) +/// +/// The source factor specifies how the pixel you are drawing contributes +/// to the final color. The destination factor specifies how the pixel +/// already drawn in the buffer contributes to the final color. +/// +/// The color channels RGB (red, green, blue; simply referred to as +/// color) and A (alpha; the transparency) can be treated separately. This +/// separation can be useful for specific blend modes, but most often you +/// won't need it and will simply treat the color as a single unit. +/// +/// The blend factors and equations correspond to their OpenGL equivalents. +/// In general, the color of the resulting pixel is calculated according +/// to the following formula (\a src is the color of the source pixel, \a dst +/// the color of the destination pixel, the other variables correspond to the +/// public members, with the equations being + or - operators): +/// \code +/// dst.rgb = colorSrcFactor * src.rgb (colorEquation) colorDstFactor * dst.rgb +/// dst.a = alphaSrcFactor * src.a (alphaEquation) alphaDstFactor * dst.a +/// \endcode +/// All factors and colors are represented as floating point numbers between +/// 0 and 1. Where necessary, the result is clamped to fit in that range. +/// +/// The most common blending modes are defined as constants +/// in the sf namespace: +/// +/// \code +/// sf::BlendMode alphaBlending = sf::BlendAlpha; +/// sf::BlendMode additiveBlending = sf::BlendAdd; +/// sf::BlendMode multiplicativeBlending = sf::BlendMultiply; +/// sf::BlendMode noBlending = sf::BlendNone; +/// \endcode +/// +/// In SFML, a blend mode can be specified every time you draw a sf::Drawable +/// object to a render target. It is part of the sf::RenderStates compound +/// that is passed to the member function sf::RenderTarget::draw(). +/// +/// \see sf::RenderStates, sf::RenderTarget +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/CircleShape.hpp b/include/SFML/Graphics/CircleShape.hpp new file mode 100644 index 0000000..018a52a --- /dev/null +++ b/include/SFML/Graphics/CircleShape.hpp @@ -0,0 +1,154 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CIRCLESHAPE_HPP +#define SFML_CIRCLESHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a circle +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API CircleShape : public Shape +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param radius Radius of the circle + /// \param pointCount Number of points composing the circle + /// + //////////////////////////////////////////////////////////// + explicit CircleShape(float radius = 0, std::size_t pointCount = 30); + + //////////////////////////////////////////////////////////// + /// \brief Set the radius of the circle + /// + /// \param radius New radius of the circle + /// + /// \see getRadius + /// + //////////////////////////////////////////////////////////// + void setRadius(float radius); + + //////////////////////////////////////////////////////////// + /// \brief Get the radius of the circle + /// + /// \return Radius of the circle + /// + /// \see setRadius + /// + //////////////////////////////////////////////////////////// + float getRadius() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the circle + /// + /// \param count New number of points of the circle + /// + /// \see getPointCount + /// + //////////////////////////////////////////////////////////// + void setPointCount(std::size_t count); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points of the circle + /// + /// \return Number of points of the circle + /// + /// \see setPointCount + /// + //////////////////////////////////////////////////////////// + virtual std::size_t getPointCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a point of the circle + /// + /// The returned point is in local coordinates, that is, + /// the shape's transforms (position, rotation, scale) are + /// not taken into account. + /// The result is undefined if \a index is out of the valid range. + /// + /// \param index Index of the point to get, in range [0 .. getPointCount() - 1] + /// + /// \return index-th point of the shape + /// + //////////////////////////////////////////////////////////// + virtual Vector2f getPoint(std::size_t index) const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float m_radius; ///< Radius of the circle + std::size_t m_pointCount; ///< Number of points composing the circle +}; + +} // namespace sf + + +#endif // SFML_CIRCLESHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::CircleShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// Usage example: +/// \code +/// sf::CircleShape circle; +/// circle.setRadius(150); +/// circle.setOutlineColor(sf::Color::Red); +/// circle.setOutlineThickness(5); +/// circle.setPosition(10, 20); +/// ... +/// window.draw(circle); +/// \endcode +/// +/// Since the graphics card can't draw perfect circles, we have to +/// fake them with multiple triangles connected to each other. The +/// "points count" property of sf::CircleShape defines how many of these +/// triangles to use, and therefore defines the quality of the circle. +/// +/// The number of points can also be used for another purpose; with +/// small numbers you can create any regular polygon shape: +/// equilateral triangle, square, pentagon, hexagon, ... +/// +/// \see sf::Shape, sf::RectangleShape, sf::ConvexShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Color.hpp b/include/SFML/Graphics/Color.hpp new file mode 100644 index 0000000..ff35de5 --- /dev/null +++ b/include/SFML/Graphics/Color.hpp @@ -0,0 +1,275 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_COLOR_HPP +#define SFML_COLOR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility class for manipulating RGBA colors +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Color +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs an opaque black color. It is equivalent to + /// sf::Color(0, 0, 0, 255). + /// + //////////////////////////////////////////////////////////// + Color(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the color from its 4 RGBA components + /// + /// \param red Red component (in the range [0, 255]) + /// \param green Green component (in the range [0, 255]) + /// \param blue Blue component (in the range [0, 255]) + /// \param alpha Alpha (opacity) component (in the range [0, 255]) + /// + //////////////////////////////////////////////////////////// + Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = 255); + + //////////////////////////////////////////////////////////// + /// \brief Construct the color from 32-bit unsigned integer + /// + /// \param color Number containing the RGBA components (in that order) + /// + //////////////////////////////////////////////////////////// + explicit Color(Uint32 color); + + //////////////////////////////////////////////////////////// + /// \brief Retrieve the color as a 32-bit unsigned integer + /// + /// \return Color represented as a 32-bit unsigned integer + /// + //////////////////////////////////////////////////////////// + Uint32 toInteger() const; + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const Color Black; ///< Black predefined color + static const Color White; ///< White predefined color + static const Color Red; ///< Red predefined color + static const Color Green; ///< Green predefined color + static const Color Blue; ///< Blue predefined color + static const Color Yellow; ///< Yellow predefined color + static const Color Magenta; ///< Magenta predefined color + static const Color Cyan; ///< Cyan predefined color + static const Color Transparent; ///< Transparent (black) predefined color + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Uint8 r; ///< Red component + Uint8 g; ///< Green component + Uint8 b; ///< Blue component + Uint8 a; ///< Alpha (opacity) component +}; + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the == operator +/// +/// This operator compares two colors and check if they are equal. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if colors are equal, false if they are different +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator ==(const Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the != operator +/// +/// This operator compares two colors and check if they are different. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if colors are different, false if they are equal +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator !=(const Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary + operator +/// +/// This operator returns the component-wise sum of two colors. +/// Components that exceed 255 are clamped to 255. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Result of \a left + \a right +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color operator +(const Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary - operator +/// +/// This operator returns the component-wise subtraction of two colors. +/// Components below 0 are clamped to 0. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Result of \a left - \a right +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color operator -(const Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary * operator +/// +/// This operator returns the component-wise multiplication +/// (also called "modulation") of two colors. +/// Components are then divided by 255 so that the result is +/// still in the range [0, 255]. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Result of \a left * \a right +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color operator *(const Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary += operator +/// +/// This operator computes the component-wise sum of two colors, +/// and assigns the result to the left operand. +/// Components that exceed 255 are clamped to 255. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color& operator +=(Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary -= operator +/// +/// This operator computes the component-wise subtraction of two colors, +/// and assigns the result to the left operand. +/// Components below 0 are clamped to 0. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color& operator -=(Color& left, const Color& right); + +//////////////////////////////////////////////////////////// +/// \relates Color +/// \brief Overload of the binary *= operator +/// +/// This operator returns the component-wise multiplication +/// (also called "modulation") of two colors, and assigns +/// the result to the left operand. +/// Components are then divided by 255 so that the result is +/// still in the range [0, 255]. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Color& operator *=(Color& left, const Color& right); + +} // namespace sf + + +#endif // SFML_COLOR_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Color +/// \ingroup graphics +/// +/// sf::Color is a simple color class composed of 4 components: +/// \li Red +/// \li Green +/// \li Blue +/// \li Alpha (opacity) +/// +/// Each component is a public member, an unsigned integer in +/// the range [0, 255]. Thus, colors can be constructed and +/// manipulated very easily: +/// +/// \code +/// sf::Color color(255, 0, 0); // red +/// color.r = 0; // make it black +/// color.b = 128; // make it dark blue +/// \endcode +/// +/// The fourth component of colors, named "alpha", represents +/// the opacity of the color. A color with an alpha value of +/// 255 will be fully opaque, while an alpha value of 0 will +/// make a color fully transparent, whatever the value of the +/// other components is. +/// +/// The most common colors are already defined as static variables: +/// \code +/// sf::Color black = sf::Color::Black; +/// sf::Color white = sf::Color::White; +/// sf::Color red = sf::Color::Red; +/// sf::Color green = sf::Color::Green; +/// sf::Color blue = sf::Color::Blue; +/// sf::Color yellow = sf::Color::Yellow; +/// sf::Color magenta = sf::Color::Magenta; +/// sf::Color cyan = sf::Color::Cyan; +/// sf::Color transparent = sf::Color::Transparent; +/// \endcode +/// +/// Colors can also be added and modulated (multiplied) using the +/// overloaded operators + and *. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/ConvexShape.hpp b/include/SFML/Graphics/ConvexShape.hpp new file mode 100644 index 0000000..5c548a8 --- /dev/null +++ b/include/SFML/Graphics/ConvexShape.hpp @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONVEXSHAPE_HPP +#define SFML_CONVEXSHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a convex polygon +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API ConvexShape : public Shape +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param pointCount Number of points of the polygon + /// + //////////////////////////////////////////////////////////// + explicit ConvexShape(std::size_t pointCount = 0); + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the polygon + /// + /// \a count must be greater than 2 to define a valid shape. + /// + /// \param count New number of points of the polygon + /// + /// \see getPointCount + /// + //////////////////////////////////////////////////////////// + void setPointCount(std::size_t count); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points of the polygon + /// + /// \return Number of points of the polygon + /// + /// \see setPointCount + /// + //////////////////////////////////////////////////////////// + virtual std::size_t getPointCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the position of a point + /// + /// Don't forget that the polygon must remain convex, and + /// the points need to stay ordered! + /// setPointCount must be called first in order to set the total + /// number of points. The result is undefined if \a index is out + /// of the valid range. + /// + /// \param index Index of the point to change, in range [0 .. getPointCount() - 1] + /// \param point New position of the point + /// + /// \see getPoint + /// + //////////////////////////////////////////////////////////// + void setPoint(std::size_t index, const Vector2f& point); + + //////////////////////////////////////////////////////////// + /// \brief Get the position of a point + /// + /// The returned point is in local coordinates, that is, + /// the shape's transforms (position, rotation, scale) are + /// not taken into account. + /// The result is undefined if \a index is out of the valid range. + /// + /// \param index Index of the point to get, in range [0 .. getPointCount() - 1] + /// + /// \return Position of the index-th point of the polygon + /// + /// \see setPoint + /// + //////////////////////////////////////////////////////////// + virtual Vector2f getPoint(std::size_t index) const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_points; ///< Points composing the convex polygon +}; + +} // namespace sf + + +#endif // SFML_CONVEXSHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::ConvexShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// It is important to keep in mind that a convex shape must +/// always be... convex, otherwise it may not be drawn correctly. +/// Moreover, the points must be defined in order; using a random +/// order would result in an incorrect shape. +/// +/// Usage example: +/// \code +/// sf::ConvexShape polygon; +/// polygon.setPointCount(3); +/// polygon.setPoint(0, sf::Vector2f(0, 0)); +/// polygon.setPoint(1, sf::Vector2f(0, 10)); +/// polygon.setPoint(2, sf::Vector2f(25, 5)); +/// polygon.setOutlineColor(sf::Color::Red); +/// polygon.setOutlineThickness(5); +/// polygon.setPosition(10, 20); +/// ... +/// window.draw(polygon); +/// \endcode +/// +/// \see sf::Shape, sf::RectangleShape, sf::CircleShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Drawable.hpp b/include/SFML/Graphics/Drawable.hpp new file mode 100644 index 0000000..9ade3bc --- /dev/null +++ b/include/SFML/Graphics/Drawable.hpp @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_DRAWABLE_HPP +#define SFML_DRAWABLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class RenderTarget; + +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for objects that can be drawn +/// to a render target +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Drawable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Drawable() {} + +protected: + + friend class RenderTarget; + + //////////////////////////////////////////////////////////// + /// \brief Draw the object to a render target + /// + /// This is a pure virtual function that has to be implemented + /// by the derived class to define how the drawable should be + /// drawn. + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void draw(RenderTarget& target, RenderStates states) const = 0; +}; + +} // namespace sf + + +#endif // SFML_DRAWABLE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Drawable +/// \ingroup graphics +/// +/// sf::Drawable is a very simple base class that allows objects +/// of derived classes to be drawn to a sf::RenderTarget. +/// +/// All you have to do in your derived class is to override the +/// draw virtual function. +/// +/// Note that inheriting from sf::Drawable is not mandatory, +/// but it allows this nice syntax "window.draw(object)" rather +/// than "object.draw(window)", which is more consistent with other +/// SFML classes. +/// +/// Example: +/// \code +/// class MyDrawable : public sf::Drawable +/// { +/// public: +/// +/// ... +/// +/// private: +/// +/// virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const +/// { +/// // You can draw other high-level objects +/// target.draw(m_sprite, states); +/// +/// // ... or use the low-level API +/// states.texture = &m_texture; +/// target.draw(m_vertices, states); +/// +/// // ... or draw with OpenGL directly +/// glBegin(GL_QUADS); +/// ... +/// glEnd(); +/// } +/// +/// sf::Sprite m_sprite; +/// sf::Texture m_texture; +/// sf::VertexArray m_vertices; +/// }; +/// \endcode +/// +/// \see sf::RenderTarget +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Export.hpp b/include/SFML/Graphics/Export.hpp new file mode 100644 index 0000000..d11f419 --- /dev/null +++ b/include/SFML/Graphics/Export.hpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GRAPHICS_EXPORT_HPP +#define SFML_GRAPHICS_EXPORT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_GRAPHICS_EXPORTS) + + #define SFML_GRAPHICS_API SFML_API_EXPORT + +#else + + #define SFML_GRAPHICS_API SFML_API_IMPORT + +#endif + + +#endif // SFML_GRAPHICS_EXPORT_HPP diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp new file mode 100644 index 0000000..1420b70 --- /dev/null +++ b/include/SFML/Graphics/Font.hpp @@ -0,0 +1,439 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_FONT_HPP +#define SFML_FONT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Class for loading and manipulating character fonts +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Font +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Holds various information about a font + /// + //////////////////////////////////////////////////////////// + struct Info + { + std::string family; ///< The font family + }; + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor defines an empty font + /// + //////////////////////////////////////////////////////////// + Font(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + Font(const Font& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Cleans up all the internal resources used by the font + /// + //////////////////////////////////////////////////////////// + ~Font(); + + //////////////////////////////////////////////////////////// + /// \brief Load the font from a file + /// + /// The supported font formats are: TrueType, Type 1, CFF, + /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. + /// Note that this function know nothing about the standard + /// fonts installed on the user's system, thus you can't + /// load them directly. + /// + /// \warning SFML cannot preload all the font data in this + /// function, so the file has to remain accessible until + /// the sf::Font object loads a new font or is destroyed. + /// + /// \param filename Path of the font file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Load the font from a file in memory + /// + /// The supported font formats are: TrueType, Type 1, CFF, + /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. + /// + /// \warning SFML cannot preload all the font data in this + /// function, so the buffer pointed by \a data has to remain + /// valid until the sf::Font object loads a new font or + /// is destroyed. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Load the font from a custom stream + /// + /// The supported font formats are: TrueType, Type 1, CFF, + /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. + /// Warning: SFML cannot preload all the font data in this + /// function, so the contents of \a stream have to remain + /// valid as long as the font is used. + /// + /// \warning SFML cannot preload all the font data in this + /// function, so the stream has to remain accessible until + /// the sf::Font object loads a new font or is destroyed. + /// + /// \param stream Source stream to read from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Get the font information + /// + /// \return A structure that holds the font information + /// + //////////////////////////////////////////////////////////// + const Info& getInfo() const; + + //////////////////////////////////////////////////////////// + /// \brief Retrieve a glyph of the font + /// + /// If the font is a bitmap font, not all character sizes + /// might be available. If the glyph is not available at the + /// requested size, an empty glyph is returned. + /// + /// Be aware that using a negative value for the outline + /// thickness will cause distorted rendering. + /// + /// \param codePoint Unicode code point of the character to get + /// \param characterSize Reference character size + /// \param bold Retrieve the bold version or the regular one? + /// \param outlineThickness Thickness of outline (when != 0 the glyph will not be filled) + /// + /// \return The glyph corresponding to \a codePoint and \a characterSize + /// + //////////////////////////////////////////////////////////// + const Glyph& getGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness = 0) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the kerning offset of two glyphs + /// + /// The kerning is an extra offset (negative) to apply between two + /// glyphs when rendering them, to make the pair look more "natural". + /// For example, the pair "AV" have a special kerning to make them + /// closer than other characters. Most of the glyphs pairs have a + /// kerning offset of zero, though. + /// + /// \param first Unicode code point of the first character + /// \param second Unicode code point of the second character + /// \param characterSize Reference character size + /// + /// \return Kerning value for \a first and \a second, in pixels + /// + //////////////////////////////////////////////////////////// + float getKerning(Uint32 first, Uint32 second, unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the line spacing + /// + /// Line spacing is the vertical offset to apply between two + /// consecutive lines of text. + /// + /// \param characterSize Reference character size + /// + /// \return Line spacing, in pixels + /// + //////////////////////////////////////////////////////////// + float getLineSpacing(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the position of the underline + /// + /// Underline position is the vertical offset to apply between the + /// baseline and the underline. + /// + /// \param characterSize Reference character size + /// + /// \return Underline position, in pixels + /// + /// \see getUnderlineThickness + /// + //////////////////////////////////////////////////////////// + float getUnderlinePosition(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the thickness of the underline + /// + /// Underline thickness is the vertical size of the underline. + /// + /// \param characterSize Reference character size + /// + /// \return Underline thickness, in pixels + /// + /// \see getUnderlinePosition + /// + //////////////////////////////////////////////////////////// + float getUnderlineThickness(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Retrieve the texture containing the loaded glyphs of a certain size + /// + /// The contents of the returned texture changes as more glyphs + /// are requested, thus it is not very relevant. It is mainly + /// used internally by sf::Text. + /// + /// \param characterSize Reference character size + /// + /// \return Texture containing the glyphs of the requested size + /// + //////////////////////////////////////////////////////////// + const Texture& getTexture(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + Font& operator =(const Font& right); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Structure defining a row of glyphs + /// + //////////////////////////////////////////////////////////// + struct Row + { + Row(unsigned int rowTop, unsigned int rowHeight) : width(0), top(rowTop), height(rowHeight) {} + + unsigned int width; ///< Current width of the row + unsigned int top; ///< Y position of the row into the texture + unsigned int height; ///< Height of the row + }; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map GlyphTable; ///< Table mapping a codepoint to its glyph + + //////////////////////////////////////////////////////////// + /// \brief Structure defining a page of glyphs + /// + //////////////////////////////////////////////////////////// + struct Page + { + Page(); + + GlyphTable glyphs; ///< Table mapping code points to their corresponding glyph + Texture texture; ///< Texture containing the pixels of the glyphs + unsigned int nextRow; ///< Y position of the next new row in the texture + std::vector rows; ///< List containing the position of all the existing rows + }; + + //////////////////////////////////////////////////////////// + /// \brief Free all the internal resources + /// + //////////////////////////////////////////////////////////// + void cleanup(); + + //////////////////////////////////////////////////////////// + /// \brief Load a new glyph and store it in the cache + /// + /// \param codePoint Unicode code point of the character to load + /// \param characterSize Reference character size + /// \param bold Retrieve the bold version or the regular one? + /// \param outlineThickness Thickness of outline (when != 0 the glyph will not be filled) + /// + /// \return The glyph corresponding to \a codePoint and \a characterSize + /// + //////////////////////////////////////////////////////////// + Glyph loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const; + + //////////////////////////////////////////////////////////// + /// \brief Find a suitable rectangle within the texture for a glyph + /// + /// \param page Page of glyphs to search in + /// \param width Width of the rectangle + /// \param height Height of the rectangle + /// + /// \return Found rectangle within the texture + /// + //////////////////////////////////////////////////////////// + IntRect findGlyphRect(Page& page, unsigned int width, unsigned int height) const; + + //////////////////////////////////////////////////////////// + /// \brief Make sure that the given size is the current one + /// + /// \param characterSize Reference character size + /// + /// \return True on success, false if any error happened + /// + //////////////////////////////////////////////////////////// + bool setCurrentSize(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map PageTable; ///< Table mapping a character size to its page (texture) + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + void* m_library; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details) + void* m_face; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details) + void* m_streamRec; ///< Pointer to the stream rec instance (it is typeless to avoid exposing implementation details) + void* m_stroker; ///< Pointer to the stroker (it is typeless to avoid exposing implementation details) + int* m_refCount; ///< Reference counter used by implicit sharing + Info m_info; ///< Information about the font + mutable PageTable m_pages; ///< Table containing the glyphs pages by character size + mutable std::vector m_pixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture + #ifdef SFML_SYSTEM_ANDROID + void* m_stream; ///< Asset file streamer (if loaded from file) + #endif +}; + +} // namespace sf + + +#endif // SFML_FONT_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Font +/// \ingroup graphics +/// +/// Fonts can be loaded from a file, from memory or from a custom +/// stream, and supports the most common types of fonts. See +/// the loadFromFile function for the complete list of supported formats. +/// +/// Once it is loaded, a sf::Font instance provides three +/// types of information about the font: +/// \li Global metrics, such as the line spacing +/// \li Per-glyph metrics, such as bounding box or kerning +/// \li Pixel representation of glyphs +/// +/// Fonts alone are not very useful: they hold the font data +/// but cannot make anything useful of it. To do so you need to +/// use the sf::Text class, which is able to properly output text +/// with several options such as character size, style, color, +/// position, rotation, etc. +/// This separation allows more flexibility and better performances: +/// indeed a sf::Font is a heavy resource, and any operation on it +/// is slow (often too slow for real-time applications). On the other +/// side, a sf::Text is a lightweight object which can combine the +/// glyphs data and metrics of a sf::Font to display any text on a +/// render target. +/// Note that it is also possible to bind several sf::Text instances +/// to the same sf::Font. +/// +/// It is important to note that the sf::Text instance doesn't +/// copy the font that it uses, it only keeps a reference to it. +/// Thus, a sf::Font must not be destructed while it is +/// used by a sf::Text (i.e. never write a function that +/// uses a local sf::Font instance for creating a text). +/// +/// Usage example: +/// \code +/// // Declare a new font +/// sf::Font font; +/// +/// // Load it from a file +/// if (!font.loadFromFile("arial.ttf")) +/// { +/// // error... +/// } +/// +/// // Create a text which uses our font +/// sf::Text text1; +/// text1.setFont(font); +/// text1.setCharacterSize(30); +/// text1.setStyle(sf::Text::Regular); +/// +/// // Create another text using the same font, but with different parameters +/// sf::Text text2; +/// text2.setFont(font); +/// text2.setCharacterSize(50); +/// text2.setStyle(sf::Text::Italic); +/// \endcode +/// +/// Apart from loading font files, and passing them to instances +/// of sf::Text, you should normally not have to deal directly +/// with this class. However, it may be useful to access the +/// font metrics or rasterized glyphs for advanced usage. +/// +/// Note that if the font is a bitmap font, it is not scalable, +/// thus not all requested sizes will be available to use. This +/// needs to be taken into consideration when using sf::Text. +/// If you need to display text of a certain size, make sure the +/// corresponding bitmap font that supports that size is used. +/// +/// \see sf::Text +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Glsl.hpp b/include/SFML/Graphics/Glsl.hpp new file mode 100644 index 0000000..74b087f --- /dev/null +++ b/include/SFML/Graphics/Glsl.hpp @@ -0,0 +1,227 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GLSL_HPP +#define SFML_GLSL_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + // Forward declarations + template + struct Matrix; + + template + struct Vector4; + +#include + +} // namespace priv + + +//////////////////////////////////////////////////////////// +/// \brief Namespace with GLSL types +/// +//////////////////////////////////////////////////////////// +namespace Glsl +{ + + //////////////////////////////////////////////////////////// + /// \brief 2D float vector (\p vec2 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector2 Vec2; + + //////////////////////////////////////////////////////////// + /// \brief 2D int vector (\p ivec2 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector2 Ivec2; + + //////////////////////////////////////////////////////////// + /// \brief 2D bool vector (\p bvec2 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector2 Bvec2; + + //////////////////////////////////////////////////////////// + /// \brief 3D float vector (\p vec3 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector3 Vec3; + + //////////////////////////////////////////////////////////// + /// \brief 3D int vector (\p ivec3 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector3 Ivec3; + + //////////////////////////////////////////////////////////// + /// \brief 3D bool vector (\p bvec3 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef Vector3 Bvec3; + +#ifdef SFML_DOXYGEN + + //////////////////////////////////////////////////////////// + /// \brief 4D float vector (\p vec4 in GLSL) + /// + /// 4D float vectors can be implicitly converted from sf::Color + /// instances. Each color channel is normalized from integers + /// in [0, 255] to floating point values in [0, 1]. + /// \code + /// sf::Glsl::Vec4 zeroVector; + /// sf::Glsl::Vec4 vector(1.f, 2.f, 3.f, 4.f); + /// sf::Glsl::Vec4 color = sf::Color::Cyan; + /// \endcode + //////////////////////////////////////////////////////////// + typedef implementation-defined Vec4; + + //////////////////////////////////////////////////////////// + /// \brief 4D int vector (\p ivec4 in GLSL) + /// + /// 4D int vectors can be implicitly converted from sf::Color + /// instances. Each color channel remains unchanged inside + /// the integer interval [0, 255]. + /// \code + /// sf::Glsl::Ivec4 zeroVector; + /// sf::Glsl::Ivec4 vector(1, 2, 3, 4); + /// sf::Glsl::Ivec4 color = sf::Color::Cyan; + /// \endcode + //////////////////////////////////////////////////////////// + typedef implementation-defined Ivec4; + + //////////////////////////////////////////////////////////// + /// \brief 4D bool vector (\p bvec4 in GLSL) + /// + //////////////////////////////////////////////////////////// + typedef implementation-defined Bvec4; + + //////////////////////////////////////////////////////////// + /// \brief 3x3 float matrix (\p mat3 in GLSL) + /// + /// The matrix can be constructed from an array with 3x3 + /// elements, aligned in column-major order. For example, + /// a translation by (x, y) looks as follows: + /// \code + /// float array[9] = + /// { + /// 1, 0, 0, + /// 0, 1, 0, + /// x, y, 1 + /// }; + /// + /// sf::Glsl::Mat3 matrix(array); + /// \endcode + /// + /// Mat3 can also be implicitly converted from sf::Transform: + /// \code + /// sf::Transform transform; + /// sf::Glsl::Mat3 matrix = transform; + /// \endcode + //////////////////////////////////////////////////////////// + typedef implementation-defined Mat3; + + //////////////////////////////////////////////////////////// + /// \brief 4x4 float matrix (\p mat4 in GLSL) + /// + /// The matrix can be constructed from an array with 4x4 + /// elements, aligned in column-major order. For example, + /// a translation by (x, y, z) looks as follows: + /// \code + /// float array[16] = + /// { + /// 1, 0, 0, 0, + /// 0, 1, 0, 0, + /// 0, 0, 1, 0, + /// x, y, z, 1 + /// }; + /// + /// sf::Glsl::Mat4 matrix(array); + /// \endcode + /// + /// Mat4 can also be implicitly converted from sf::Transform: + /// \code + /// sf::Transform transform; + /// sf::Glsl::Mat4 matrix = transform; + /// \endcode + //////////////////////////////////////////////////////////// + typedef implementation-defined Mat4; + +#else // SFML_DOXYGEN + + typedef priv::Vector4 Vec4; + typedef priv::Vector4 Ivec4; + typedef priv::Vector4 Bvec4; + typedef priv::Matrix<3, 3> Mat3; + typedef priv::Matrix<4, 4> Mat4; + +#endif // SFML_DOXYGEN + +} // namespace Glsl +} // namespace sf + +#endif // SFML_GLSL_HPP + + +//////////////////////////////////////////////////////////// +/// \namespace sf::Glsl +/// \ingroup graphics +/// +/// \details The sf::Glsl namespace contains types that match +/// their equivalents in GLSL, the OpenGL shading language. +/// These types are exclusively used by the sf::Shader class. +/// +/// Types that already exist in SFML, such as \ref sf::Vector2 +/// and \ref sf::Vector3, are reused as typedefs, so you can use +/// the types in this namespace as well as the original ones. +/// Others are newly defined, such as Glsl::Vec4 or Glsl::Mat3. Their +/// actual type is an implementation detail and should not be used. +/// +/// All vector types support a default constructor that +/// initializes every component to zero, in addition to a +/// constructor with one parameter for each component. +/// The components are stored in member variables called +/// x, y, z, and w. +/// +/// All matrix types support a constructor with a float* +/// parameter that points to a float array of the appropriate +/// size (that is, 9 in a 3x3 matrix, 16 in a 4x4 matrix). +/// Furthermore, they can be converted from sf::Transform +/// objects. +/// +/// \see sf::Shader +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Glsl.inl b/include/SFML/Graphics/Glsl.inl new file mode 100644 index 0000000..3f2b027 --- /dev/null +++ b/include/SFML/Graphics/Glsl.inl @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +/// \brief Helper functions to copy sf::Transform to sf::Glsl::Mat3/4 +/// +//////////////////////////////////////////////////////////// +void SFML_GRAPHICS_API copyMatrix(const Transform& source, Matrix<3, 3>& dest); +void SFML_GRAPHICS_API copyMatrix(const Transform& source, Matrix<4, 4>& dest); + +//////////////////////////////////////////////////////////// +/// \brief Copy array-based matrix with given number of elements +/// +/// Indirection to std::copy() to avoid inclusion of +/// and MSVC's annoying 4996 warning in header +/// +//////////////////////////////////////////////////////////// +void SFML_GRAPHICS_API copyMatrix(const float* source, std::size_t elements, float* dest); + +//////////////////////////////////////////////////////////// +/// \brief Helper functions to copy sf::Color to sf::Glsl::Vec4/Ivec4 +/// +//////////////////////////////////////////////////////////// +void SFML_GRAPHICS_API copyVector(const Color& source, Vector4& dest); +void SFML_GRAPHICS_API copyVector(const Color& source, Vector4& dest); + + +//////////////////////////////////////////////////////////// +/// \brief Matrix type, used to set uniforms in GLSL +/// +//////////////////////////////////////////////////////////// +template +struct Matrix +{ + //////////////////////////////////////////////////////////// + /// \brief Construct from raw data + /// + /// \param pointer Points to the beginning of an array that + /// has the size of the matrix. The elements + /// are copied to the instance. + /// + //////////////////////////////////////////////////////////// + explicit Matrix(const float* pointer) + { + copyMatrix(pointer, Columns * Rows, array); + } + + //////////////////////////////////////////////////////////// + /// \brief Construct implicitly from SFML transform + /// + /// This constructor is only supported for 3x3 and 4x4 + /// matrices. + /// + /// \param transform Object containing a transform. + /// + //////////////////////////////////////////////////////////// + Matrix(const Transform& transform) + { + copyMatrix(transform, *this); + } + + float array[Columns * Rows]; ///< Array holding matrix data +}; + +//////////////////////////////////////////////////////////// +/// \brief 4D vector type, used to set uniforms in GLSL +/// +//////////////////////////////////////////////////////////// +template +struct Vector4 +{ + //////////////////////////////////////////////////////////// + /// \brief Default constructor, creates a zero vector + /// + //////////////////////////////////////////////////////////// + Vector4() : + x(0), + y(0), + z(0), + w(0) + { + } + + //////////////////////////////////////////////////////////// + /// \brief Construct from 4 vector components + /// + /// \param X Component of the 4D vector + /// \param Y Component of the 4D vector + /// \param Z Component of the 4D vector + /// \param W Component of the 4D vector + /// + //////////////////////////////////////////////////////////// + Vector4(T X, T Y, T Z, T W) : + x(X), + y(Y), + z(Z), + w(W) + { + } + + //////////////////////////////////////////////////////////// + /// \brief Conversion constructor + /// + /// \param other 4D vector of different type + /// + //////////////////////////////////////////////////////////// + template + explicit Vector4(const Vector4& other) : + x(static_cast(other.x)), + y(static_cast(other.y)), + z(static_cast(other.z)), + w(static_cast(other.w)) + { + } + + //////////////////////////////////////////////////////////// + /// \brief Construct float vector implicitly from color + /// + /// \param color Color instance. Is normalized to [0, 1] + /// for floats, and left as-is for ints. + /// + //////////////////////////////////////////////////////////// + Vector4(const Color& color) + // uninitialized + { + copyVector(color, *this); + } + + T x; ///< 1st component (X) of the 4D vector + T y; ///< 2nd component (Y) of the 4D vector + T z; ///< 3rd component (Z) of the 4D vector + T w; ///< 4th component (W) of the 4D vector +}; diff --git a/include/SFML/Graphics/Glyph.hpp b/include/SFML/Graphics/Glyph.hpp new file mode 100644 index 0000000..174eb84 --- /dev/null +++ b/include/SFML/Graphics/Glyph.hpp @@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GLYPH_HPP +#define SFML_GLYPH_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Structure describing a glyph +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Glyph +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Glyph() : advance(0) {} + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float advance; ///< Offset to move horizontally to the next character + FloatRect bounds; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline + IntRect textureRect; ///< Texture coordinates of the glyph inside the font's texture +}; + +} // namespace sf + + +#endif // SFML_GLYPH_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Glyph +/// \ingroup graphics +/// +/// A glyph is the visual representation of a character. +/// +/// The sf::Glyph structure provides the information needed +/// to handle the glyph: +/// \li its coordinates in the font's texture +/// \li its bounding rectangle +/// \li the offset to apply to get the starting position of the next glyph +/// +/// \see sf::Font +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Image.hpp b/include/SFML/Graphics/Image.hpp new file mode 100644 index 0000000..6eaa1f7 --- /dev/null +++ b/include/SFML/Graphics/Image.hpp @@ -0,0 +1,327 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_IMAGE_HPP +#define SFML_IMAGE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Class for loading, manipulating and saving images +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Image +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty image. + /// + //////////////////////////////////////////////////////////// + Image(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Image(); + + //////////////////////////////////////////////////////////// + /// \brief Create the image and fill it with a unique color + /// + /// \param width Width of the image + /// \param height Height of the image + /// \param color Fill color + /// + //////////////////////////////////////////////////////////// + void create(unsigned int width, unsigned int height, const Color& color = Color(0, 0, 0)); + + //////////////////////////////////////////////////////////// + /// \brief Create the image from an array of pixels + /// + /// The \a pixel array is assumed to contain 32-bits RGBA pixels, + /// and have the given \a width and \a height. If not, this is + /// an undefined behavior. + /// If \a pixels is null, an empty image is created. + /// + /// \param width Width of the image + /// \param height Height of the image + /// \param pixels Array of pixels to copy to the image + /// + //////////////////////////////////////////////////////////// + void create(unsigned int width, unsigned int height, const Uint8* pixels); + + //////////////////////////////////////////////////////////// + /// \brief Load the image from a file on disk + /// + /// The supported image formats are bmp, png, tga, jpg, gif, + /// psd, hdr and pic. Some format options are not supported, + /// like progressive jpeg. + /// If this function fails, the image is left unchanged. + /// + /// \param filename Path of the image file to load + /// + /// \return True if loading was successful + /// + /// \see loadFromMemory, loadFromStream, saveToFile + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Load the image from a file in memory + /// + /// The supported image formats are bmp, png, tga, jpg, gif, + /// psd, hdr and pic. Some format options are not supported, + /// like progressive jpeg. + /// If this function fails, the image is left unchanged. + /// + /// \param data Pointer to the file data in memory + /// \param size Size of the data to load, in bytes + /// + /// \return True if loading was successful + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const void* data, std::size_t size); + + //////////////////////////////////////////////////////////// + /// \brief Load the image from a custom stream + /// + /// The supported image formats are bmp, png, tga, jpg, gif, + /// psd, hdr and pic. Some format options are not supported, + /// like progressive jpeg. + /// If this function fails, the image is left unchanged. + /// + /// \param stream Source stream to read from + /// + /// \return True if loading was successful + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Save the image to a file on disk + /// + /// The format of the image is automatically deduced from + /// the extension. The supported image formats are bmp, png, + /// tga and jpg. The destination file is overwritten + /// if it already exists. This function fails if the image is empty. + /// + /// \param filename Path of the file to save + /// + /// \return True if saving was successful + /// + /// \see create, loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool saveToFile(const std::string& filename) const; + + //////////////////////////////////////////////////////////// + /// \brief Return the size (width and height) of the image + /// + /// \return Size of the image, in pixels + /// + //////////////////////////////////////////////////////////// + Vector2u getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Create a transparency mask from a specified color-key + /// + /// This function sets the alpha value of every pixel matching + /// the given color to \a alpha (0 by default), so that they + /// become transparent. + /// + /// \param color Color to make transparent + /// \param alpha Alpha value to assign to transparent pixels + /// + //////////////////////////////////////////////////////////// + void createMaskFromColor(const Color& color, Uint8 alpha = 0); + + //////////////////////////////////////////////////////////// + /// \brief Copy pixels from another image onto this one + /// + /// This function does a slow pixel copy and should not be + /// used intensively. It can be used to prepare a complex + /// static image from several others, but if you need this + /// kind of feature in real-time you'd better use sf::RenderTexture. + /// + /// If \a sourceRect is empty, the whole image is copied. + /// If \a applyAlpha is set to true, the transparency of + /// source pixels is applied. If it is false, the pixels are + /// copied unchanged with their alpha value. + /// + /// \param source Source image to copy + /// \param destX X coordinate of the destination position + /// \param destY Y coordinate of the destination position + /// \param sourceRect Sub-rectangle of the source image to copy + /// \param applyAlpha Should the copy take into account the source transparency? + /// + //////////////////////////////////////////////////////////// + void copy(const Image& source, unsigned int destX, unsigned int destY, const IntRect& sourceRect = IntRect(0, 0, 0, 0), bool applyAlpha = false); + + //////////////////////////////////////////////////////////// + /// \brief Change the color of a pixel + /// + /// This function doesn't check the validity of the pixel + /// coordinates, using out-of-range values will result in + /// an undefined behavior. + /// + /// \param x X coordinate of pixel to change + /// \param y Y coordinate of pixel to change + /// \param color New color of the pixel + /// + /// \see getPixel + /// + //////////////////////////////////////////////////////////// + void setPixel(unsigned int x, unsigned int y, const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Get the color of a pixel + /// + /// This function doesn't check the validity of the pixel + /// coordinates, using out-of-range values will result in + /// an undefined behavior. + /// + /// \param x X coordinate of pixel to get + /// \param y Y coordinate of pixel to get + /// + /// \return Color of the pixel at coordinates (x, y) + /// + /// \see setPixel + /// + //////////////////////////////////////////////////////////// + Color getPixel(unsigned int x, unsigned int y) const; + + //////////////////////////////////////////////////////////// + /// \brief Get a read-only pointer to the array of pixels + /// + /// The returned value points to an array of RGBA pixels made of + /// 8 bits integers components. The size of the array is + /// width * height * 4 (getSize().x * getSize().y * 4). + /// Warning: the returned pointer may become invalid if you + /// modify the image, so you should never store it for too long. + /// If the image is empty, a null pointer is returned. + /// + /// \return Read-only pointer to the array of pixels + /// + //////////////////////////////////////////////////////////// + const Uint8* getPixelsPtr() const; + + //////////////////////////////////////////////////////////// + /// \brief Flip the image horizontally (left <-> right) + /// + //////////////////////////////////////////////////////////// + void flipHorizontally(); + + //////////////////////////////////////////////////////////// + /// \brief Flip the image vertically (top <-> bottom) + /// + //////////////////////////////////////////////////////////// + void flipVertically(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2u m_size; ///< Image size + std::vector m_pixels; ///< Pixels of the image + #ifdef SFML_SYSTEM_ANDROID + void* m_stream; ///< Asset file streamer (if loaded from file) + #endif +}; + +} // namespace sf + + +#endif // SFML_IMAGE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Image +/// \ingroup graphics +/// +/// sf::Image is an abstraction to manipulate images +/// as bidimensional arrays of pixels. The class provides +/// functions to load, read, write and save pixels, as well +/// as many other useful functions. +/// +/// sf::Image can handle a unique internal representation of +/// pixels, which is RGBA 32 bits. This means that a pixel +/// must be composed of 8 bits red, green, blue and alpha +/// channels -- just like a sf::Color. +/// All the functions that return an array of pixels follow +/// this rule, and all parameters that you pass to sf::Image +/// functions (such as loadFromMemory) must use this +/// representation as well. +/// +/// A sf::Image can be copied, but it is a heavy resource and +/// if possible you should always use [const] references to +/// pass or return them to avoid useless copies. +/// +/// Usage example: +/// \code +/// // Load an image file from a file +/// sf::Image background; +/// if (!background.loadFromFile("background.jpg")) +/// return -1; +/// +/// // Create a 20x20 image filled with black color +/// sf::Image image; +/// image.create(20, 20, sf::Color::Black); +/// +/// // Copy image1 on image2 at position (10, 10) +/// image.copy(background, 10, 10); +/// +/// // Make the top-left pixel transparent +/// sf::Color color = image.getPixel(0, 0); +/// color.a = 0; +/// image.setPixel(0, 0, color); +/// +/// // Save the image to a file +/// if (!image.saveToFile("result.png")) +/// return -1; +/// \endcode +/// +/// \see sf::Texture +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/PrimitiveType.hpp b/include/SFML/Graphics/PrimitiveType.hpp new file mode 100644 index 0000000..931530b --- /dev/null +++ b/include/SFML/Graphics/PrimitiveType.hpp @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_PRIMITIVETYPE_HPP +#define SFML_PRIMITIVETYPE_HPP + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \ingroup graphics +/// \brief Types of primitives that a sf::VertexArray can render +/// +/// Points and lines have no area, therefore their thickness +/// will always be 1 pixel, regardless the current transform +/// and view. +/// +//////////////////////////////////////////////////////////// +enum PrimitiveType +{ + Points, ///< List of individual points + Lines, ///< List of individual lines + LineStrip, ///< List of connected lines, a point uses the previous point to form a line + Triangles, ///< List of individual triangles + TriangleStrip, ///< List of connected triangles, a point uses the two previous points to form a triangle + TriangleFan, ///< List of connected triangles, a point uses the common center and the previous point to form a triangle + Quads, ///< List of individual quads (deprecated, don't work with OpenGL ES) + + // Deprecated names + LinesStrip = LineStrip, ///< \deprecated Use LineStrip instead + TrianglesStrip = TriangleStrip, ///< \deprecated Use TriangleStrip instead + TrianglesFan = TriangleFan ///< \deprecated Use TriangleFan instead +}; + +} // namespace sf + + +#endif // SFML_PRIMITIVETYPE_HPP diff --git a/include/SFML/Graphics/Rect.hpp b/include/SFML/Graphics/Rect.hpp new file mode 100644 index 0000000..782b799 --- /dev/null +++ b/include/SFML/Graphics/Rect.hpp @@ -0,0 +1,254 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RECT_HPP +#define SFML_RECT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility class for manipulating 2D axis aligned rectangles +/// +//////////////////////////////////////////////////////////// +template +class Rect +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty rectangle (it is equivalent to calling + /// Rect(0, 0, 0, 0)). + /// + //////////////////////////////////////////////////////////// + Rect(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the rectangle from its coordinates + /// + /// Be careful, the last two parameters are the width + /// and height, not the right and bottom coordinates! + /// + /// \param rectLeft Left coordinate of the rectangle + /// \param rectTop Top coordinate of the rectangle + /// \param rectWidth Width of the rectangle + /// \param rectHeight Height of the rectangle + /// + //////////////////////////////////////////////////////////// + Rect(T rectLeft, T rectTop, T rectWidth, T rectHeight); + + //////////////////////////////////////////////////////////// + /// \brief Construct the rectangle from position and size + /// + /// Be careful, the last parameter is the size, + /// not the bottom-right corner! + /// + /// \param position Position of the top-left corner of the rectangle + /// \param size Size of the rectangle + /// + //////////////////////////////////////////////////////////// + Rect(const Vector2& position, const Vector2& size); + + //////////////////////////////////////////////////////////// + /// \brief Construct the rectangle from another type of rectangle + /// + /// This constructor doesn't replace the copy constructor, + /// it's called only when U != T. + /// A call to this constructor will fail to compile if U + /// is not convertible to T. + /// + /// \param rectangle Rectangle to convert + /// + //////////////////////////////////////////////////////////// + template + explicit Rect(const Rect& rectangle); + + //////////////////////////////////////////////////////////// + /// \brief Check if a point is inside the rectangle's area + /// + /// This check is non-inclusive. If the point lies on the + /// edge of the rectangle, this function will return false. + /// + /// \param x X coordinate of the point to test + /// \param y Y coordinate of the point to test + /// + /// \return True if the point is inside, false otherwise + /// + /// \see intersects + /// + //////////////////////////////////////////////////////////// + bool contains(T x, T y) const; + + //////////////////////////////////////////////////////////// + /// \brief Check if a point is inside the rectangle's area + /// + /// This check is non-inclusive. If the point lies on the + /// edge of the rectangle, this function will return false. + /// + /// \param point Point to test + /// + /// \return True if the point is inside, false otherwise + /// + /// \see intersects + /// + //////////////////////////////////////////////////////////// + bool contains(const Vector2& point) const; + + //////////////////////////////////////////////////////////// + /// \brief Check the intersection between two rectangles + /// + /// \param rectangle Rectangle to test + /// + /// \return True if rectangles overlap, false otherwise + /// + /// \see contains + /// + //////////////////////////////////////////////////////////// + bool intersects(const Rect& rectangle) const; + + //////////////////////////////////////////////////////////// + /// \brief Check the intersection between two rectangles + /// + /// This overload returns the overlapped rectangle in the + /// \a intersection parameter. + /// + /// \param rectangle Rectangle to test + /// \param intersection Rectangle to be filled with the intersection + /// + /// \return True if rectangles overlap, false otherwise + /// + /// \see contains + /// + //////////////////////////////////////////////////////////// + bool intersects(const Rect& rectangle, Rect& intersection) const; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + T left; ///< Left coordinate of the rectangle + T top; ///< Top coordinate of the rectangle + T width; ///< Width of the rectangle + T height; ///< Height of the rectangle +}; + +//////////////////////////////////////////////////////////// +/// \relates Rect +/// \brief Overload of binary operator == +/// +/// This operator compares strict equality between two rectangles. +/// +/// \param left Left operand (a rectangle) +/// \param right Right operand (a rectangle) +/// +/// \return True if \a left is equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator ==(const Rect& left, const Rect& right); + +//////////////////////////////////////////////////////////// +/// \relates Rect +/// \brief Overload of binary operator != +/// +/// This operator compares strict difference between two rectangles. +/// +/// \param left Left operand (a rectangle) +/// \param right Right operand (a rectangle) +/// +/// \return True if \a left is not equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator !=(const Rect& left, const Rect& right); + +#include + +// Create typedefs for the most common types +typedef Rect IntRect; +typedef Rect FloatRect; + +} // namespace sf + + +#endif // SFML_RECT_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Rect +/// \ingroup graphics +/// +/// A rectangle is defined by its top-left corner and its size. +/// It is a very simple class defined for convenience, so +/// its member variables (left, top, width and height) are public +/// and can be accessed directly, just like the vector classes +/// (Vector2 and Vector3). +/// +/// To keep things simple, sf::Rect doesn't define +/// functions to emulate the properties that are not directly +/// members (such as right, bottom, center, etc.), it rather +/// only provides intersection functions. +/// +/// sf::Rect uses the usual rules for its boundaries: +/// \li The left and top edges are included in the rectangle's area +/// \li The right (left + width) and bottom (top + height) edges are excluded from the rectangle's area +/// +/// This means that sf::IntRect(0, 0, 1, 1) and sf::IntRect(1, 1, 1, 1) +/// don't intersect. +/// +/// sf::Rect is a template and may be used with any numeric type, but +/// for simplicity the instantiations used by SFML are typedef'd: +/// \li sf::Rect is sf::IntRect +/// \li sf::Rect is sf::FloatRect +/// +/// So that you don't have to care about the template syntax. +/// +/// Usage example: +/// \code +/// // Define a rectangle, located at (0, 0) with a size of 20x5 +/// sf::IntRect r1(0, 0, 20, 5); +/// +/// // Define another rectangle, located at (4, 2) with a size of 18x10 +/// sf::Vector2i position(4, 2); +/// sf::Vector2i size(18, 10); +/// sf::IntRect r2(position, size); +/// +/// // Test intersections with the point (3, 1) +/// bool b1 = r1.contains(3, 1); // true +/// bool b2 = r2.contains(3, 1); // false +/// +/// // Test the intersection between r1 and r2 +/// sf::IntRect result; +/// bool b3 = r1.intersects(r2, result); // true +/// // result == (4, 2, 16, 3) +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Rect.inl b/include/SFML/Graphics/Rect.inl new file mode 100644 index 0000000..036fb47 --- /dev/null +++ b/include/SFML/Graphics/Rect.inl @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +template +Rect::Rect() : +left (0), +top (0), +width (0), +height(0) +{ + +} + + +//////////////////////////////////////////////////////////// +template +Rect::Rect(T rectLeft, T rectTop, T rectWidth, T rectHeight) : +left (rectLeft), +top (rectTop), +width (rectWidth), +height(rectHeight) +{ + +} + + +//////////////////////////////////////////////////////////// +template +Rect::Rect(const Vector2& position, const Vector2& size) : +left (position.x), +top (position.y), +width (size.x), +height(size.y) +{ + +} + + +//////////////////////////////////////////////////////////// +template +template +Rect::Rect(const Rect& rectangle) : +left (static_cast(rectangle.left)), +top (static_cast(rectangle.top)), +width (static_cast(rectangle.width)), +height(static_cast(rectangle.height)) +{ +} + + +//////////////////////////////////////////////////////////// +template +bool Rect::contains(T x, T y) const +{ + // Rectangles with negative dimensions are allowed, so we must handle them correctly + + // Compute the real min and max of the rectangle on both axes + T minX = std::min(left, static_cast(left + width)); + T maxX = std::max(left, static_cast(left + width)); + T minY = std::min(top, static_cast(top + height)); + T maxY = std::max(top, static_cast(top + height)); + + return (x >= minX) && (x < maxX) && (y >= minY) && (y < maxY); +} + + +//////////////////////////////////////////////////////////// +template +bool Rect::contains(const Vector2& point) const +{ + return contains(point.x, point.y); +} + + +//////////////////////////////////////////////////////////// +template +bool Rect::intersects(const Rect& rectangle) const +{ + Rect intersection; + return intersects(rectangle, intersection); +} + + +//////////////////////////////////////////////////////////// +template +bool Rect::intersects(const Rect& rectangle, Rect& intersection) const +{ + // Rectangles with negative dimensions are allowed, so we must handle them correctly + + // Compute the min and max of the first rectangle on both axes + T r1MinX = std::min(left, static_cast(left + width)); + T r1MaxX = std::max(left, static_cast(left + width)); + T r1MinY = std::min(top, static_cast(top + height)); + T r1MaxY = std::max(top, static_cast(top + height)); + + // Compute the min and max of the second rectangle on both axes + T r2MinX = std::min(rectangle.left, static_cast(rectangle.left + rectangle.width)); + T r2MaxX = std::max(rectangle.left, static_cast(rectangle.left + rectangle.width)); + T r2MinY = std::min(rectangle.top, static_cast(rectangle.top + rectangle.height)); + T r2MaxY = std::max(rectangle.top, static_cast(rectangle.top + rectangle.height)); + + // Compute the intersection boundaries + T interLeft = std::max(r1MinX, r2MinX); + T interTop = std::max(r1MinY, r2MinY); + T interRight = std::min(r1MaxX, r2MaxX); + T interBottom = std::min(r1MaxY, r2MaxY); + + // If the intersection is valid (positive non zero area), then there is an intersection + if ((interLeft < interRight) && (interTop < interBottom)) + { + intersection = Rect(interLeft, interTop, interRight - interLeft, interBottom - interTop); + return true; + } + else + { + intersection = Rect(0, 0, 0, 0); + return false; + } +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator ==(const Rect& left, const Rect& right) +{ + return (left.left == right.left) && (left.width == right.width) && + (left.top == right.top) && (left.height == right.height); +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator !=(const Rect& left, const Rect& right) +{ + return !(left == right); +} diff --git a/include/SFML/Graphics/RectangleShape.hpp b/include/SFML/Graphics/RectangleShape.hpp new file mode 100644 index 0000000..35dcc67 --- /dev/null +++ b/include/SFML/Graphics/RectangleShape.hpp @@ -0,0 +1,132 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RECTANGLESHAPE_HPP +#define SFML_RECTANGLESHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a rectangle +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API RectangleShape : public Shape +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param size Size of the rectangle + /// + //////////////////////////////////////////////////////////// + explicit RectangleShape(const Vector2f& size = Vector2f(0, 0)); + + //////////////////////////////////////////////////////////// + /// \brief Set the size of the rectangle + /// + /// \param size New size of the rectangle + /// + /// \see getSize + /// + //////////////////////////////////////////////////////////// + void setSize(const Vector2f& size); + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the rectangle + /// + /// \return Size of the rectangle + /// + /// \see setSize + /// + //////////////////////////////////////////////////////////// + const Vector2f& getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape. For rectangle + /// shapes, this number is always 4. + /// + //////////////////////////////////////////////////////////// + virtual std::size_t getPointCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a point of the rectangle + /// + /// The returned point is in local coordinates, that is, + /// the shape's transforms (position, rotation, scale) are + /// not taken into account. + /// The result is undefined if \a index is out of the valid range. + /// + /// \param index Index of the point to get, in range [0 .. 3] + /// + /// \return index-th point of the shape + /// + //////////////////////////////////////////////////////////// + virtual Vector2f getPoint(std::size_t index) const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f m_size; ///< Size of the rectangle +}; + +} // namespace sf + + +#endif // SFML_RECTANGLESHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RectangleShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// Usage example: +/// \code +/// sf::RectangleShape rectangle; +/// rectangle.setSize(sf::Vector2f(100, 50)); +/// rectangle.setOutlineColor(sf::Color::Red); +/// rectangle.setOutlineThickness(5); +/// rectangle.setPosition(10, 20); +/// ... +/// window.draw(rectangle); +/// \endcode +/// +/// \see sf::Shape, sf::CircleShape, sf::ConvexShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderStates.hpp b/include/SFML/Graphics/RenderStates.hpp new file mode 100644 index 0000000..94f1197 --- /dev/null +++ b/include/SFML/Graphics/RenderStates.hpp @@ -0,0 +1,174 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RENDERSTATES_HPP +#define SFML_RENDERSTATES_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class Shader; +class Texture; + +//////////////////////////////////////////////////////////// +/// \brief Define the states used for drawing to a RenderTarget +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API RenderStates +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructing a default set of render states is equivalent + /// to using sf::RenderStates::Default. + /// The default set defines: + /// \li the BlendAlpha blend mode + /// \li the identity transform + /// \li a null texture + /// \li a null shader + /// + //////////////////////////////////////////////////////////// + RenderStates(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom blend mode + /// + /// \param theBlendMode Blend mode to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const BlendMode& theBlendMode); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom transform + /// + /// \param theTransform Transform to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const Transform& theTransform); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom texture + /// + /// \param theTexture Texture to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const Texture* theTexture); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom shader + /// + /// \param theShader Shader to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const Shader* theShader); + + //////////////////////////////////////////////////////////// + /// \brief Construct a set of render states with all its attributes + /// + /// \param theBlendMode Blend mode to use + /// \param theTransform Transform to use + /// \param theTexture Texture to use + /// \param theShader Shader to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const BlendMode& theBlendMode, const Transform& theTransform, + const Texture* theTexture, const Shader* theShader); + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const RenderStates Default; ///< Special instance holding the default render states + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + BlendMode blendMode; ///< Blending mode + Transform transform; ///< Transform + const Texture* texture; ///< Texture + const Shader* shader; ///< Shader +}; + +} // namespace sf + + +#endif // SFML_RENDERSTATES_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RenderStates +/// \ingroup graphics +/// +/// There are four global states that can be applied to +/// the drawn objects: +/// \li the blend mode: how pixels of the object are blended with the background +/// \li the transform: how the object is positioned/rotated/scaled +/// \li the texture: what image is mapped to the object +/// \li the shader: what custom effect is applied to the object +/// +/// High-level objects such as sprites or text force some of +/// these states when they are drawn. For example, a sprite +/// will set its own texture, so that you don't have to care +/// about it when drawing the sprite. +/// +/// The transform is a special case: sprites, texts and shapes +/// (and it's a good idea to do it with your own drawable classes +/// too) combine their transform with the one that is passed in the +/// RenderStates structure. So that you can use a "global" transform +/// on top of each object's transform. +/// +/// Most objects, especially high-level drawables, can be drawn +/// directly without defining render states explicitly -- the +/// default set of states is ok in most cases. +/// \code +/// window.draw(sprite); +/// \endcode +/// +/// If you want to use a single specific render state, +/// for example a shader, you can pass it directly to the Draw +/// function: sf::RenderStates has an implicit one-argument +/// constructor for each state. +/// \code +/// window.draw(sprite, shader); +/// \endcode +/// +/// When you're inside the Draw function of a drawable +/// object (inherited from sf::Drawable), you can +/// either pass the render states unmodified, or change +/// some of them. +/// For example, a transformable object will combine the +/// current transform with its own transform. A sprite will +/// set its texture. Etc. +/// +/// \see sf::RenderTarget, sf::Drawable +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderTarget.hpp b/include/SFML/Graphics/RenderTarget.hpp new file mode 100644 index 0000000..adfa9ad --- /dev/null +++ b/include/SFML/Graphics/RenderTarget.hpp @@ -0,0 +1,451 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RENDERTARGET_HPP +#define SFML_RENDERTARGET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class Drawable; + +//////////////////////////////////////////////////////////// +/// \brief Base class for all render targets (window, texture, ...) +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API RenderTarget : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~RenderTarget(); + + //////////////////////////////////////////////////////////// + /// \brief Clear the entire target with a single color + /// + /// This function is usually called once every frame, + /// to clear the previous contents of the target. + /// + /// \param color Fill color to use to clear the render target + /// + //////////////////////////////////////////////////////////// + void clear(const Color& color = Color(0, 0, 0, 255)); + + //////////////////////////////////////////////////////////// + /// \brief Change the current active view + /// + /// The view is like a 2D camera, it controls which part of + /// the 2D scene is visible, and how it is viewed in the + /// render target. + /// The new view will affect everything that is drawn, until + /// another view is set. + /// The render target keeps its own copy of the view object, + /// so it is not necessary to keep the original one alive + /// after calling this function. + /// To restore the original view of the target, you can pass + /// the result of getDefaultView() to this function. + /// + /// \param view New view to use + /// + /// \see getView, getDefaultView + /// + //////////////////////////////////////////////////////////// + void setView(const View& view); + + //////////////////////////////////////////////////////////// + /// \brief Get the view currently in use in the render target + /// + /// \return The view object that is currently used + /// + /// \see setView, getDefaultView + /// + //////////////////////////////////////////////////////////// + const View& getView() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the default view of the render target + /// + /// The default view has the initial size of the render target, + /// and never changes after the target has been created. + /// + /// \return The default view of the render target + /// + /// \see setView, getView + /// + //////////////////////////////////////////////////////////// + const View& getDefaultView() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the viewport of a view, applied to this render target + /// + /// The viewport is defined in the view as a ratio, this function + /// simply applies this ratio to the current dimensions of the + /// render target to calculate the pixels rectangle that the viewport + /// actually covers in the target. + /// + /// \param view The view for which we want to compute the viewport + /// + /// \return Viewport rectangle, expressed in pixels + /// + //////////////////////////////////////////////////////////// + IntRect getViewport(const View& view) const; + + //////////////////////////////////////////////////////////// + /// \brief Convert a point from target coordinates to world + /// coordinates, using the current view + /// + /// This function is an overload of the mapPixelToCoords + /// function that implicitly uses the current view. + /// It is equivalent to: + /// \code + /// target.mapPixelToCoords(point, target.getView()); + /// \endcode + /// + /// \param point Pixel to convert + /// + /// \return The converted point, in "world" coordinates + /// + /// \see mapCoordsToPixel + /// + //////////////////////////////////////////////////////////// + Vector2f mapPixelToCoords(const Vector2i& point) const; + + //////////////////////////////////////////////////////////// + /// \brief Convert a point from target coordinates to world coordinates + /// + /// This function finds the 2D position that matches the + /// given pixel of the render target. In other words, it does + /// the inverse of what the graphics card does, to find the + /// initial position of a rendered pixel. + /// + /// Initially, both coordinate systems (world units and target pixels) + /// match perfectly. But if you define a custom view or resize your + /// render target, this assertion is not true anymore, i.e. a point + /// located at (10, 50) in your render target may map to the point + /// (150, 75) in your 2D world -- if the view is translated by (140, 25). + /// + /// For render-windows, this function is typically used to find + /// which point (or object) is located below the mouse cursor. + /// + /// This version uses a custom view for calculations, see the other + /// overload of the function if you want to use the current view of the + /// render target. + /// + /// \param point Pixel to convert + /// \param view The view to use for converting the point + /// + /// \return The converted point, in "world" units + /// + /// \see mapCoordsToPixel + /// + //////////////////////////////////////////////////////////// + Vector2f mapPixelToCoords(const Vector2i& point, const View& view) const; + + //////////////////////////////////////////////////////////// + /// \brief Convert a point from world coordinates to target + /// coordinates, using the current view + /// + /// This function is an overload of the mapCoordsToPixel + /// function that implicitly uses the current view. + /// It is equivalent to: + /// \code + /// target.mapCoordsToPixel(point, target.getView()); + /// \endcode + /// + /// \param point Point to convert + /// + /// \return The converted point, in target coordinates (pixels) + /// + /// \see mapPixelToCoords + /// + //////////////////////////////////////////////////////////// + Vector2i mapCoordsToPixel(const Vector2f& point) const; + + //////////////////////////////////////////////////////////// + /// \brief Convert a point from world coordinates to target coordinates + /// + /// This function finds the pixel of the render target that matches + /// the given 2D point. In other words, it goes through the same process + /// as the graphics card, to compute the final position of a rendered point. + /// + /// Initially, both coordinate systems (world units and target pixels) + /// match perfectly. But if you define a custom view or resize your + /// render target, this assertion is not true anymore, i.e. a point + /// located at (150, 75) in your 2D world may map to the pixel + /// (10, 50) of your render target -- if the view is translated by (140, 25). + /// + /// This version uses a custom view for calculations, see the other + /// overload of the function if you want to use the current view of the + /// render target. + /// + /// \param point Point to convert + /// \param view The view to use for converting the point + /// + /// \return The converted point, in target coordinates (pixels) + /// + /// \see mapPixelToCoords + /// + //////////////////////////////////////////////////////////// + Vector2i mapCoordsToPixel(const Vector2f& point, const View& view) const; + + //////////////////////////////////////////////////////////// + /// \brief Draw a drawable object to the render target + /// + /// \param drawable Object to draw + /// \param states Render states to use for drawing + /// + //////////////////////////////////////////////////////////// + void draw(const Drawable& drawable, const RenderStates& states = RenderStates::Default); + + //////////////////////////////////////////////////////////// + /// \brief Draw primitives defined by an array of vertices + /// + /// \param vertices Pointer to the vertices + /// \param vertexCount Number of vertices in the array + /// \param type Type of primitives to draw + /// \param states Render states to use for drawing + /// + //////////////////////////////////////////////////////////// + void draw(const Vertex* vertices, std::size_t vertexCount, + PrimitiveType type, const RenderStates& states = RenderStates::Default); + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the rendering region of the target + /// + /// \return Size in pixels + /// + //////////////////////////////////////////////////////////// + virtual Vector2u getSize() const = 0; + + //////////////////////////////////////////////////////////// + /// \brief Save the current OpenGL render states and matrices + /// + /// This function can be used when you mix SFML drawing + /// and direct OpenGL rendering. Combined with popGLStates, + /// it ensures that: + /// \li SFML's internal states are not messed up by your OpenGL code + /// \li your OpenGL states are not modified by a call to a SFML function + /// + /// More specifically, it must be used around code that + /// calls Draw functions. Example: + /// \code + /// // OpenGL code here... + /// window.pushGLStates(); + /// window.draw(...); + /// window.draw(...); + /// window.popGLStates(); + /// // OpenGL code here... + /// \endcode + /// + /// Note that this function is quite expensive: it saves all the + /// possible OpenGL states and matrices, even the ones you + /// don't care about. Therefore it should be used wisely. + /// It is provided for convenience, but the best results will + /// be achieved if you handle OpenGL states yourself (because + /// you know which states have really changed, and need to be + /// saved and restored). Take a look at the resetGLStates + /// function if you do so. + /// + /// \see popGLStates + /// + //////////////////////////////////////////////////////////// + void pushGLStates(); + + //////////////////////////////////////////////////////////// + /// \brief Restore the previously saved OpenGL render states and matrices + /// + /// See the description of pushGLStates to get a detailed + /// description of these functions. + /// + /// \see pushGLStates + /// + //////////////////////////////////////////////////////////// + void popGLStates(); + + //////////////////////////////////////////////////////////// + /// \brief Reset the internal OpenGL states so that the target is ready for drawing + /// + /// This function can be used when you mix SFML drawing + /// and direct OpenGL rendering, if you choose not to use + /// pushGLStates/popGLStates. It makes sure that all OpenGL + /// states needed by SFML are set, so that subsequent draw() + /// calls will work as expected. + /// + /// Example: + /// \code + /// // OpenGL code here... + /// glPushAttrib(...); + /// window.resetGLStates(); + /// window.draw(...); + /// window.draw(...); + /// glPopAttrib(...); + /// // OpenGL code here... + /// \endcode + /// + //////////////////////////////////////////////////////////// + void resetGLStates(); + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + RenderTarget(); + + //////////////////////////////////////////////////////////// + /// \brief Performs the common initialization step after creation + /// + /// The derived classes must call this function after the + /// target is created and ready for drawing. + /// + //////////////////////////////////////////////////////////// + void initialize(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Apply the current view + /// + //////////////////////////////////////////////////////////// + void applyCurrentView(); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new blending mode + /// + /// \param mode Blending mode to apply + /// + //////////////////////////////////////////////////////////// + void applyBlendMode(const BlendMode& mode); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new transform + /// + /// \param transform Transform to apply + /// + //////////////////////////////////////////////////////////// + void applyTransform(const Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new texture + /// + /// \param texture Texture to apply + /// + //////////////////////////////////////////////////////////// + void applyTexture(const Texture* texture); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new shader + /// + /// \param shader Shader to apply + /// + //////////////////////////////////////////////////////////// + void applyShader(const Shader* shader); + + //////////////////////////////////////////////////////////// + /// \brief Activate the target for rendering + /// + /// This function must be implemented by derived classes to make + /// their OpenGL context current; it is called by the base class + /// everytime it's going to use OpenGL calls. + /// + /// \param active True to make the target active, false to deactivate it + /// + /// \return True if the function succeeded + /// + //////////////////////////////////////////////////////////// + virtual bool activate(bool active) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Render states cache + /// + //////////////////////////////////////////////////////////// + struct StatesCache + { + enum {VertexCacheSize = 4}; + + bool glStatesSet; ///< Are our internal GL states set yet? + bool viewChanged; ///< Has the current view changed since last draw? + BlendMode lastBlendMode; ///< Cached blending mode + Uint64 lastTextureId; ///< Cached texture + bool useVertexCache; ///< Did we previously use the vertex cache? + Vertex vertexCache[VertexCacheSize]; ///< Pre-transformed vertices cache + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + View m_defaultView; ///< Default view + View m_view; ///< Current view + StatesCache m_cache; ///< Render states cache +}; + +} // namespace sf + + +#endif // SFML_RENDERTARGET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RenderTarget +/// \ingroup graphics +/// +/// sf::RenderTarget defines the common behavior of all the +/// 2D render targets usable in the graphics module. It makes +/// it possible to draw 2D entities like sprites, shapes, text +/// without using any OpenGL command directly. +/// +/// A sf::RenderTarget is also able to use views (sf::View), +/// which are a kind of 2D cameras. With views you can globally +/// scroll, rotate or zoom everything that is drawn, +/// without having to transform every single entity. See the +/// documentation of sf::View for more details and sample pieces of +/// code about this class. +/// +/// On top of that, render targets are still able to render direct +/// OpenGL stuff. It is even possible to mix together OpenGL calls +/// and regular SFML drawing commands. When doing so, make sure that +/// OpenGL states are not messed up by calling the +/// pushGLStates/popGLStates functions. +/// +/// \see sf::RenderWindow, sf::RenderTexture, sf::View +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderTexture.hpp b/include/SFML/Graphics/RenderTexture.hpp new file mode 100644 index 0000000..4c6a833 --- /dev/null +++ b/include/SFML/Graphics/RenderTexture.hpp @@ -0,0 +1,296 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RENDERTEXTURE_HPP +#define SFML_RENDERTEXTURE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + class RenderTextureImpl; +} + +//////////////////////////////////////////////////////////// +/// \brief Target for off-screen 2D rendering into a texture +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API RenderTexture : public RenderTarget +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs an empty, invalid render-texture. You must + /// call create to have a valid render-texture. + /// + /// \see create + /// + //////////////////////////////////////////////////////////// + RenderTexture(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~RenderTexture(); + + //////////////////////////////////////////////////////////// + /// \brief Create the render-texture + /// + /// Before calling this function, the render-texture is in + /// an invalid state, thus it is mandatory to call it before + /// doing anything with the render-texture. + /// The last parameter, \a depthBuffer, is useful if you want + /// to use the render-texture for 3D OpenGL rendering that requires + /// a depth buffer. Otherwise it is unnecessary, and you should + /// leave this parameter to false (which is its default value). + /// + /// \param width Width of the render-texture + /// \param height Height of the render-texture + /// \param depthBuffer Do you want this render-texture to have a depth buffer? + /// + /// \return True if creation has been successful + /// + //////////////////////////////////////////////////////////// + bool create(unsigned int width, unsigned int height, bool depthBuffer = false); + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable texture smoothing + /// + /// This function is similar to Texture::setSmooth. + /// This parameter is disabled by default. + /// + /// \param smooth True to enable smoothing, false to disable it + /// + /// \see isSmooth + /// + //////////////////////////////////////////////////////////// + void setSmooth(bool smooth); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the smooth filtering is enabled or not + /// + /// \return True if texture smoothing is enabled + /// + /// \see setSmooth + /// + //////////////////////////////////////////////////////////// + bool isSmooth() const; + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable texture repeating + /// + /// This function is similar to Texture::setRepeated. + /// This parameter is disabled by default. + /// + /// \param repeated True to enable repeating, false to disable it + /// + /// \see isRepeated + /// + //////////////////////////////////////////////////////////// + void setRepeated(bool repeated); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the texture is repeated or not + /// + /// \return True if texture is repeated + /// + /// \see setRepeated + /// + //////////////////////////////////////////////////////////// + bool isRepeated() const; + + //////////////////////////////////////////////////////////// + /// \brief Generate a mipmap using the current texture data + /// + /// This function is similar to Texture::generateMipmap and operates + /// on the texture used as the target for drawing. + /// Be aware that any draw operation may modify the base level image data. + /// For this reason, calling this function only makes sense after all + /// drawing is completed and display has been called. Not calling display + /// after subsequent drawing will lead to undefined behavior if a mipmap + /// had been previously generated. + /// + /// \return True if mipmap generation was successful, false if unsuccessful + /// + //////////////////////////////////////////////////////////// + bool generateMipmap(); + + //////////////////////////////////////////////////////////// + /// \brief Activate or deactivate the render-texture for rendering + /// + /// This function makes the render-texture's context current for + /// future OpenGL rendering operations (so you shouldn't care + /// about it if you're not doing direct OpenGL stuff). + /// Only one context can be current in a thread, so if you + /// want to draw OpenGL geometry to another render target + /// (like a RenderWindow) don't forget to activate it again. + /// + /// \param active True to activate, false to deactivate + /// + /// \return True if operation was successful, false otherwise + /// + //////////////////////////////////////////////////////////// + bool setActive(bool active = true); + + //////////////////////////////////////////////////////////// + /// \brief Update the contents of the target texture + /// + /// This function updates the target texture with what + /// has been drawn so far. Like for windows, calling this + /// function is mandatory at the end of rendering. Not calling + /// it may leave the texture in an undefined state. + /// + //////////////////////////////////////////////////////////// + void display(); + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the rendering region of the texture + /// + /// The returned value is the size that you passed to + /// the create function. + /// + /// \return Size in pixels + /// + //////////////////////////////////////////////////////////// + virtual Vector2u getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a read-only reference to the target texture + /// + /// After drawing to the render-texture and calling Display, + /// you can retrieve the updated texture using this function, + /// and draw it using a sprite (for example). + /// The internal sf::Texture of a render-texture is always the + /// same instance, so that it is possible to call this function + /// once and keep a reference to the texture even after it is + /// modified. + /// + /// \return Const reference to the texture + /// + //////////////////////////////////////////////////////////// + const Texture& getTexture() const; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Activate the target for rendering + /// + /// This function is called by the base class + /// everytime it's going to use OpenGL calls. + /// + /// \param active True to make the target active, false to deactivate it + /// + /// \return True if the function succeeded + /// + //////////////////////////////////////////////////////////// + virtual bool activate(bool active); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::RenderTextureImpl* m_impl; ///< Platform/hardware specific implementation + Texture m_texture; ///< Target texture to draw on +}; + +} // namespace sf + + +#endif // SFML_RENDERTEXTURE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RenderTexture +/// \ingroup graphics +/// +/// sf::RenderTexture is the little brother of sf::RenderWindow. +/// It implements the same 2D drawing and OpenGL-related functions +/// (see their base class sf::RenderTarget for more details), +/// the difference is that the result is stored in an off-screen +/// texture rather than being show in a window. +/// +/// Rendering to a texture can be useful in a variety of situations: +/// \li precomputing a complex static texture (like a level's background from multiple tiles) +/// \li applying post-effects to the whole scene with shaders +/// \li creating a sprite from a 3D object rendered with OpenGL +/// \li etc. +/// +/// Usage example: +/// +/// \code +/// // Create a new render-window +/// sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); +/// +/// // Create a new render-texture +/// sf::RenderTexture texture; +/// if (!texture.create(500, 500)) +/// return -1; +/// +/// // The main loop +/// while (window.isOpen()) +/// { +/// // Event processing +/// // ... +/// +/// // Clear the whole texture with red color +/// texture.clear(sf::Color::Red); +/// +/// // Draw stuff to the texture +/// texture.draw(sprite); // sprite is a sf::Sprite +/// texture.draw(shape); // shape is a sf::Shape +/// texture.draw(text); // text is a sf::Text +/// +/// // We're done drawing to the texture +/// texture.display(); +/// +/// // Now we start rendering to the window, clear it first +/// window.clear(); +/// +/// // Draw the texture +/// sf::Sprite sprite(texture.getTexture()); +/// window.draw(sprite); +/// +/// // End the current frame and display its contents on screen +/// window.display(); +/// } +/// \endcode +/// +/// Like sf::RenderWindow, sf::RenderTexture is still able to render direct +/// OpenGL stuff. It is even possible to mix together OpenGL calls +/// and regular SFML drawing commands. If you need a depth buffer for +/// 3D rendering, don't forget to request it when calling RenderTexture::create. +/// +/// \see sf::RenderTarget, sf::RenderWindow, sf::View, sf::Texture +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderWindow.hpp b/include/SFML/Graphics/RenderWindow.hpp new file mode 100644 index 0000000..fc55af4 --- /dev/null +++ b/include/SFML/Graphics/RenderWindow.hpp @@ -0,0 +1,278 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RENDERWINDOW_HPP +#define SFML_RENDERWINDOW_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Window that can serve as a target for 2D drawing +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API RenderWindow : public Window, public RenderTarget +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor doesn't actually create the window, + /// use the other constructors or call create() to do so. + /// + //////////////////////////////////////////////////////////// + RenderWindow(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a new window + /// + /// This constructor creates the window with the size and pixel + /// depth defined in \a mode. An optional style can be passed to + /// customize the look and behavior of the window (borders, + /// title bar, resizable, closable, ...). + /// + /// The fourth parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. You shouldn't care about these + /// parameters for a regular usage of the graphics module. + /// + /// \param mode Video mode to use (defines the width, height and depth of the rendering area of the window) + /// \param title Title of the window + /// \param style %Window style, a bitwise OR combination of sf::Style enumerators + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + RenderWindow(VideoMode mode, const String& title, Uint32 style = Style::Default, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Construct the window from an existing control + /// + /// Use this constructor if you want to create an SFML + /// rendering area into an already existing control. + /// + /// The second parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. You shouldn't care about these + /// parameters for a regular usage of the graphics module. + /// + /// \param handle Platform-specific handle of the control (\a HWND on + /// Windows, \a %Window on Linux/FreeBSD, \a NSWindow on OS X) + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + explicit RenderWindow(WindowHandle handle, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Closes the window and frees all the resources attached to it. + /// + //////////////////////////////////////////////////////////// + virtual ~RenderWindow(); + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the rendering region of the window + /// + /// The size doesn't include the titlebar and borders + /// of the window. + /// + /// \return Size in pixels + /// + //////////////////////////////////////////////////////////// + virtual Vector2u getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Copy the current contents of the window to an image + /// + /// \deprecated + /// Use a sf::Texture and its sf::Texture::update(const Window&) + /// function and copy its contents into an sf::Image instead. + /// \code + /// sf::Vector2u windowSize = window.getSize(); + /// sf::Texture texture; + /// texture.create(windowSize.x, windowSize.y); + /// texture.update(window); + /// sf::Image screenshot = texture.copyToImage(); + /// \endcode + /// + /// This is a slow operation, whose main purpose is to make + /// screenshots of the application. If you want to update an + /// image with the contents of the window and then use it for + /// drawing, you should rather use a sf::Texture and its + /// update(Window&) function. + /// You can also draw things directly to a texture with the + /// sf::RenderTexture class. + /// + /// \return Image containing the captured contents + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED Image capture() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Function called after the window has been created + /// + /// This function is called so that derived classes can + /// perform their own specific initialization as soon as + /// the window is created. + /// + //////////////////////////////////////////////////////////// + virtual void onCreate(); + + //////////////////////////////////////////////////////////// + /// \brief Function called after the window has been resized + /// + /// This function is called so that derived classes can + /// perform custom actions when the size of the window changes. + /// + //////////////////////////////////////////////////////////// + virtual void onResize(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Activate the target for rendering + /// + /// \param active True to make the target active, false to deactivate it + /// + /// \return True if the function succeeded + /// + //////////////////////////////////////////////////////////// + virtual bool activate(bool active); +}; + +} // namespace sf + + +#endif // SFML_RENDERWINDOW_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RenderWindow +/// \ingroup graphics +/// +/// sf::RenderWindow is the main class of the Graphics module. +/// It defines an OS window that can be painted using the other +/// classes of the graphics module. +/// +/// sf::RenderWindow is derived from sf::Window, thus it inherits +/// all its features: events, window management, OpenGL rendering, +/// etc. See the documentation of sf::Window for a more complete +/// description of all these features, as well as code examples. +/// +/// On top of that, sf::RenderWindow adds more features related to +/// 2D drawing with the graphics module (see its base class +/// sf::RenderTarget for more details). +/// Here is a typical rendering and event loop with a sf::RenderWindow: +/// +/// \code +/// // Declare and create a new render-window +/// sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); +/// +/// // Limit the framerate to 60 frames per second (this step is optional) +/// window.setFramerateLimit(60); +/// +/// // The main loop - ends as soon as the window is closed +/// while (window.isOpen()) +/// { +/// // Event processing +/// sf::Event event; +/// while (window.pollEvent(event)) +/// { +/// // Request for closing the window +/// if (event.type == sf::Event::Closed) +/// window.close(); +/// } +/// +/// // Clear the whole window before rendering a new frame +/// window.clear(); +/// +/// // Draw some graphical entities +/// window.draw(sprite); +/// window.draw(circle); +/// window.draw(text); +/// +/// // End the current frame and display its contents on screen +/// window.display(); +/// } +/// \endcode +/// +/// Like sf::Window, sf::RenderWindow is still able to render direct +/// OpenGL stuff. It is even possible to mix together OpenGL calls +/// and regular SFML drawing commands. +/// +/// \code +/// // Create the render window +/// sf::RenderWindow window(sf::VideoMode(800, 600), "SFML OpenGL"); +/// +/// // Create a sprite and a text to display +/// sf::Sprite sprite; +/// sf::Text text; +/// ... +/// +/// // Perform OpenGL initializations +/// glMatrixMode(GL_PROJECTION); +/// ... +/// +/// // Start the rendering loop +/// while (window.isOpen()) +/// { +/// // Process events +/// ... +/// +/// // Draw a background sprite +/// window.pushGLStates(); +/// window.draw(sprite); +/// window.popGLStates(); +/// +/// // Draw a 3D object using OpenGL +/// glBegin(GL_QUADS); +/// glVertex3f(...); +/// ... +/// glEnd(); +/// +/// // Draw text on top of the 3D object +/// window.pushGLStates(); +/// window.draw(text); +/// window.popGLStates(); +/// +/// // Finally, display the rendered frame on screen +/// window.display(); +/// } +/// \endcode +/// +/// \see sf::Window, sf::RenderTarget, sf::RenderTexture, sf::View +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp new file mode 100644 index 0000000..9597fcb --- /dev/null +++ b/include/SFML/Graphics/Shader.hpp @@ -0,0 +1,875 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SHADER_HPP +#define SFML_SHADER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class Color; +class InputStream; +class Texture; +class Transform; + +//////////////////////////////////////////////////////////// +/// \brief Shader class (vertex, geometry and fragment) +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Shader : GlResource, NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Types of shaders + /// + //////////////////////////////////////////////////////////// + enum Type + { + Vertex, ///< %Vertex shader + Geometry, ///< Geometry shader + Fragment ///< Fragment (pixel) shader + }; + + //////////////////////////////////////////////////////////// + /// \brief Special type that can be passed to setUniform(), + /// and that represents the texture of the object being drawn + /// + /// \see setUniform(const std::string&, CurrentTextureType) + /// + //////////////////////////////////////////////////////////// + struct CurrentTextureType {}; + + //////////////////////////////////////////////////////////// + /// \brief Represents the texture of the object being drawn + /// + /// \see setUniform(const std::string&, CurrentTextureType) + /// + //////////////////////////////////////////////////////////// + static CurrentTextureType CurrentTexture; + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor creates an invalid shader. + /// + //////////////////////////////////////////////////////////// + Shader(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Shader(); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry or fragment shader from a file + /// + /// This function loads a single shader, vertex, geometry or + /// fragment, identified by the second argument. + /// The source must be a text file containing a valid + /// shader in GLSL language. GLSL is a C-like language + /// dedicated to OpenGL shaders; you'll probably need to + /// read a good documentation for it before writing your + /// own shaders. + /// + /// \param filename Path of the vertex, geometry or fragment shader file to load + /// \param type Type of shader (vertex, geometry or fragment) + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename, Type type); + + //////////////////////////////////////////////////////////// + /// \brief Load both the vertex and fragment shaders from files + /// + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be text files containing valid shaders + /// in GLSL language. GLSL is a C-like language dedicated to + /// OpenGL shaders; you'll probably need to read a good documentation + /// for it before writing your own shaders. + /// + /// \param vertexShaderFilename Path of the vertex shader file to load + /// \param fragmentShaderFilename Path of the fragment shader file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry and fragment shaders from files + /// + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be text files containing valid shaders + /// in GLSL language. GLSL is a C-like language dedicated to + /// OpenGL shaders; you'll probably need to read a good documentation + /// for it before writing your own shaders. + /// + /// \param vertexShaderFilename Path of the vertex shader file to load + /// \param geometryShaderFilename Path of the geometry shader file to load + /// \param fragmentShaderFilename Path of the fragment shader file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry or fragment shader from a source code in memory + /// + /// This function loads a single shader, vertex, geometry + /// or fragment, identified by the second argument. + /// The source code must be a valid shader in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. + /// + /// \param shader String containing the source code of the shader + /// \param type Type of shader (vertex, geometry or fragment) + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const std::string& shader, Type type); + + //////////////////////////////////////////////////////////// + /// \brief Load both the vertex and fragment shaders from source codes in memory + /// + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be valid shaders in GLSL language. GLSL is + /// a C-like language dedicated to OpenGL shaders; you'll + /// probably need to read a good documentation for it before + /// writing your own shaders. + /// + /// \param vertexShader String containing the source code of the vertex shader + /// \param fragmentShader String containing the source code of the fragment shader + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry and fragment shaders from source codes in memory + /// + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be valid shaders in GLSL language. GLSL is + /// a C-like language dedicated to OpenGL shaders; you'll + /// probably need to read a good documentation for it before + /// writing your own shaders. + /// + /// \param vertexShader String containing the source code of the vertex shader + /// \param geometryShader String containing the source code of the geometry shader + /// \param fragmentShader String containing the source code of the fragment shader + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry or fragment shader from a custom stream + /// + /// This function loads a single shader, vertex, geometry + /// or fragment, identified by the second argument. + /// The source code must be a valid shader in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for it + /// before writing your own shaders. + /// + /// \param stream Source stream to read from + /// \param type Type of shader (vertex, geometry or fragment) + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream, Type type); + + //////////////////////////////////////////////////////////// + /// \brief Load both the vertex and fragment shaders from custom streams + /// + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The source codes must be valid shaders in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. + /// + /// \param vertexShaderStream Source stream to read the vertex shader from + /// \param fragmentShaderStream Source stream to read the fragment shader from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry and fragment shaders from custom streams + /// + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The source codes must be valid shaders in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. + /// + /// \param vertexShaderStream Source stream to read the vertex shader from + /// \param geometryShaderStream Source stream to read the geometry shader from + /// \param fragmentShaderStream Source stream to read the fragment shader from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p float uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param x Value of the float scalar + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, float x); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p vec2 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the vec2 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Vec2& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p vec3 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the vec3 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Vec3& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p vec4 uniform + /// + /// This overload can also be called with sf::Color objects + /// that are converted to sf::Glsl::Vec4. + /// + /// It is important to note that the components of the color are + /// normalized before being passed to the shader. Therefore, + /// they are converted from range [0 .. 255] to range [0 .. 1]. + /// For example, a sf::Color(255, 127, 0, 255) will be transformed + /// to a vec4(1.0, 0.5, 0.0, 1.0) in the shader. + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the vec4 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Vec4& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p int uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param x Value of the int scalar + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, int x); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p ivec2 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the ivec2 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Ivec2& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p ivec3 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the ivec3 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Ivec3& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p ivec4 uniform + /// + /// This overload can also be called with sf::Color objects + /// that are converted to sf::Glsl::Ivec4. + /// + /// If color conversions are used, the ivec4 uniform in GLSL + /// will hold the same values as the original sf::Color + /// instance. For example, sf::Color(255, 127, 0, 255) is + /// mapped to ivec4(255, 127, 0, 255). + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the ivec4 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Ivec4& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p bool uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param x Value of the bool scalar + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, bool x); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p bvec2 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the bvec2 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Bvec2& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p bvec3 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the bvec3 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Bvec3& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p bvec4 uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vector Value of the bvec4 vector + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Bvec4& vector); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p mat3 matrix + /// + /// \param name Name of the uniform variable in GLSL + /// \param matrix Value of the mat3 matrix + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Mat3& matrix); + + //////////////////////////////////////////////////////////// + /// \brief Specify value for \p mat4 matrix + /// + /// \param name Name of the uniform variable in GLSL + /// \param matrix Value of the mat4 matrix + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Glsl::Mat4& matrix); + + //////////////////////////////////////////////////////////// + /// \brief Specify a texture as \p sampler2D uniform + /// + /// \a name is the name of the variable to change in the shader. + /// The corresponding parameter in the shader must be a 2D texture + /// (\p sampler2D GLSL type). + /// + /// Example: + /// \code + /// uniform sampler2D the_texture; // this is the variable in the shader + /// \endcode + /// \code + /// sf::Texture texture; + /// ... + /// shader.setUniform("the_texture", texture); + /// \endcode + /// It is important to note that \a texture must remain alive as long + /// as the shader uses it, no copy is made internally. + /// + /// To use the texture of the object being drawn, which cannot be + /// known in advance, you can pass the special value + /// sf::Shader::CurrentTexture: + /// \code + /// shader.setUniform("the_texture", sf::Shader::CurrentTexture). + /// \endcode + /// + /// \param name Name of the texture in the shader + /// \param texture Texture to assign + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, const Texture& texture); + + //////////////////////////////////////////////////////////// + /// \brief Specify current texture as \p sampler2D uniform + /// + /// This overload maps a shader texture variable to the + /// texture of the object being drawn, which cannot be + /// known in advance. The second argument must be + /// sf::Shader::CurrentTexture. + /// The corresponding parameter in the shader must be a 2D texture + /// (\p sampler2D GLSL type). + /// + /// Example: + /// \code + /// uniform sampler2D current; // this is the variable in the shader + /// \endcode + /// \code + /// shader.setUniform("current", sf::Shader::CurrentTexture); + /// \endcode + /// + /// \param name Name of the texture in the shader + /// + //////////////////////////////////////////////////////////// + void setUniform(const std::string& name, CurrentTextureType); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p float[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param scalarArray pointer to array of \p float values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const float* scalarArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p vec2[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vectorArray pointer to array of \p vec2 values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p vec3[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vectorArray pointer to array of \p vec3 values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p vec4[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param vectorArray pointer to array of \p vec4 values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p mat3[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param matrixArray pointer to array of \p mat3 values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Specify values for \p mat4[] array uniform + /// + /// \param name Name of the uniform variable in GLSL + /// \param matrixArray pointer to array of \p mat4 values + /// \param length Number of elements in the array + /// + //////////////////////////////////////////////////////////// + void setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length); + + //////////////////////////////////////////////////////////// + /// \brief Change a float parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, float) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, float x); + + //////////////////////////////////////////////////////////// + /// \brief Change a 2-components vector parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec2&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Change a 3-components vector parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec3&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Change a 4-components vector parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec4&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, float x, float y, float z, float w); + + //////////////////////////////////////////////////////////// + /// \brief Change a 2-components vector parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec2&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, const Vector2f& vector); + + //////////////////////////////////////////////////////////// + /// \brief Change a 3-components vector parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec3&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, const Vector3f& vector); + + //////////////////////////////////////////////////////////// + /// \brief Change a color parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Vec4&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Change a matrix parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Glsl::Mat4&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, const Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Change a texture parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, const Texture&) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, const Texture& texture); + + //////////////////////////////////////////////////////////// + /// \brief Change a texture parameter of the shader + /// + /// \deprecated Use setUniform(const std::string&, CurrentTextureType) instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setParameter(const std::string& name, CurrentTextureType); + + //////////////////////////////////////////////////////////// + /// \brief Get the underlying OpenGL handle of the shader. + /// + /// You shouldn't need to use this function, unless you have + /// very specific stuff to implement that SFML doesn't support, + /// or implement a temporary workaround until a bug is fixed. + /// + /// \return OpenGL handle of the shader or 0 if not yet loaded + /// + //////////////////////////////////////////////////////////// + unsigned int getNativeHandle() const; + + //////////////////////////////////////////////////////////// + /// \brief Bind a shader for rendering + /// + /// This function is not part of the graphics API, it mustn't be + /// used when drawing SFML entities. It must be used only if you + /// mix sf::Shader with OpenGL code. + /// + /// \code + /// sf::Shader s1, s2; + /// ... + /// sf::Shader::bind(&s1); + /// // draw OpenGL stuff that use s1... + /// sf::Shader::bind(&s2); + /// // draw OpenGL stuff that use s2... + /// sf::Shader::bind(NULL); + /// // draw OpenGL stuff that use no shader... + /// \endcode + /// + /// \param shader Shader to bind, can be null to use no shader + /// + //////////////////////////////////////////////////////////// + static void bind(const Shader* shader); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the system supports shaders + /// + /// This function should always be called before using + /// the shader features. If it returns false, then + /// any attempt to use sf::Shader will fail. + /// + /// \return True if shaders are supported, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isAvailable(); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the system supports geometry shaders + /// + /// This function should always be called before using + /// the geometry shader features. If it returns false, then + /// any attempt to use sf::Shader geometry shader features will fail. + /// + /// This function can only return true if isAvailable() would also + /// return true, since shaders in general have to be supported in + /// order for geometry shaders to be supported as well. + /// + /// Note: The first call to this function, whether by your + /// code or SFML will result in a context switch. + /// + /// \return True if geometry shaders are supported, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isGeometryAvailable(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Compile the shader(s) and create the program + /// + /// If one of the arguments is NULL, the corresponding shader + /// is not created. + /// + /// \param vertexShaderCode Source code of the vertex shader + /// \param geometryShaderCode Source code of the geometry shader + /// \param fragmentShaderCode Source code of the fragment shader + /// + /// \return True on success, false if any error happened + /// + //////////////////////////////////////////////////////////// + bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode); + + //////////////////////////////////////////////////////////// + /// \brief Bind all the textures used by the shader + /// + /// This function each texture to a different unit, and + /// updates the corresponding variables in the shader accordingly. + /// + //////////////////////////////////////////////////////////// + void bindTextures() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the location ID of a shader uniform + /// + /// \param name Name of the uniform variable to search + /// + /// \return Location ID of the uniform, or -1 if not found + /// + //////////////////////////////////////////////////////////// + int getUniformLocation(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief RAII object to save and restore the program + /// binding while uniforms are being set + /// + /// Implementation is private in the .cpp file. + /// + //////////////////////////////////////////////////////////// + struct UniformBinder; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map TextureTable; + typedef std::map UniformTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int m_shaderProgram; ///< OpenGL identifier for the program + int m_currentTexture; ///< Location of the current texture in the shader + TextureTable m_textures; ///< Texture variables in the shader, mapped to their location + UniformTable m_uniforms; ///< Parameters location cache +}; + +} // namespace sf + + +#endif // SFML_SHADER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Shader +/// \ingroup graphics +/// +/// Shaders are programs written using a specific language, +/// executed directly by the graphics card and allowing +/// to apply real-time operations to the rendered entities. +/// +/// There are three kinds of shaders: +/// \li %Vertex shaders, that process vertices +/// \li Geometry shaders, that process primitives +/// \li Fragment (pixel) shaders, that process pixels +/// +/// A sf::Shader can be composed of either a vertex shader +/// alone, a geometry shader alone, a fragment shader alone, +/// or any combination of them. (see the variants of the +/// load functions). +/// +/// Shaders are written in GLSL, which is a C-like +/// language dedicated to OpenGL shaders. You'll probably +/// need to learn its basics before writing your own shaders +/// for SFML. +/// +/// Like any C/C++ program, a GLSL shader has its own variables +/// called \a uniforms that you can set from your C++ application. +/// sf::Shader handles different types of uniforms: +/// \li scalars: \p float, \p int, \p bool +/// \li vectors (2, 3 or 4 components) +/// \li matrices (3x3 or 4x4) +/// \li samplers (textures) +/// +/// Some SFML-specific types can be converted: +/// \li sf::Color as a 4D vector (\p vec4) +/// \li sf::Transform as matrices (\p mat3 or \p mat4) +/// +/// Every uniform variable in a shader can be set through one of the +/// setUniform() or setUniformArray() overloads. For example, if you +/// have a shader with the following uniforms: +/// \code +/// uniform float offset; +/// uniform vec3 point; +/// uniform vec4 color; +/// uniform mat4 matrix; +/// uniform sampler2D overlay; +/// uniform sampler2D current; +/// \endcode +/// You can set their values from C++ code as follows, using the types +/// defined in the sf::Glsl namespace: +/// \code +/// shader.setUniform("offset", 2.f); +/// shader.setUniform("point", sf::Vector3f(0.5f, 0.8f, 0.3f)); +/// shader.setUniform("color", sf::Glsl::Vec4(color)); // color is a sf::Color +/// shader.setUniform("matrix", sf::Glsl::Mat4(transform)); // transform is a sf::Transform +/// shader.setUniform("overlay", texture); // texture is a sf::Texture +/// shader.setUniform("current", sf::Shader::CurrentTexture); +/// \endcode +/// +/// The old setParameter() overloads are deprecated and will be removed in a +/// future version. You should use their setUniform() equivalents instead. +/// +/// The special Shader::CurrentTexture argument maps the +/// given \p sampler2D uniform to the current texture of the +/// object being drawn (which cannot be known in advance). +/// +/// To apply a shader to a drawable, you must pass it as an +/// additional parameter to the \ref Window::draw() draw() function: +/// \code +/// window.draw(sprite, &shader); +/// \endcode +/// +/// ... which is in fact just a shortcut for this: +/// \code +/// sf::RenderStates states; +/// states.shader = &shader; +/// window.draw(sprite, states); +/// \endcode +/// +/// In the code above we pass a pointer to the shader, because it may +/// be null (which means "no shader"). +/// +/// Shaders can be used on any drawable, but some combinations are +/// not interesting. For example, using a vertex shader on a sf::Sprite +/// is limited because there are only 4 vertices, the sprite would +/// have to be subdivided in order to apply wave effects. +/// Another bad example is a fragment shader with sf::Text: the texture +/// of the text is not the actual text that you see on screen, it is +/// a big texture containing all the characters of the font in an +/// arbitrary order; thus, texture lookups on pixels other than the +/// current one may not give you the expected result. +/// +/// Shaders can also be used to apply global post-effects to the +/// current contents of the target (like the old sf::PostFx class +/// in SFML 1). This can be done in two different ways: +/// \li draw everything to a sf::RenderTexture, then draw it to +/// the main target using the shader +/// \li draw everything directly to the main target, then use +/// sf::Texture::update(Window&) to copy its contents to a texture +/// and draw it to the main target using the shader +/// +/// The first technique is more optimized because it doesn't involve +/// retrieving the target's pixels to system memory, but the +/// second one doesn't impact the rendering process and can be +/// easily inserted anywhere without impacting all the code. +/// +/// Like sf::Texture that can be used as a raw OpenGL texture, +/// sf::Shader can also be used directly as a raw shader for +/// custom OpenGL geometry. +/// \code +/// sf::Shader::bind(&shader); +/// ... render OpenGL geometry ... +/// sf::Shader::bind(NULL); +/// \endcode +/// +/// \see sf::Glsl +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Shape.hpp b/include/SFML/Graphics/Shape.hpp new file mode 100644 index 0000000..2878cc5 --- /dev/null +++ b/include/SFML/Graphics/Shape.hpp @@ -0,0 +1,355 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SHAPE_HPP +#define SFML_SHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Base class for textured shapes with outline +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Shape : public Drawable, public Transformable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Shape(); + + //////////////////////////////////////////////////////////// + /// \brief Change the source texture of the shape + /// + /// The \a texture argument refers to a texture that must + /// exist as long as the shape uses it. Indeed, the shape + /// doesn't store its own copy of the texture, but rather keeps + /// a pointer to the one that you passed to this function. + /// If the source texture is destroyed and the shape tries to + /// use it, the behavior is undefined. + /// \a texture can be NULL to disable texturing. + /// If \a resetRect is true, the TextureRect property of + /// the shape is automatically adjusted to the size of the new + /// texture. If it is false, the texture rect is left unchanged. + /// + /// \param texture New texture + /// \param resetRect Should the texture rect be reset to the size of the new texture? + /// + /// \see getTexture, setTextureRect + /// + //////////////////////////////////////////////////////////// + void setTexture(const Texture* texture, bool resetRect = false); + + //////////////////////////////////////////////////////////// + /// \brief Set the sub-rectangle of the texture that the shape will display + /// + /// The texture rect is useful when you don't want to display + /// the whole texture, but rather a part of it. + /// By default, the texture rect covers the entire texture. + /// + /// \param rect Rectangle defining the region of the texture to display + /// + /// \see getTextureRect, setTexture + /// + //////////////////////////////////////////////////////////// + void setTextureRect(const IntRect& rect); + + //////////////////////////////////////////////////////////// + /// \brief Set the fill color of the shape + /// + /// This color is modulated (multiplied) with the shape's + /// texture if any. It can be used to colorize the shape, + /// or change its global opacity. + /// You can use sf::Color::Transparent to make the inside of + /// the shape transparent, and have the outline alone. + /// By default, the shape's fill color is opaque white. + /// + /// \param color New color of the shape + /// + /// \see getFillColor, setOutlineColor + /// + //////////////////////////////////////////////////////////// + void setFillColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Set the outline color of the shape + /// + /// By default, the shape's outline color is opaque white. + /// + /// \param color New outline color of the shape + /// + /// \see getOutlineColor, setFillColor + /// + //////////////////////////////////////////////////////////// + void setOutlineColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Set the thickness of the shape's outline + /// + /// Note that negative values are allowed (so that the outline + /// expands towards the center of the shape), and using zero + /// disables the outline. + /// By default, the outline thickness is 0. + /// + /// \param thickness New outline thickness + /// + /// \see getOutlineThickness + /// + //////////////////////////////////////////////////////////// + void setOutlineThickness(float thickness); + + //////////////////////////////////////////////////////////// + /// \brief Get the source texture of the shape + /// + /// If the shape has no source texture, a NULL pointer is returned. + /// The returned pointer is const, which means that you can't + /// modify the texture when you retrieve it with this function. + /// + /// \return Pointer to the shape's texture + /// + /// \see setTexture + /// + //////////////////////////////////////////////////////////// + const Texture* getTexture() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sub-rectangle of the texture displayed by the shape + /// + /// \return Texture rectangle of the shape + /// + /// \see setTextureRect + /// + //////////////////////////////////////////////////////////// + const IntRect& getTextureRect() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the fill color of the shape + /// + /// \return Fill color of the shape + /// + /// \see setFillColor + /// + //////////////////////////////////////////////////////////// + const Color& getFillColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the outline color of the shape + /// + /// \return Outline color of the shape + /// + /// \see setOutlineColor + /// + //////////////////////////////////////////////////////////// + const Color& getOutlineColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the outline thickness of the shape + /// + /// \return Outline thickness of the shape + /// + /// \see setOutlineThickness + /// + //////////////////////////////////////////////////////////// + float getOutlineThickness() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the total number of points of the shape + /// + /// \return Number of points of the shape + /// + /// \see getPoint + /// + //////////////////////////////////////////////////////////// + virtual std::size_t getPointCount() const = 0; + + //////////////////////////////////////////////////////////// + /// \brief Get a point of the shape + /// + /// The returned point is in local coordinates, that is, + /// the shape's transforms (position, rotation, scale) are + /// not taken into account. + /// The result is undefined if \a index is out of the valid range. + /// + /// \param index Index of the point to get, in range [0 .. getPointCount() - 1] + /// + /// \return index-th point of the shape + /// + /// \see getPointCount + /// + //////////////////////////////////////////////////////////// + virtual Vector2f getPoint(std::size_t index) const = 0; + + //////////////////////////////////////////////////////////// + /// \brief Get the local bounding rectangle of the entity + /// + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. + /// + /// \return Local bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getLocalBounds() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the global (non-minimal) bounding rectangle of the entity + /// + /// The returned rectangle is in global coordinates, which means + /// that it takes into account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// shape in the global 2D world's coordinate system. + /// + /// This function does not necessarily return the \a minimal + /// bounding rectangle. It merely ensures that the returned + /// rectangle covers all the vertices (but possibly more). + /// This allows for a fast approximation of the bounds as a + /// first check; you may want to use more precise checks + /// on top of that. + /// + /// \return Global bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getGlobalBounds() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Shape(); + + //////////////////////////////////////////////////////////// + /// \brief Recompute the internal geometry of the shape + /// + /// This function must be called by the derived class everytime + /// the shape's points change (i.e. the result of either + /// getPointCount or getPoint is different). + /// + //////////////////////////////////////////////////////////// + void update(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Draw the shape to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void draw(RenderTarget& target, RenderStates states) const; + + //////////////////////////////////////////////////////////// + /// \brief Update the fill vertices' color + /// + //////////////////////////////////////////////////////////// + void updateFillColors(); + + //////////////////////////////////////////////////////////// + /// \brief Update the fill vertices' texture coordinates + /// + //////////////////////////////////////////////////////////// + void updateTexCoords(); + + //////////////////////////////////////////////////////////// + /// \brief Update the outline vertices' position + /// + //////////////////////////////////////////////////////////// + void updateOutline(); + + //////////////////////////////////////////////////////////// + /// \brief Update the outline vertices' color + /// + //////////////////////////////////////////////////////////// + void updateOutlineColors(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + const Texture* m_texture; ///< Texture of the shape + IntRect m_textureRect; ///< Rectangle defining the area of the source texture to display + Color m_fillColor; ///< Fill color + Color m_outlineColor; ///< Outline color + float m_outlineThickness; ///< Thickness of the shape's outline + VertexArray m_vertices; ///< Vertex array containing the fill geometry + VertexArray m_outlineVertices; ///< Vertex array containing the outline geometry + FloatRect m_insideBounds; ///< Bounding rectangle of the inside (fill) + FloatRect m_bounds; ///< Bounding rectangle of the whole shape (outline + fill) +}; + +} // namespace sf + + +#endif // SFML_SHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Shape +/// \ingroup graphics +/// +/// sf::Shape is a drawable class that allows to define and +/// display a custom convex shape on a render target. +/// It's only an abstract base, it needs to be specialized for +/// concrete types of shapes (circle, rectangle, convex polygon, +/// star, ...). +/// +/// In addition to the attributes provided by the specialized +/// shape classes, a shape always has the following attributes: +/// \li a texture +/// \li a texture rectangle +/// \li a fill color +/// \li an outline color +/// \li an outline thickness +/// +/// Each feature is optional, and can be disabled easily: +/// \li the texture can be null +/// \li the fill/outline colors can be sf::Color::Transparent +/// \li the outline thickness can be zero +/// +/// You can write your own derived shape class, there are only +/// two virtual functions to override: +/// \li getPointCount must return the number of points of the shape +/// \li getPoint must return the points of the shape +/// +/// \see sf::RectangleShape, sf::CircleShape, sf::ConvexShape, sf::Transformable +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Sprite.hpp b/include/SFML/Graphics/Sprite.hpp new file mode 100644 index 0000000..712fa15 --- /dev/null +++ b/include/SFML/Graphics/Sprite.hpp @@ -0,0 +1,279 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SPRITE_HPP +#define SFML_SPRITE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +class Texture; + +//////////////////////////////////////////////////////////// +/// \brief Drawable representation of a texture, with its +/// own transformations, color, etc. +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty sprite with no source texture. + /// + //////////////////////////////////////////////////////////// + Sprite(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the sprite from a source texture + /// + /// \param texture Source texture + /// + /// \see setTexture + /// + //////////////////////////////////////////////////////////// + explicit Sprite(const Texture& texture); + + //////////////////////////////////////////////////////////// + /// \brief Construct the sprite from a sub-rectangle of a source texture + /// + /// \param texture Source texture + /// \param rectangle Sub-rectangle of the texture to assign to the sprite + /// + /// \see setTexture, setTextureRect + /// + //////////////////////////////////////////////////////////// + Sprite(const Texture& texture, const IntRect& rectangle); + + //////////////////////////////////////////////////////////// + /// \brief Change the source texture of the sprite + /// + /// The \a texture argument refers to a texture that must + /// exist as long as the sprite uses it. Indeed, the sprite + /// doesn't store its own copy of the texture, but rather keeps + /// a pointer to the one that you passed to this function. + /// If the source texture is destroyed and the sprite tries to + /// use it, the behavior is undefined. + /// If \a resetRect is true, the TextureRect property of + /// the sprite is automatically adjusted to the size of the new + /// texture. If it is false, the texture rect is left unchanged. + /// + /// \param texture New texture + /// \param resetRect Should the texture rect be reset to the size of the new texture? + /// + /// \see getTexture, setTextureRect + /// + //////////////////////////////////////////////////////////// + void setTexture(const Texture& texture, bool resetRect = false); + + //////////////////////////////////////////////////////////// + /// \brief Set the sub-rectangle of the texture that the sprite will display + /// + /// The texture rect is useful when you don't want to display + /// the whole texture, but rather a part of it. + /// By default, the texture rect covers the entire texture. + /// + /// \param rectangle Rectangle defining the region of the texture to display + /// + /// \see getTextureRect, setTexture + /// + //////////////////////////////////////////////////////////// + void setTextureRect(const IntRect& rectangle); + + //////////////////////////////////////////////////////////// + /// \brief Set the global color of the sprite + /// + /// This color is modulated (multiplied) with the sprite's + /// texture. It can be used to colorize the sprite, or change + /// its global opacity. + /// By default, the sprite's color is opaque white. + /// + /// \param color New color of the sprite + /// + /// \see getColor + /// + //////////////////////////////////////////////////////////// + void setColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Get the source texture of the sprite + /// + /// If the sprite has no source texture, a NULL pointer is returned. + /// The returned pointer is const, which means that you can't + /// modify the texture when you retrieve it with this function. + /// + /// \return Pointer to the sprite's texture + /// + /// \see setTexture + /// + //////////////////////////////////////////////////////////// + const Texture* getTexture() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sub-rectangle of the texture displayed by the sprite + /// + /// \return Texture rectangle of the sprite + /// + /// \see setTextureRect + /// + //////////////////////////////////////////////////////////// + const IntRect& getTextureRect() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the global color of the sprite + /// + /// \return Global color of the sprite + /// + /// \see setColor + /// + //////////////////////////////////////////////////////////// + const Color& getColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the local bounding rectangle of the entity + /// + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. + /// + /// \return Local bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getLocalBounds() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the global bounding rectangle of the entity + /// + /// The returned rectangle is in global coordinates, which means + /// that it takes into account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// sprite in the global 2D world's coordinate system. + /// + /// \return Global bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getGlobalBounds() const; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Draw the sprite to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void draw(RenderTarget& target, RenderStates states) const; + + //////////////////////////////////////////////////////////// + /// \brief Update the vertices' positions + /// + //////////////////////////////////////////////////////////// + void updatePositions(); + + //////////////////////////////////////////////////////////// + /// \brief Update the vertices' texture coordinates + /// + //////////////////////////////////////////////////////////// + void updateTexCoords(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vertex m_vertices[4]; ///< Vertices defining the sprite's geometry + const Texture* m_texture; ///< Texture of the sprite + IntRect m_textureRect; ///< Rectangle defining the area of the source texture to display +}; + +} // namespace sf + + +#endif // SFML_SPRITE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Sprite +/// \ingroup graphics +/// +/// sf::Sprite is a drawable class that allows to easily display +/// a texture (or a part of it) on a render target. +/// +/// It inherits all the functions from sf::Transformable: +/// position, rotation, scale, origin. It also adds sprite-specific +/// properties such as the texture to use, the part of it to display, +/// and some convenience functions to change the overall color of the +/// sprite, or to get its bounding rectangle. +/// +/// sf::Sprite works in combination with the sf::Texture class, which +/// loads and provides the pixel data of a given texture. +/// +/// The separation of sf::Sprite and sf::Texture allows more flexibility +/// and better performances: indeed a sf::Texture is a heavy resource, +/// and any operation on it is slow (often too slow for real-time +/// applications). On the other side, a sf::Sprite is a lightweight +/// object which can use the pixel data of a sf::Texture and draw +/// it with its own transformation/color/blending attributes. +/// +/// It is important to note that the sf::Sprite instance doesn't +/// copy the texture that it uses, it only keeps a reference to it. +/// Thus, a sf::Texture must not be destroyed while it is +/// used by a sf::Sprite (i.e. never write a function that +/// uses a local sf::Texture instance for creating a sprite). +/// +/// See also the note on coordinates and undistorted rendering in sf::Transformable. +/// +/// Usage example: +/// \code +/// // Declare and load a texture +/// sf::Texture texture; +/// texture.loadFromFile("texture.png"); +/// +/// // Create a sprite +/// sf::Sprite sprite; +/// sprite.setTexture(texture); +/// sprite.setTextureRect(sf::IntRect(10, 10, 50, 30)); +/// sprite.setColor(sf::Color(255, 255, 255, 200)); +/// sprite.setPosition(100, 25); +/// +/// // Draw it +/// window.draw(sprite); +/// \endcode +/// +/// \see sf::Texture, sf::Transformable +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Text.hpp b/include/SFML/Graphics/Text.hpp new file mode 100644 index 0000000..9d54d97 --- /dev/null +++ b/include/SFML/Graphics/Text.hpp @@ -0,0 +1,456 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TEXT_HPP +#define SFML_TEXT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Graphical text that can be drawn to a render target +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Text : public Drawable, public Transformable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the string drawing styles + /// + //////////////////////////////////////////////////////////// + enum Style + { + Regular = 0, ///< Regular characters, no style + Bold = 1 << 0, ///< Bold characters + Italic = 1 << 1, ///< Italic characters + Underlined = 1 << 2, ///< Underlined characters + StrikeThrough = 1 << 3 ///< Strike through characters + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty text. + /// + //////////////////////////////////////////////////////////// + Text(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the text from a string, font and size + /// + /// Note that if the used font is a bitmap font, it is not + /// scalable, thus not all requested sizes will be available + /// to use. This needs to be taken into consideration when + /// setting the character size. If you need to display text + /// of a certain size, make sure the corresponding bitmap + /// font that supports that size is used. + /// + /// \param string Text assigned to the string + /// \param font Font used to draw the string + /// \param characterSize Base size of characters, in pixels + /// + //////////////////////////////////////////////////////////// + Text(const String& string, const Font& font, unsigned int characterSize = 30); + + //////////////////////////////////////////////////////////// + /// \brief Set the text's string + /// + /// The \a string argument is a sf::String, which can + /// automatically be constructed from standard string types. + /// So, the following calls are all valid: + /// \code + /// text.setString("hello"); + /// text.setString(L"hello"); + /// text.setString(std::string("hello")); + /// text.setString(std::wstring(L"hello")); + /// \endcode + /// A text's string is empty by default. + /// + /// \param string New string + /// + /// \see getString + /// + //////////////////////////////////////////////////////////// + void setString(const String& string); + + //////////////////////////////////////////////////////////// + /// \brief Set the text's font + /// + /// The \a font argument refers to a font that must + /// exist as long as the text uses it. Indeed, the text + /// doesn't store its own copy of the font, but rather keeps + /// a pointer to the one that you passed to this function. + /// If the font is destroyed and the text tries to + /// use it, the behavior is undefined. + /// + /// \param font New font + /// + /// \see getFont + /// + //////////////////////////////////////////////////////////// + void setFont(const Font& font); + + //////////////////////////////////////////////////////////// + /// \brief Set the character size + /// + /// The default size is 30. + /// + /// Note that if the used font is a bitmap font, it is not + /// scalable, thus not all requested sizes will be available + /// to use. This needs to be taken into consideration when + /// setting the character size. If you need to display text + /// of a certain size, make sure the corresponding bitmap + /// font that supports that size is used. + /// + /// \param size New character size, in pixels + /// + /// \see getCharacterSize + /// + //////////////////////////////////////////////////////////// + void setCharacterSize(unsigned int size); + + //////////////////////////////////////////////////////////// + /// \brief Set the text's style + /// + /// You can pass a combination of one or more styles, for + /// example sf::Text::Bold | sf::Text::Italic. + /// The default style is sf::Text::Regular. + /// + /// \param style New style + /// + /// \see getStyle + /// + //////////////////////////////////////////////////////////// + void setStyle(Uint32 style); + + //////////////////////////////////////////////////////////// + /// \brief Set the fill color of the text + /// + /// By default, the text's fill color is opaque white. + /// Setting the fill color to a transparent color with an outline + /// will cause the outline to be displayed in the fill area of the text. + /// + /// \param color New fill color of the text + /// + /// \see getFillColor + /// + /// \deprecated There is now fill and outline colors instead + /// of a single global color. + /// Use setFillColor() or setOutlineColor() instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED void setColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Set the fill color of the text + /// + /// By default, the text's fill color is opaque white. + /// Setting the fill color to a transparent color with an outline + /// will cause the outline to be displayed in the fill area of the text. + /// + /// \param color New fill color of the text + /// + /// \see getFillColor + /// + //////////////////////////////////////////////////////////// + void setFillColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Set the outline color of the text + /// + /// By default, the text's outline color is opaque black. + /// + /// \param color New outline color of the text + /// + /// \see getOutlineColor + /// + //////////////////////////////////////////////////////////// + void setOutlineColor(const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Set the thickness of the text's outline + /// + /// By default, the outline thickness is 0. + /// + /// Be aware that using a negative value for the outline + /// thickness will cause distorted rendering. + /// + /// \param thickness New outline thickness, in pixels + /// + /// \see getOutlineThickness + /// + //////////////////////////////////////////////////////////// + void setOutlineThickness(float thickness); + + //////////////////////////////////////////////////////////// + /// \brief Get the text's string + /// + /// The returned string is a sf::String, which can automatically + /// be converted to standard string types. So, the following + /// lines of code are all valid: + /// \code + /// sf::String s1 = text.getString(); + /// std::string s2 = text.getString(); + /// std::wstring s3 = text.getString(); + /// \endcode + /// + /// \return Text's string + /// + /// \see setString + /// + //////////////////////////////////////////////////////////// + const String& getString() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the text's font + /// + /// If the text has no font attached, a NULL pointer is returned. + /// The returned pointer is const, which means that you + /// cannot modify the font when you get it from this function. + /// + /// \return Pointer to the text's font + /// + /// \see setFont + /// + //////////////////////////////////////////////////////////// + const Font* getFont() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the character size + /// + /// \return Size of the characters, in pixels + /// + /// \see setCharacterSize + /// + //////////////////////////////////////////////////////////// + unsigned int getCharacterSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the text's style + /// + /// \return Text's style + /// + /// \see setStyle + /// + //////////////////////////////////////////////////////////// + Uint32 getStyle() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the fill color of the text + /// + /// \return Fill color of the text + /// + /// \see setFillColor + /// + /// \deprecated There is now fill and outline colors instead + /// of a single global color. + /// Use getFillColor() or getOutlineColor() instead. + /// + //////////////////////////////////////////////////////////// + SFML_DEPRECATED const Color& getColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the fill color of the text + /// + /// \return Fill color of the text + /// + /// \see setFillColor + /// + //////////////////////////////////////////////////////////// + const Color& getFillColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the outline color of the text + /// + /// \return Outline color of the text + /// + /// \see setOutlineColor + /// + //////////////////////////////////////////////////////////// + const Color& getOutlineColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the outline thickness of the text + /// + /// \return Outline thickness of the text, in pixels + /// + /// \see setOutlineThickness + /// + //////////////////////////////////////////////////////////// + float getOutlineThickness() const; + + //////////////////////////////////////////////////////////// + /// \brief Return the position of the \a index-th character + /// + /// This function computes the visual position of a character + /// from its index in the string. The returned position is + /// in global coordinates (translation, rotation, scale and + /// origin are applied). + /// If \a index is out of range, the position of the end of + /// the string is returned. + /// + /// \param index Index of the character + /// + /// \return Position of the character + /// + //////////////////////////////////////////////////////////// + Vector2f findCharacterPos(std::size_t index) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the local bounding rectangle of the entity + /// + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. + /// + /// \return Local bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getLocalBounds() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the global bounding rectangle of the entity + /// + /// The returned rectangle is in global coordinates, which means + /// that it takes into account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// text in the global 2D world's coordinate system. + /// + /// \return Global bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect getGlobalBounds() const; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Draw the text to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void draw(RenderTarget& target, RenderStates states) const; + + //////////////////////////////////////////////////////////// + /// \brief Make sure the text's geometry is updated + /// + /// All the attributes related to rendering are cached, such + /// that the geometry is only updated when necessary. + /// + //////////////////////////////////////////////////////////// + void ensureGeometryUpdate() const; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + String m_string; ///< String to display + const Font* m_font; ///< Font used to display the string + unsigned int m_characterSize; ///< Base size of characters, in pixels + Uint32 m_style; ///< Text style (see Style enum) + Color m_fillColor; ///< Text fill color + Color m_outlineColor; ///< Text outline color + float m_outlineThickness; ///< Thickness of the text's outline + mutable VertexArray m_vertices; ///< Vertex array containing the fill geometry + mutable VertexArray m_outlineVertices; ///< Vertex array containing the outline geometry + mutable FloatRect m_bounds; ///< Bounding rectangle of the text (in local coordinates) + mutable bool m_geometryNeedUpdate; ///< Does the geometry need to be recomputed? +}; + +} // namespace sf + + +#endif // SFML_TEXT_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Text +/// \ingroup graphics +/// +/// sf::Text is a drawable class that allows to easily display +/// some text with custom style and color on a render target. +/// +/// It inherits all the functions from sf::Transformable: +/// position, rotation, scale, origin. It also adds text-specific +/// properties such as the font to use, the character size, +/// the font style (bold, italic, underlined, strike through), the +/// global color and the text to display of course. +/// It also provides convenience functions to calculate the +/// graphical size of the text, or to get the global position +/// of a given character. +/// +/// sf::Text works in combination with the sf::Font class, which +/// loads and provides the glyphs (visual characters) of a given font. +/// +/// The separation of sf::Font and sf::Text allows more flexibility +/// and better performances: indeed a sf::Font is a heavy resource, +/// and any operation on it is slow (often too slow for real-time +/// applications). On the other side, a sf::Text is a lightweight +/// object which can combine the glyphs data and metrics of a sf::Font +/// to display any text on a render target. +/// +/// It is important to note that the sf::Text instance doesn't +/// copy the font that it uses, it only keeps a reference to it. +/// Thus, a sf::Font must not be destructed while it is +/// used by a sf::Text (i.e. never write a function that +/// uses a local sf::Font instance for creating a text). +/// +/// See also the note on coordinates and undistorted rendering in sf::Transformable. +/// +/// Usage example: +/// \code +/// // Declare and load a font +/// sf::Font font; +/// font.loadFromFile("arial.ttf"); +/// +/// // Create a text +/// sf::Text text("hello", font); +/// text.setCharacterSize(30); +/// text.setStyle(sf::Text::Bold); +/// text.setColor(sf::Color::Red); +/// +/// // Draw it +/// window.draw(text); +/// \endcode +/// +/// \see sf::Font, sf::Transformable +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Texture.hpp b/include/SFML/Graphics/Texture.hpp new file mode 100644 index 0000000..6434ab0 --- /dev/null +++ b/include/SFML/Graphics/Texture.hpp @@ -0,0 +1,686 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TEXTURE_HPP +#define SFML_TEXTURE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class Window; +class RenderTarget; +class RenderTexture; +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Image living on the graphics card that can be used for drawing +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Texture : GlResource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Types of texture coordinates that can be used for rendering + /// + //////////////////////////////////////////////////////////// + enum CoordinateType + { + Normalized, ///< Texture coordinates in range [0 .. 1] + Pixels ///< Texture coordinates in range [0 .. size] + }; + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty texture. + /// + //////////////////////////////////////////////////////////// + Texture(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy instance to copy + /// + //////////////////////////////////////////////////////////// + Texture(const Texture& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Texture(); + + //////////////////////////////////////////////////////////// + /// \brief Create the texture + /// + /// If this function fails, the texture is left unchanged. + /// + /// \param width Width of the texture + /// \param height Height of the texture + /// + /// \return True if creation was successful + /// + //////////////////////////////////////////////////////////// + bool create(unsigned int width, unsigned int height); + + //////////////////////////////////////////////////////////// + /// \brief Load the texture from a file on disk + /// + /// This function is a shortcut for the following code: + /// \code + /// sf::Image image; + /// image.loadFromFile(filename); + /// texture.loadFromImage(image, area); + /// \endcode + /// + /// The \a area argument can be used to load only a sub-rectangle + /// of the whole image. If you want the entire image then leave + /// the default value (which is an empty IntRect). + /// If the \a area rectangle crosses the bounds of the image, it + /// is adjusted to fit the image size. + /// + /// The maximum size for a texture depends on the graphics + /// driver and can be retrieved with the getMaximumSize function. + /// + /// If this function fails, the texture is left unchanged. + /// + /// \param filename Path of the image file to load + /// \param area Area of the image to load + /// + /// \return True if loading was successful + /// + /// \see loadFromMemory, loadFromStream, loadFromImage + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename, const IntRect& area = IntRect()); + + //////////////////////////////////////////////////////////// + /// \brief Load the texture from a file in memory + /// + /// This function is a shortcut for the following code: + /// \code + /// sf::Image image; + /// image.loadFromMemory(data, size); + /// texture.loadFromImage(image, area); + /// \endcode + /// + /// The \a area argument can be used to load only a sub-rectangle + /// of the whole image. If you want the entire image then leave + /// the default value (which is an empty IntRect). + /// If the \a area rectangle crosses the bounds of the image, it + /// is adjusted to fit the image size. + /// + /// The maximum size for a texture depends on the graphics + /// driver and can be retrieved with the getMaximumSize function. + /// + /// If this function fails, the texture is left unchanged. + /// + /// \param data Pointer to the file data in memory + /// \param size Size of the data to load, in bytes + /// \param area Area of the image to load + /// + /// \return True if loading was successful + /// + /// \see loadFromFile, loadFromStream, loadFromImage + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const void* data, std::size_t size, const IntRect& area = IntRect()); + + //////////////////////////////////////////////////////////// + /// \brief Load the texture from a custom stream + /// + /// This function is a shortcut for the following code: + /// \code + /// sf::Image image; + /// image.loadFromStream(stream); + /// texture.loadFromImage(image, area); + /// \endcode + /// + /// The \a area argument can be used to load only a sub-rectangle + /// of the whole image. If you want the entire image then leave + /// the default value (which is an empty IntRect). + /// If the \a area rectangle crosses the bounds of the image, it + /// is adjusted to fit the image size. + /// + /// The maximum size for a texture depends on the graphics + /// driver and can be retrieved with the getMaximumSize function. + /// + /// If this function fails, the texture is left unchanged. + /// + /// \param stream Source stream to read from + /// \param area Area of the image to load + /// + /// \return True if loading was successful + /// + /// \see loadFromFile, loadFromMemory, loadFromImage + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream, const IntRect& area = IntRect()); + + //////////////////////////////////////////////////////////// + /// \brief Load the texture from an image + /// + /// The \a area argument can be used to load only a sub-rectangle + /// of the whole image. If you want the entire image then leave + /// the default value (which is an empty IntRect). + /// If the \a area rectangle crosses the bounds of the image, it + /// is adjusted to fit the image size. + /// + /// The maximum size for a texture depends on the graphics + /// driver and can be retrieved with the getMaximumSize function. + /// + /// If this function fails, the texture is left unchanged. + /// + /// \param image Image to load into the texture + /// \param area Area of the image to load + /// + /// \return True if loading was successful + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromImage(const Image& image, const IntRect& area = IntRect()); + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the texture + /// + /// \return Size in pixels + /// + //////////////////////////////////////////////////////////// + Vector2u getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Copy the texture pixels to an image + /// + /// This function performs a slow operation that downloads + /// the texture's pixels from the graphics card and copies + /// them to a new image, potentially applying transformations + /// to pixels if necessary (texture may be padded or flipped). + /// + /// \return Image containing the texture's pixels + /// + /// \see loadFromImage + /// + //////////////////////////////////////////////////////////// + Image copyToImage() const; + + //////////////////////////////////////////////////////////// + /// \brief Update the whole texture from an array of pixels + /// + /// The \a pixel array is assumed to have the same size as + /// the \a area rectangle, and to contain 32-bits RGBA pixels. + /// + /// No additional check is performed on the size of the pixel + /// array, passing invalid arguments will lead to an undefined + /// behavior. + /// + /// This function does nothing if \a pixels is null or if the + /// texture was not previously created. + /// + /// \param pixels Array of pixels to copy to the texture + /// + //////////////////////////////////////////////////////////// + void update(const Uint8* pixels); + + //////////////////////////////////////////////////////////// + /// \brief Update a part of the texture from an array of pixels + /// + /// The size of the \a pixel array must match the \a width and + /// \a height arguments, and it must contain 32-bits RGBA pixels. + /// + /// No additional check is performed on the size of the pixel + /// array or the bounds of the area to update, passing invalid + /// arguments will lead to an undefined behavior. + /// + /// This function does nothing if \a pixels is null or if the + /// texture was not previously created. + /// + /// \param pixels Array of pixels to copy to the texture + /// \param width Width of the pixel region contained in \a pixels + /// \param height Height of the pixel region contained in \a pixels + /// \param x X offset in the texture where to copy the source pixels + /// \param y Y offset in the texture where to copy the source pixels + /// + //////////////////////////////////////////////////////////// + void update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y); + + //////////////////////////////////////////////////////////// + /// \brief Update the texture from an image + /// + /// Although the source image can be smaller than the texture, + /// this function is usually used for updating the whole texture. + /// The other overload, which has (x, y) additional arguments, + /// is more convenient for updating a sub-area of the texture. + /// + /// No additional check is performed on the size of the image, + /// passing an image bigger than the texture will lead to an + /// undefined behavior. + /// + /// This function does nothing if the texture was not + /// previously created. + /// + /// \param image Image to copy to the texture + /// + //////////////////////////////////////////////////////////// + void update(const Image& image); + + //////////////////////////////////////////////////////////// + /// \brief Update a part of the texture from an image + /// + /// No additional check is performed on the size of the image, + /// passing an invalid combination of image size and offset + /// will lead to an undefined behavior. + /// + /// This function does nothing if the texture was not + /// previously created. + /// + /// \param image Image to copy to the texture + /// \param x X offset in the texture where to copy the source image + /// \param y Y offset in the texture where to copy the source image + /// + //////////////////////////////////////////////////////////// + void update(const Image& image, unsigned int x, unsigned int y); + + //////////////////////////////////////////////////////////// + /// \brief Update the texture from the contents of a window + /// + /// Although the source window can be smaller than the texture, + /// this function is usually used for updating the whole texture. + /// The other overload, which has (x, y) additional arguments, + /// is more convenient for updating a sub-area of the texture. + /// + /// No additional check is performed on the size of the window, + /// passing a window bigger than the texture will lead to an + /// undefined behavior. + /// + /// This function does nothing if either the texture or the window + /// was not previously created. + /// + /// \param window Window to copy to the texture + /// + //////////////////////////////////////////////////////////// + void update(const Window& window); + + //////////////////////////////////////////////////////////// + /// \brief Update a part of the texture from the contents of a window + /// + /// No additional check is performed on the size of the window, + /// passing an invalid combination of window size and offset + /// will lead to an undefined behavior. + /// + /// This function does nothing if either the texture or the window + /// was not previously created. + /// + /// \param window Window to copy to the texture + /// \param x X offset in the texture where to copy the source window + /// \param y Y offset in the texture where to copy the source window + /// + //////////////////////////////////////////////////////////// + void update(const Window& window, unsigned int x, unsigned int y); + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable the smooth filter + /// + /// When the filter is activated, the texture appears smoother + /// so that pixels are less noticeable. However if you want + /// the texture to look exactly the same as its source file, + /// you should leave it disabled. + /// The smooth filter is disabled by default. + /// + /// \param smooth True to enable smoothing, false to disable it + /// + /// \see isSmooth + /// + //////////////////////////////////////////////////////////// + void setSmooth(bool smooth); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the smooth filter is enabled or not + /// + /// \return True if smoothing is enabled, false if it is disabled + /// + /// \see setSmooth + /// + //////////////////////////////////////////////////////////// + bool isSmooth() const; + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable conversion from sRGB + /// + /// When providing texture data from an image file or memory, it can + /// either be stored in a linear color space or an sRGB color space. + /// Most digital images account for gamma correction already, so they + /// would need to be "uncorrected" back to linear color space before + /// being processed by the hardware. The hardware can automatically + /// convert it from the sRGB color space to a linear color space when + /// it gets sampled. When the rendered image gets output to the final + /// framebuffer, it gets converted back to sRGB. + /// + /// After enabling or disabling sRGB conversion, make sure to reload + /// the texture data in order for the setting to take effect. + /// + /// This option is only useful in conjunction with an sRGB capable + /// framebuffer. This can be requested during window creation. + /// + /// \param sRgb True to enable sRGB conversion, false to disable it + /// + /// \see isSrgb + /// + //////////////////////////////////////////////////////////// + void setSrgb(bool sRgb); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the texture source is converted from sRGB or not + /// + /// \return True if the texture source is converted from sRGB, false if not + /// + /// \see setSrgb + /// + //////////////////////////////////////////////////////////// + bool isSrgb() const; + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable repeating + /// + /// Repeating is involved when using texture coordinates + /// outside the texture rectangle [0, 0, width, height]. + /// In this case, if repeat mode is enabled, the whole texture + /// will be repeated as many times as needed to reach the + /// coordinate (for example, if the X texture coordinate is + /// 3 * width, the texture will be repeated 3 times). + /// If repeat mode is disabled, the "extra space" will instead + /// be filled with border pixels. + /// Warning: on very old graphics cards, white pixels may appear + /// when the texture is repeated. With such cards, repeat mode + /// can be used reliably only if the texture has power-of-two + /// dimensions (such as 256x128). + /// Repeating is disabled by default. + /// + /// \param repeated True to repeat the texture, false to disable repeating + /// + /// \see isRepeated + /// + //////////////////////////////////////////////////////////// + void setRepeated(bool repeated); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the texture is repeated or not + /// + /// \return True if repeat mode is enabled, false if it is disabled + /// + /// \see setRepeated + /// + //////////////////////////////////////////////////////////// + bool isRepeated() const; + + //////////////////////////////////////////////////////////// + /// \brief Generate a mipmap using the current texture data + /// + /// Mipmaps are pre-computed chains of optimized textures. Each + /// level of texture in a mipmap is generated by halving each of + /// the previous level's dimensions. This is done until the final + /// level has the size of 1x1. The textures generated in this process may + /// make use of more advanced filters which might improve the visual quality + /// of textures when they are applied to objects much smaller than they are. + /// This is known as minification. Because fewer texels (texture elements) + /// have to be sampled from when heavily minified, usage of mipmaps + /// can also improve rendering performance in certain scenarios. + /// + /// Mipmap generation relies on the necessary OpenGL extension being + /// available. If it is unavailable or generation fails due to another + /// reason, this function will return false. Mipmap data is only valid from + /// the time it is generated until the next time the base level image is + /// modified, at which point this function will have to be called again to + /// regenerate it. + /// + /// \return True if mipmap generation was successful, false if unsuccessful + /// + //////////////////////////////////////////////////////////// + bool generateMipmap(); + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + Texture& operator =(const Texture& right); + + //////////////////////////////////////////////////////////// + /// \brief Get the underlying OpenGL handle of the texture. + /// + /// You shouldn't need to use this function, unless you have + /// very specific stuff to implement that SFML doesn't support, + /// or implement a temporary workaround until a bug is fixed. + /// + /// \return OpenGL handle of the texture or 0 if not yet created + /// + //////////////////////////////////////////////////////////// + unsigned int getNativeHandle() const; + + //////////////////////////////////////////////////////////// + /// \brief Bind a texture for rendering + /// + /// This function is not part of the graphics API, it mustn't be + /// used when drawing SFML entities. It must be used only if you + /// mix sf::Texture with OpenGL code. + /// + /// \code + /// sf::Texture t1, t2; + /// ... + /// sf::Texture::bind(&t1); + /// // draw OpenGL stuff that use t1... + /// sf::Texture::bind(&t2); + /// // draw OpenGL stuff that use t2... + /// sf::Texture::bind(NULL); + /// // draw OpenGL stuff that use no texture... + /// \endcode + /// + /// The \a coordinateType argument controls how texture + /// coordinates will be interpreted. If Normalized (the default), they + /// must be in range [0 .. 1], which is the default way of handling + /// texture coordinates with OpenGL. If Pixels, they must be given + /// in pixels (range [0 .. size]). This mode is used internally by + /// the graphics classes of SFML, it makes the definition of texture + /// coordinates more intuitive for the high-level API, users don't need + /// to compute normalized values. + /// + /// \param texture Pointer to the texture to bind, can be null to use no texture + /// \param coordinateType Type of texture coordinates to use + /// + //////////////////////////////////////////////////////////// + static void bind(const Texture* texture, CoordinateType coordinateType = Normalized); + + //////////////////////////////////////////////////////////// + /// \brief Get the maximum texture size allowed + /// + /// This maximum size is defined by the graphics driver. + /// You can expect a value of 512 pixels for low-end graphics + /// card, and up to 8192 pixels or more for newer hardware. + /// + /// \return Maximum size allowed for textures, in pixels + /// + //////////////////////////////////////////////////////////// + static unsigned int getMaximumSize(); + +private: + + friend class RenderTexture; + friend class RenderTarget; + + //////////////////////////////////////////////////////////// + /// \brief Get a valid image size according to hardware support + /// + /// This function checks whether the graphics driver supports + /// non power of two sizes or not, and adjusts the size + /// accordingly. + /// The returned size is greater than or equal to the original size. + /// + /// \param size size to convert + /// + /// \return Valid nearest size (greater than or equal to specified size) + /// + //////////////////////////////////////////////////////////// + static unsigned int getValidSize(unsigned int size); + + //////////////////////////////////////////////////////////// + /// \brief Invalidate the mipmap if one exists + /// + /// This also resets the texture's minifying function. + /// This function is mainly for internal use by RenderTexture. + /// + //////////////////////////////////////////////////////////// + void invalidateMipmap(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2u m_size; ///< Public texture size + Vector2u m_actualSize; ///< Actual texture size (can be greater than public size because of padding) + unsigned int m_texture; ///< Internal texture identifier + bool m_isSmooth; ///< Status of the smooth filter + bool m_sRgb; ///< Should the texture source be converted from sRGB? + bool m_isRepeated; ///< Is the texture in repeat mode? + mutable bool m_pixelsFlipped; ///< To work around the inconsistency in Y orientation + bool m_fboAttachment; ///< Is this texture owned by a framebuffer object? + bool m_hasMipmap; ///< Has the mipmap been generated? + Uint64 m_cacheId; ///< Unique number that identifies the texture to the render target's cache +}; + +} // namespace sf + + +#endif // SFML_TEXTURE_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::Texture +/// \ingroup graphics +/// +/// sf::Texture stores pixels that can be drawn, with a sprite +/// for example. A texture lives in the graphics card memory, +/// therefore it is very fast to draw a texture to a render target, +/// or copy a render target to a texture (the graphics card can +/// access both directly). +/// +/// Being stored in the graphics card memory has some drawbacks. +/// A texture cannot be manipulated as freely as a sf::Image, +/// you need to prepare the pixels first and then upload them +/// to the texture in a single operation (see Texture::update). +/// +/// sf::Texture makes it easy to convert from/to sf::Image, but +/// keep in mind that these calls require transfers between +/// the graphics card and the central memory, therefore they are +/// slow operations. +/// +/// A texture can be loaded from an image, but also directly +/// from a file/memory/stream. The necessary shortcuts are defined +/// so that you don't need an image first for the most common cases. +/// However, if you want to perform some modifications on the pixels +/// before creating the final texture, you can load your file to a +/// sf::Image, do whatever you need with the pixels, and then call +/// Texture::loadFromImage. +/// +/// Since they live in the graphics card memory, the pixels of a texture +/// cannot be accessed without a slow copy first. And they cannot be +/// accessed individually. Therefore, if you need to read the texture's +/// pixels (like for pixel-perfect collisions), it is recommended to +/// store the collision information separately, for example in an array +/// of booleans. +/// +/// Like sf::Image, sf::Texture can handle a unique internal +/// representation of pixels, which is RGBA 32 bits. This means +/// that a pixel must be composed of 8 bits red, green, blue and +/// alpha channels -- just like a sf::Color. +/// +/// Usage example: +/// \code +/// // This example shows the most common use of sf::Texture: +/// // drawing a sprite +/// +/// // Load a texture from a file +/// sf::Texture texture; +/// if (!texture.loadFromFile("texture.png")) +/// return -1; +/// +/// // Assign it to a sprite +/// sf::Sprite sprite; +/// sprite.setTexture(texture); +/// +/// // Draw the textured sprite +/// window.draw(sprite); +/// \endcode +/// +/// \code +/// // This example shows another common use of sf::Texture: +/// // streaming real-time data, like video frames +/// +/// // Create an empty texture +/// sf::Texture texture; +/// if (!texture.create(640, 480)) +/// return -1; +/// +/// // Create a sprite that will display the texture +/// sf::Sprite sprite(texture); +/// +/// while (...) // the main loop +/// { +/// ... +/// +/// // update the texture +/// sf::Uint8* pixels = ...; // get a fresh chunk of pixels (the next frame of a movie, for example) +/// texture.update(pixels); +/// +/// // draw it +/// window.draw(sprite); +/// +/// ... +/// } +/// +/// \endcode +/// +/// Like sf::Shader that can be used as a raw OpenGL shader, +/// sf::Texture can also be used directly as a raw texture for +/// custom OpenGL geometry. +/// \code +/// sf::Texture::bind(&texture); +/// ... render OpenGL geometry ... +/// sf::Texture::bind(NULL); +/// \endcode +/// +/// \see sf::Sprite, sf::Image, sf::RenderTexture +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Transform.hpp b/include/SFML/Graphics/Transform.hpp new file mode 100644 index 0000000..f1094ce --- /dev/null +++ b/include/SFML/Graphics/Transform.hpp @@ -0,0 +1,450 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TRANSFORM_HPP +#define SFML_TRANSFORM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a 3x3 transform matrix +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Transform +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an identity transform (a transform that does nothing). + /// + //////////////////////////////////////////////////////////// + Transform(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a transform from a 3x3 matrix + /// + /// \param a00 Element (0, 0) of the matrix + /// \param a01 Element (0, 1) of the matrix + /// \param a02 Element (0, 2) of the matrix + /// \param a10 Element (1, 0) of the matrix + /// \param a11 Element (1, 1) of the matrix + /// \param a12 Element (1, 2) of the matrix + /// \param a20 Element (2, 0) of the matrix + /// \param a21 Element (2, 1) of the matrix + /// \param a22 Element (2, 2) of the matrix + /// + //////////////////////////////////////////////////////////// + Transform(float a00, float a01, float a02, + float a10, float a11, float a12, + float a20, float a21, float a22); + + //////////////////////////////////////////////////////////// + /// \brief Return the transform as a 4x4 matrix + /// + /// This function returns a pointer to an array of 16 floats + /// containing the transform elements as a 4x4 matrix, which + /// is directly compatible with OpenGL functions. + /// + /// \code + /// sf::Transform transform = ...; + /// glLoadMatrixf(transform.getMatrix()); + /// \endcode + /// + /// \return Pointer to a 4x4 matrix + /// + //////////////////////////////////////////////////////////// + const float* getMatrix() const; + + //////////////////////////////////////////////////////////// + /// \brief Return the inverse of the transform + /// + /// If the inverse cannot be computed, an identity transform + /// is returned. + /// + /// \return A new transform which is the inverse of self + /// + //////////////////////////////////////////////////////////// + Transform getInverse() const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a 2D point + /// + /// \param x X coordinate of the point to transform + /// \param y Y coordinate of the point to transform + /// + /// \return Transformed point + /// + //////////////////////////////////////////////////////////// + Vector2f transformPoint(float x, float y) const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a 2D point + /// + /// \param point Point to transform + /// + /// \return Transformed point + /// + //////////////////////////////////////////////////////////// + Vector2f transformPoint(const Vector2f& point) const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a rectangle + /// + /// Since SFML doesn't provide support for oriented rectangles, + /// the result of this function is always an axis-aligned + /// rectangle. Which means that if the transform contains a + /// rotation, the bounding rectangle of the transformed rectangle + /// is returned. + /// + /// \param rectangle Rectangle to transform + /// + /// \return Transformed rectangle + /// + //////////////////////////////////////////////////////////// + FloatRect transformRect(const FloatRect& rectangle) const; + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with another one + /// + /// The result is a transform that is equivalent to applying + /// *this followed by \a transform. Mathematically, it is + /// equivalent to a matrix multiplication. + /// + /// \param transform Transform to combine with this transform + /// + /// \return Reference to *this + /// + //////////////////////////////////////////////////////////// + Transform& combine(const Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a translation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.translate(100, 200).rotate(45); + /// \endcode + /// + /// \param x Offset to apply on X axis + /// \param y Offset to apply on Y axis + /// + /// \return Reference to *this + /// + /// \see rotate, scale + /// + //////////////////////////////////////////////////////////// + Transform& translate(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a translation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.translate(sf::Vector2f(100, 200)).rotate(45); + /// \endcode + /// + /// \param offset Translation offset to apply + /// + /// \return Reference to *this + /// + /// \see rotate, scale + /// + //////////////////////////////////////////////////////////// + Transform& translate(const Vector2f& offset); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.rotate(90).translate(50, 20); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// + /// \return Reference to *this + /// + /// \see translate, scale + /// + //////////////////////////////////////////////////////////// + Transform& rotate(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// The center of rotation is provided for convenience as a second + /// argument, so that you can build rotations around arbitrary points + /// more easily (and efficiently) than the usual + /// translate(-center).rotate(angle).translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.rotate(90, 8, 3).translate(50, 20); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// \param centerX X coordinate of the center of rotation + /// \param centerY Y coordinate of the center of rotation + /// + /// \return Reference to *this + /// + /// \see translate, scale + /// + //////////////////////////////////////////////////////////// + Transform& rotate(float angle, float centerX, float centerY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// The center of rotation is provided for convenience as a second + /// argument, so that you can build rotations around arbitrary points + /// more easily (and efficiently) than the usual + /// translate(-center).rotate(angle).translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.rotate(90, sf::Vector2f(8, 3)).translate(sf::Vector2f(50, 20)); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// \param center Center of rotation + /// + /// \return Reference to *this + /// + /// \see translate, scale + /// + //////////////////////////////////////////////////////////// + Transform& rotate(float angle, const Vector2f& center); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.scale(2, 1).rotate(45); + /// \endcode + /// + /// \param scaleX Scaling factor on the X axis + /// \param scaleY Scaling factor on the Y axis + /// + /// \return Reference to *this + /// + /// \see translate, rotate + /// + //////////////////////////////////////////////////////////// + Transform& scale(float scaleX, float scaleY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// The center of scaling is provided for convenience as a second + /// argument, so that you can build scaling around arbitrary points + /// more easily (and efficiently) than the usual + /// translate(-center).scale(factors).translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.scale(2, 1, 8, 3).rotate(45); + /// \endcode + /// + /// \param scaleX Scaling factor on X axis + /// \param scaleY Scaling factor on Y axis + /// \param centerX X coordinate of the center of scaling + /// \param centerY Y coordinate of the center of scaling + /// + /// \return Reference to *this + /// + /// \see translate, rotate + /// + //////////////////////////////////////////////////////////// + Transform& scale(float scaleX, float scaleY, float centerX, float centerY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.scale(sf::Vector2f(2, 1)).rotate(45); + /// \endcode + /// + /// \param factors Scaling factors + /// + /// \return Reference to *this + /// + /// \see translate, rotate + /// + //////////////////////////////////////////////////////////// + Transform& scale(const Vector2f& factors); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// The center of scaling is provided for convenience as a second + /// argument, so that you can build scaling around arbitrary points + /// more easily (and efficiently) than the usual + /// translate(-center).scale(factors).translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.scale(sf::Vector2f(2, 1), sf::Vector2f(8, 3)).rotate(45); + /// \endcode + /// + /// \param factors Scaling factors + /// \param center Center of scaling + /// + /// \return Reference to *this + /// + /// \see translate, rotate + /// + //////////////////////////////////////////////////////////// + Transform& scale(const Vector2f& factors, const Vector2f& center); + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const Transform Identity; ///< The identity transform (does nothing) + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float m_matrix[16]; ///< 4x4 matrix defining the transformation +}; + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator * to combine two transforms +/// +/// This call is equivalent to calling Transform(left).combine(right). +/// +/// \param left Left operand (the first transform) +/// \param right Right operand (the second transform) +/// +/// \return New combined transform +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Transform operator *(const Transform& left, const Transform& right); + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator *= to combine two transforms +/// +/// This call is equivalent to calling left.combine(right). +/// +/// \param left Left operand (the first transform) +/// \param right Right operand (the second transform) +/// +/// \return The combined transform +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Transform& operator *=(Transform& left, const Transform& right); + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator * to transform a point +/// +/// This call is equivalent to calling left.transformPoint(right). +/// +/// \param left Left operand (the transform) +/// \param right Right operand (the point to transform) +/// +/// \return New transformed point +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API Vector2f operator *(const Transform& left, const Vector2f& right); + +} // namespace sf + + +#endif // SFML_TRANSFORM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Transform +/// \ingroup graphics +/// +/// A sf::Transform specifies how to translate, rotate, scale, +/// shear, project, whatever things. In mathematical terms, it defines +/// how to transform a coordinate system into another. +/// +/// For example, if you apply a rotation transform to a sprite, the +/// result will be a rotated sprite. And anything that is transformed +/// by this rotation transform will be rotated the same way, according +/// to its initial position. +/// +/// Transforms are typically used for drawing. But they can also be +/// used for any computation that requires to transform points between +/// the local and global coordinate systems of an entity (like collision +/// detection). +/// +/// Example: +/// \code +/// // define a translation transform +/// sf::Transform translation; +/// translation.translate(20, 50); +/// +/// // define a rotation transform +/// sf::Transform rotation; +/// rotation.rotate(45); +/// +/// // combine them +/// sf::Transform transform = translation * rotation; +/// +/// // use the result to transform stuff... +/// sf::Vector2f point = transform.transformPoint(10, 20); +/// sf::FloatRect rect = transform.transformRect(sf::FloatRect(0, 0, 10, 100)); +/// \endcode +/// +/// \see sf::Transformable, sf::RenderStates +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Transformable.hpp b/include/SFML/Graphics/Transformable.hpp new file mode 100644 index 0000000..d73cca4 --- /dev/null +++ b/include/SFML/Graphics/Transformable.hpp @@ -0,0 +1,429 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TRANSFORMABLE_HPP +#define SFML_TRANSFORMABLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Decomposed transform defined by a position, a rotation and a scale +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Transformable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Transformable(); + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Transformable(); + + //////////////////////////////////////////////////////////// + /// \brief set the position of the object + /// + /// This function completely overwrites the previous position. + /// See the move function to apply an offset based on the previous position instead. + /// The default position of a transformable object is (0, 0). + /// + /// \param x X coordinate of the new position + /// \param y Y coordinate of the new position + /// + /// \see move, getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief set the position of the object + /// + /// This function completely overwrites the previous position. + /// See the move function to apply an offset based on the previous position instead. + /// The default position of a transformable object is (0, 0). + /// + /// \param position New position + /// + /// \see move, getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(const Vector2f& position); + + //////////////////////////////////////////////////////////// + /// \brief set the orientation of the object + /// + /// This function completely overwrites the previous rotation. + /// See the rotate function to add an angle based on the previous rotation instead. + /// The default rotation of a transformable object is 0. + /// + /// \param angle New rotation, in degrees + /// + /// \see rotate, getRotation + /// + //////////////////////////////////////////////////////////// + void setRotation(float angle); + + //////////////////////////////////////////////////////////// + /// \brief set the scale factors of the object + /// + /// This function completely overwrites the previous scale. + /// See the scale function to add a factor based on the previous scale instead. + /// The default scale of a transformable object is (1, 1). + /// + /// \param factorX New horizontal scale factor + /// \param factorY New vertical scale factor + /// + /// \see scale, getScale + /// + //////////////////////////////////////////////////////////// + void setScale(float factorX, float factorY); + + //////////////////////////////////////////////////////////// + /// \brief set the scale factors of the object + /// + /// This function completely overwrites the previous scale. + /// See the scale function to add a factor based on the previous scale instead. + /// The default scale of a transformable object is (1, 1). + /// + /// \param factors New scale factors + /// + /// \see scale, getScale + /// + //////////////////////////////////////////////////////////// + void setScale(const Vector2f& factors); + + //////////////////////////////////////////////////////////// + /// \brief set the local origin of the object + /// + /// The origin of an object defines the center point for + /// all transformations (position, scale, rotation). + /// The coordinates of this point must be relative to the + /// top-left corner of the object, and ignore all + /// transformations (position, scale, rotation). + /// The default origin of a transformable object is (0, 0). + /// + /// \param x X coordinate of the new origin + /// \param y Y coordinate of the new origin + /// + /// \see getOrigin + /// + //////////////////////////////////////////////////////////// + void setOrigin(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief set the local origin of the object + /// + /// The origin of an object defines the center point for + /// all transformations (position, scale, rotation). + /// The coordinates of this point must be relative to the + /// top-left corner of the object, and ignore all + /// transformations (position, scale, rotation). + /// The default origin of a transformable object is (0, 0). + /// + /// \param origin New origin + /// + /// \see getOrigin + /// + //////////////////////////////////////////////////////////// + void setOrigin(const Vector2f& origin); + + //////////////////////////////////////////////////////////// + /// \brief get the position of the object + /// + /// \return Current position + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + const Vector2f& getPosition() const; + + //////////////////////////////////////////////////////////// + /// \brief get the orientation of the object + /// + /// The rotation is always in the range [0, 360]. + /// + /// \return Current rotation, in degrees + /// + /// \see setRotation + /// + //////////////////////////////////////////////////////////// + float getRotation() const; + + //////////////////////////////////////////////////////////// + /// \brief get the current scale of the object + /// + /// \return Current scale factors + /// + /// \see setScale + /// + //////////////////////////////////////////////////////////// + const Vector2f& getScale() const; + + //////////////////////////////////////////////////////////// + /// \brief get the local origin of the object + /// + /// \return Current origin + /// + /// \see setOrigin + /// + //////////////////////////////////////////////////////////// + const Vector2f& getOrigin() const; + + //////////////////////////////////////////////////////////// + /// \brief Move the object by a given offset + /// + /// This function adds to the current position of the object, + /// unlike setPosition which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f pos = object.getPosition(); + /// object.setPosition(pos.x + offsetX, pos.y + offsetY); + /// \endcode + /// + /// \param offsetX X offset + /// \param offsetY Y offset + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + void move(float offsetX, float offsetY); + + //////////////////////////////////////////////////////////// + /// \brief Move the object by a given offset + /// + /// This function adds to the current position of the object, + /// unlike setPosition which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// object.setPosition(object.getPosition() + offset); + /// \endcode + /// + /// \param offset Offset + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + void move(const Vector2f& offset); + + //////////////////////////////////////////////////////////// + /// \brief Rotate the object + /// + /// This function adds to the current rotation of the object, + /// unlike setRotation which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// object.setRotation(object.getRotation() + angle); + /// \endcode + /// + /// \param angle Angle of rotation, in degrees + /// + //////////////////////////////////////////////////////////// + void rotate(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Scale the object + /// + /// This function multiplies the current scale of the object, + /// unlike setScale which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f scale = object.getScale(); + /// object.setScale(scale.x * factorX, scale.y * factorY); + /// \endcode + /// + /// \param factorX Horizontal scale factor + /// \param factorY Vertical scale factor + /// + /// \see setScale + /// + //////////////////////////////////////////////////////////// + void scale(float factorX, float factorY); + + //////////////////////////////////////////////////////////// + /// \brief Scale the object + /// + /// This function multiplies the current scale of the object, + /// unlike setScale which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f scale = object.getScale(); + /// object.setScale(scale.x * factor.x, scale.y * factor.y); + /// \endcode + /// + /// \param factor Scale factors + /// + /// \see setScale + /// + //////////////////////////////////////////////////////////// + void scale(const Vector2f& factor); + + //////////////////////////////////////////////////////////// + /// \brief get the combined transform of the object + /// + /// \return Transform combining the position/rotation/scale/origin of the object + /// + /// \see getInverseTransform + /// + //////////////////////////////////////////////////////////// + const Transform& getTransform() const; + + //////////////////////////////////////////////////////////// + /// \brief get the inverse of the combined transform of the object + /// + /// \return Inverse of the combined transformations applied to the object + /// + /// \see getTransform + /// + //////////////////////////////////////////////////////////// + const Transform& getInverseTransform() const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f m_origin; ///< Origin of translation/rotation/scaling of the object + Vector2f m_position; ///< Position of the object in the 2D world + float m_rotation; ///< Orientation of the object, in degrees + Vector2f m_scale; ///< Scale of the object + mutable Transform m_transform; ///< Combined transformation of the object + mutable bool m_transformNeedUpdate; ///< Does the transform need to be recomputed? + mutable Transform m_inverseTransform; ///< Combined transformation of the object + mutable bool m_inverseTransformNeedUpdate; ///< Does the transform need to be recomputed? +}; + +} // namespace sf + + +#endif // SFML_TRANSFORMABLE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Transformable +/// \ingroup graphics +/// +/// This class is provided for convenience, on top of sf::Transform. +/// +/// sf::Transform, as a low-level class, offers a great level of +/// flexibility but it is not always convenient to manage. Indeed, +/// one can easily combine any kind of operation, such as a translation +/// followed by a rotation followed by a scaling, but once the result +/// transform is built, there's no way to go backward and, let's say, +/// change only the rotation without modifying the translation and scaling. +/// The entire transform must be recomputed, which means that you +/// need to retrieve the initial translation and scale factors as +/// well, and combine them the same way you did before updating the +/// rotation. This is a tedious operation, and it requires to store +/// all the individual components of the final transform. +/// +/// That's exactly what sf::Transformable was written for: it hides +/// these variables and the composed transform behind an easy to use +/// interface. You can set or get any of the individual components +/// without worrying about the others. It also provides the composed +/// transform (as a sf::Transform), and keeps it up-to-date. +/// +/// In addition to the position, rotation and scale, sf::Transformable +/// provides an "origin" component, which represents the local origin +/// of the three other components. Let's take an example with a 10x10 +/// pixels sprite. By default, the sprite is positioned/rotated/scaled +/// relatively to its top-left corner, because it is the local point +/// (0, 0). But if we change the origin to be (5, 5), the sprite will +/// be positioned/rotated/scaled around its center instead. And if +/// we set the origin to (10, 10), it will be transformed around its +/// bottom-right corner. +/// +/// To keep the sf::Transformable class simple, there's only one +/// origin for all the components. You cannot position the sprite +/// relatively to its top-left corner while rotating it around its +/// center, for example. To do such things, use sf::Transform directly. +/// +/// sf::Transformable can be used as a base class. It is often +/// combined with sf::Drawable -- that's what SFML's sprites, +/// texts and shapes do. +/// \code +/// class MyEntity : public sf::Transformable, public sf::Drawable +/// { +/// virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const +/// { +/// states.transform *= getTransform(); +/// target.draw(..., states); +/// } +/// }; +/// +/// MyEntity entity; +/// entity.setPosition(10, 20); +/// entity.setRotation(45); +/// window.draw(entity); +/// \endcode +/// +/// It can also be used as a member, if you don't want to use +/// its API directly (because you don't need all its functions, +/// or you have different naming conventions for example). +/// \code +/// class MyEntity +/// { +/// public: +/// void SetPosition(const MyVector& v) +/// { +/// myTransform.setPosition(v.x(), v.y()); +/// } +/// +/// void Draw(sf::RenderTarget& target) const +/// { +/// target.draw(..., myTransform.getTransform()); +/// } +/// +/// private: +/// sf::Transformable myTransform; +/// }; +/// \endcode +/// +/// A note on coordinates and undistorted rendering: \n +/// By default, SFML (or more exactly, OpenGL) may interpolate drawable objects +/// such as sprites or texts when rendering. While this allows transitions +/// like slow movements or rotations to appear smoothly, it can lead to +/// unwanted results in some cases, for example blurred or distorted objects. +/// In order to render a sf::Drawable object pixel-perfectly, make sure +/// the involved coordinates allow a 1:1 mapping of pixels in the window +/// to texels (pixels in the texture). More specifically, this means: +/// * The object's position, origin and scale have no fractional part +/// * The object's and the view's rotation are a multiple of 90 degrees +/// * The view's center and size have no fractional part +/// +/// \see sf::Transform +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Vertex.hpp b/include/SFML/Graphics/Vertex.hpp new file mode 100644 index 0000000..d2693f9 --- /dev/null +++ b/include/SFML/Graphics/Vertex.hpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VERTEX_HPP +#define SFML_VERTEX_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a point with color and texture coordinates +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API Vertex +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Vertex(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position + /// + /// The vertex color is white and texture coordinates are (0, 0). + /// + /// \param thePosition Vertex position + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& thePosition); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position and color + /// + /// The texture coordinates are (0, 0). + /// + /// \param thePosition Vertex position + /// \param theColor Vertex color + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& thePosition, const Color& theColor); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position and texture coordinates + /// + /// The vertex color is white. + /// + /// \param thePosition Vertex position + /// \param theTexCoords Vertex texture coordinates + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& thePosition, const Vector2f& theTexCoords); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position, color and texture coordinates + /// + /// \param thePosition Vertex position + /// \param theColor Vertex color + /// \param theTexCoords Vertex texture coordinates + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& thePosition, const Color& theColor, const Vector2f& theTexCoords); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f position; ///< 2D position of the vertex + Color color; ///< Color of the vertex + Vector2f texCoords; ///< Coordinates of the texture's pixel to map to the vertex +}; + +} // namespace sf + + +#endif // SFML_VERTEX_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Vertex +/// \ingroup graphics +/// +/// A vertex is an improved point. It has a position and other +/// extra attributes that will be used for drawing: in SFML, +/// vertices also have a color and a pair of texture coordinates. +/// +/// The vertex is the building block of drawing. Everything which +/// is visible on screen is made of vertices. They are grouped +/// as 2D primitives (triangles, quads, ...), and these primitives +/// are grouped to create even more complex 2D entities such as +/// sprites, texts, etc. +/// +/// If you use the graphical entities of SFML (sprite, text, shape) +/// you won't have to deal with vertices directly. But if you want +/// to define your own 2D entities, such as tiled maps or particle +/// systems, using vertices will allow you to get maximum performances. +/// +/// Example: +/// \code +/// // define a 100x100 square, red, with a 10x10 texture mapped on it +/// sf::Vertex vertices[] = +/// { +/// sf::Vertex(sf::Vector2f( 0, 0), sf::Color::Red, sf::Vector2f( 0, 0)), +/// sf::Vertex(sf::Vector2f( 0, 100), sf::Color::Red, sf::Vector2f( 0, 10)), +/// sf::Vertex(sf::Vector2f(100, 100), sf::Color::Red, sf::Vector2f(10, 10)), +/// sf::Vertex(sf::Vector2f(100, 0), sf::Color::Red, sf::Vector2f(10, 0)) +/// }; +/// +/// // draw it +/// window.draw(vertices, 4, sf::Quads); +/// \endcode +/// +/// Note: although texture coordinates are supposed to be an integer +/// amount of pixels, their type is float because of some buggy graphics +/// drivers that are not able to process integer coordinates correctly. +/// +/// \see sf::VertexArray +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/VertexArray.hpp b/include/SFML/Graphics/VertexArray.hpp new file mode 100644 index 0000000..33dfe95 --- /dev/null +++ b/include/SFML/Graphics/VertexArray.hpp @@ -0,0 +1,223 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VERTEXARRAY_HPP +#define SFML_VERTEXARRAY_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a set of one or more 2D primitives +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API VertexArray : public Drawable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty vertex array. + /// + //////////////////////////////////////////////////////////// + VertexArray(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex array with a type and an initial number of vertices + /// + /// \param type Type of primitives + /// \param vertexCount Initial number of vertices in the array + /// + //////////////////////////////////////////////////////////// + explicit VertexArray(PrimitiveType type, std::size_t vertexCount = 0); + + //////////////////////////////////////////////////////////// + /// \brief Return the vertex count + /// + /// \return Number of vertices in the array + /// + //////////////////////////////////////////////////////////// + std::size_t getVertexCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a read-write access to a vertex by its index + /// + /// This function doesn't check \a index, it must be in range + /// [0, getVertexCount() - 1]. The behavior is undefined + /// otherwise. + /// + /// \param index Index of the vertex to get + /// + /// \return Reference to the index-th vertex + /// + /// \see getVertexCount + /// + //////////////////////////////////////////////////////////// + Vertex& operator [](std::size_t index); + + //////////////////////////////////////////////////////////// + /// \brief Get a read-only access to a vertex by its index + /// + /// This function doesn't check \a index, it must be in range + /// [0, getVertexCount() - 1]. The behavior is undefined + /// otherwise. + /// + /// \param index Index of the vertex to get + /// + /// \return Const reference to the index-th vertex + /// + /// \see getVertexCount + /// + //////////////////////////////////////////////////////////// + const Vertex& operator [](std::size_t index) const; + + //////////////////////////////////////////////////////////// + /// \brief Clear the vertex array + /// + /// This function removes all the vertices from the array. + /// It doesn't deallocate the corresponding memory, so that + /// adding new vertices after clearing doesn't involve + /// reallocating all the memory. + /// + //////////////////////////////////////////////////////////// + void clear(); + + //////////////////////////////////////////////////////////// + /// \brief Resize the vertex array + /// + /// If \a vertexCount is greater than the current size, the previous + /// vertices are kept and new (default-constructed) vertices are + /// added. + /// If \a vertexCount is less than the current size, existing vertices + /// are removed from the array. + /// + /// \param vertexCount New size of the array (number of vertices) + /// + //////////////////////////////////////////////////////////// + void resize(std::size_t vertexCount); + + //////////////////////////////////////////////////////////// + /// \brief Add a vertex to the array + /// + /// \param vertex Vertex to add + /// + //////////////////////////////////////////////////////////// + void append(const Vertex& vertex); + + //////////////////////////////////////////////////////////// + /// \brief Set the type of primitives to draw + /// + /// This function defines how the vertices must be interpreted + /// when it's time to draw them: + /// \li As points + /// \li As lines + /// \li As triangles + /// \li As quads + /// The default primitive type is sf::Points. + /// + /// \param type Type of primitive + /// + //////////////////////////////////////////////////////////// + void setPrimitiveType(PrimitiveType type); + + //////////////////////////////////////////////////////////// + /// \brief Get the type of primitives drawn by the vertex array + /// + /// \return Primitive type + /// + //////////////////////////////////////////////////////////// + PrimitiveType getPrimitiveType() const; + + //////////////////////////////////////////////////////////// + /// \brief Compute the bounding rectangle of the vertex array + /// + /// This function returns the minimal axis-aligned rectangle + /// that contains all the vertices of the array. + /// + /// \return Bounding rectangle of the vertex array + /// + //////////////////////////////////////////////////////////// + FloatRect getBounds() const; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Draw the vertex array to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void draw(RenderTarget& target, RenderStates states) const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_vertices; ///< Vertices contained in the array + PrimitiveType m_primitiveType; ///< Type of primitives to draw +}; + +} // namespace sf + + +#endif // SFML_VERTEXARRAY_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::VertexArray +/// \ingroup graphics +/// +/// sf::VertexArray is a very simple wrapper around a dynamic +/// array of vertices and a primitives type. +/// +/// It inherits sf::Drawable, but unlike other drawables it +/// is not transformable. +/// +/// Example: +/// \code +/// sf::VertexArray lines(sf::LineStrip, 4); +/// lines[0].position = sf::Vector2f(10, 0); +/// lines[1].position = sf::Vector2f(20, 0); +/// lines[2].position = sf::Vector2f(30, 5); +/// lines[3].position = sf::Vector2f(40, 2); +/// +/// window.draw(lines); +/// \endcode +/// +/// \see sf::Vertex +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/View.hpp b/include/SFML/Graphics/View.hpp new file mode 100644 index 0000000..2e4f510 --- /dev/null +++ b/include/SFML/Graphics/View.hpp @@ -0,0 +1,343 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VIEW_HPP +#define SFML_VIEW_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief 2D camera that defines what region is shown on screen +/// +//////////////////////////////////////////////////////////// +class SFML_GRAPHICS_API View +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor creates a default view of (0, 0, 1000, 1000) + /// + //////////////////////////////////////////////////////////// + View(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the view from a rectangle + /// + /// \param rectangle Rectangle defining the zone to display + /// + //////////////////////////////////////////////////////////// + explicit View(const FloatRect& rectangle); + + //////////////////////////////////////////////////////////// + /// \brief Construct the view from its center and size + /// + /// \param center Center of the zone to display + /// \param size Size of zone to display + /// + //////////////////////////////////////////////////////////// + View(const Vector2f& center, const Vector2f& size); + + //////////////////////////////////////////////////////////// + /// \brief Set the center of the view + /// + /// \param x X coordinate of the new center + /// \param y Y coordinate of the new center + /// + /// \see setSize, getCenter + /// + //////////////////////////////////////////////////////////// + void setCenter(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Set the center of the view + /// + /// \param center New center + /// + /// \see setSize, getCenter + /// + //////////////////////////////////////////////////////////// + void setCenter(const Vector2f& center); + + //////////////////////////////////////////////////////////// + /// \brief Set the size of the view + /// + /// \param width New width of the view + /// \param height New height of the view + /// + /// \see setCenter, getCenter + /// + //////////////////////////////////////////////////////////// + void setSize(float width, float height); + + //////////////////////////////////////////////////////////// + /// \brief Set the size of the view + /// + /// \param size New size + /// + /// \see setCenter, getCenter + /// + //////////////////////////////////////////////////////////// + void setSize(const Vector2f& size); + + //////////////////////////////////////////////////////////// + /// \brief Set the orientation of the view + /// + /// The default rotation of a view is 0 degree. + /// + /// \param angle New angle, in degrees + /// + /// \see getRotation + /// + //////////////////////////////////////////////////////////// + void setRotation(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Set the target viewport + /// + /// The viewport is the rectangle into which the contents of the + /// view are displayed, expressed as a factor (between 0 and 1) + /// of the size of the RenderTarget to which the view is applied. + /// For example, a view which takes the left side of the target would + /// be defined with View.setViewport(sf::FloatRect(0, 0, 0.5, 1)). + /// By default, a view has a viewport which covers the entire target. + /// + /// \param viewport New viewport rectangle + /// + /// \see getViewport + /// + //////////////////////////////////////////////////////////// + void setViewport(const FloatRect& viewport); + + //////////////////////////////////////////////////////////// + /// \brief Reset the view to the given rectangle + /// + /// Note that this function resets the rotation angle to 0. + /// + /// \param rectangle Rectangle defining the zone to display + /// + /// \see setCenter, setSize, setRotation + /// + //////////////////////////////////////////////////////////// + void reset(const FloatRect& rectangle); + + //////////////////////////////////////////////////////////// + /// \brief Get the center of the view + /// + /// \return Center of the view + /// + /// \see getSize, setCenter + /// + //////////////////////////////////////////////////////////// + const Vector2f& getCenter() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the view + /// + /// \return Size of the view + /// + /// \see getCenter, setSize + /// + //////////////////////////////////////////////////////////// + const Vector2f& getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current orientation of the view + /// + /// \return Rotation angle of the view, in degrees + /// + /// \see setRotation + /// + //////////////////////////////////////////////////////////// + float getRotation() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the target viewport rectangle of the view + /// + /// \return Viewport rectangle, expressed as a factor of the target size + /// + /// \see setViewport + /// + //////////////////////////////////////////////////////////// + const FloatRect& getViewport() const; + + //////////////////////////////////////////////////////////// + /// \brief Move the view relatively to its current position + /// + /// \param offsetX X coordinate of the move offset + /// \param offsetY Y coordinate of the move offset + /// + /// \see setCenter, rotate, zoom + /// + //////////////////////////////////////////////////////////// + void move(float offsetX, float offsetY); + + //////////////////////////////////////////////////////////// + /// \brief Move the view relatively to its current position + /// + /// \param offset Move offset + /// + /// \see setCenter, rotate, zoom + /// + //////////////////////////////////////////////////////////// + void move(const Vector2f& offset); + + //////////////////////////////////////////////////////////// + /// \brief Rotate the view relatively to its current orientation + /// + /// \param angle Angle to rotate, in degrees + /// + /// \see setRotation, move, zoom + /// + //////////////////////////////////////////////////////////// + void rotate(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Resize the view rectangle relatively to its current size + /// + /// Resizing the view simulates a zoom, as the zone displayed on + /// screen grows or shrinks. + /// \a factor is a multiplier: + /// \li 1 keeps the size unchanged + /// \li > 1 makes the view bigger (objects appear smaller) + /// \li < 1 makes the view smaller (objects appear bigger) + /// + /// \param factor Zoom factor to apply + /// + /// \see setSize, move, rotate + /// + //////////////////////////////////////////////////////////// + void zoom(float factor); + + //////////////////////////////////////////////////////////// + /// \brief Get the projection transform of the view + /// + /// This function is meant for internal use only. + /// + /// \return Projection transform defining the view + /// + /// \see getInverseTransform + /// + //////////////////////////////////////////////////////////// + const Transform& getTransform() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the inverse projection transform of the view + /// + /// This function is meant for internal use only. + /// + /// \return Inverse of the projection transform defining the view + /// + /// \see getTransform + /// + //////////////////////////////////////////////////////////// + const Transform& getInverseTransform() const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f m_center; ///< Center of the view, in scene coordinates + Vector2f m_size; ///< Size of the view, in scene coordinates + float m_rotation; ///< Angle of rotation of the view rectangle, in degrees + FloatRect m_viewport; ///< Viewport rectangle, expressed as a factor of the render-target's size + mutable Transform m_transform; ///< Precomputed projection transform corresponding to the view + mutable Transform m_inverseTransform; ///< Precomputed inverse projection transform corresponding to the view + mutable bool m_transformUpdated; ///< Internal state telling if the transform needs to be updated + mutable bool m_invTransformUpdated; ///< Internal state telling if the inverse transform needs to be updated +}; + +} // namespace sf + + +#endif // SFML_VIEW_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::View +/// \ingroup graphics +/// +/// sf::View defines a camera in the 2D scene. This is a +/// very powerful concept: you can scroll, rotate or zoom +/// the entire scene without altering the way that your +/// drawable objects are drawn. +/// +/// A view is composed of a source rectangle, which defines +/// what part of the 2D scene is shown, and a target viewport, +/// which defines where the contents of the source rectangle +/// will be displayed on the render target (window or texture). +/// +/// The viewport allows to map the scene to a custom part +/// of the render target, and can be used for split-screen +/// or for displaying a minimap, for example. If the source +/// rectangle doesn't have the same size as the viewport, its +/// contents will be stretched to fit in. +/// +/// To apply a view, you have to assign it to the render target. +/// Then, objects drawn in this render target will be +/// affected by the view until you use another view. +/// +/// Usage example: +/// \code +/// sf::RenderWindow window; +/// sf::View view; +/// +/// // Initialize the view to a rectangle located at (100, 100) and with a size of 400x200 +/// view.reset(sf::FloatRect(100, 100, 400, 200)); +/// +/// // Rotate it by 45 degrees +/// view.rotate(45); +/// +/// // Set its target viewport to be half of the window +/// view.setViewport(sf::FloatRect(0.f, 0.f, 0.5f, 1.f)); +/// +/// // Apply it +/// window.setView(view); +/// +/// // Render stuff +/// window.draw(someSprite); +/// +/// // Set the default view back +/// window.setView(window.getDefaultView()); +/// +/// // Render stuff not affected by the view +/// window.draw(someText); +/// \endcode +/// +/// See also the note on coordinates and undistorted rendering in sf::Transformable. +/// +/// \see sf::RenderWindow, sf::RenderTexture +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Main.hpp b/include/SFML/Main.hpp new file mode 100644 index 0000000..d61b82e --- /dev/null +++ b/include/SFML/Main.hpp @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_MAIN_HPP +#define SFML_MAIN_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +#if defined(SFML_SYSTEM_IOS) + + // On iOS, we have no choice but to have our own main, + // so we need to rename the user one and call it later + #define main sfmlMain + +#endif + + +#endif // SFML_MAIN_HPP diff --git a/include/SFML/Network.hpp b/include/SFML/Network.hpp new file mode 100644 index 0000000..1deaa03 --- /dev/null +++ b/include/SFML/Network.hpp @@ -0,0 +1,53 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NETWORK_HPP +#define SFML_NETWORK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif // SFML_NETWORK_HPP + +//////////////////////////////////////////////////////////// +/// \defgroup network Network module +/// +/// Socket-based communication, utilities and higher-level +/// network protocols (HTTP, FTP). +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Export.hpp b/include/SFML/Network/Export.hpp new file mode 100644 index 0000000..43adf18 --- /dev/null +++ b/include/SFML/Network/Export.hpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NETWORK_EXPORT_HPP +#define SFML_NETWORK_EXPORT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_NETWORK_EXPORTS) + + #define SFML_NETWORK_API SFML_API_EXPORT + +#else + + #define SFML_NETWORK_API SFML_API_IMPORT + +#endif + + +#endif // SFML_NETWORK_EXPORT_HPP diff --git a/include/SFML/Network/Ftp.hpp b/include/SFML/Network/Ftp.hpp new file mode 100644 index 0000000..ad0cbc3 --- /dev/null +++ b/include/SFML/Network/Ftp.hpp @@ -0,0 +1,612 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_FTP_HPP +#define SFML_FTP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +class IpAddress; + +//////////////////////////////////////////////////////////// +/// \brief A FTP client +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API Ftp : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of transfer modes + /// + //////////////////////////////////////////////////////////// + enum TransferMode + { + Binary, ///< Binary mode (file is transfered as a sequence of bytes) + Ascii, ///< Text mode using ASCII encoding + Ebcdic ///< Text mode using EBCDIC encoding + }; + + //////////////////////////////////////////////////////////// + /// \brief Define a FTP response + /// + //////////////////////////////////////////////////////////// + class SFML_NETWORK_API Response + { + public: + + //////////////////////////////////////////////////////////// + /// \brief Status codes possibly returned by a FTP response + /// + //////////////////////////////////////////////////////////// + enum Status + { + // 1xx: the requested action is being initiated, + // expect another reply before proceeding with a new command + RestartMarkerReply = 110, ///< Restart marker reply + ServiceReadySoon = 120, ///< Service ready in N minutes + DataConnectionAlreadyOpened = 125, ///< Data connection already opened, transfer starting + OpeningDataConnection = 150, ///< File status ok, about to open data connection + + // 2xx: the requested action has been successfully completed + Ok = 200, ///< Command ok + PointlessCommand = 202, ///< Command not implemented + SystemStatus = 211, ///< System status, or system help reply + DirectoryStatus = 212, ///< Directory status + FileStatus = 213, ///< File status + HelpMessage = 214, ///< Help message + SystemType = 215, ///< NAME system type, where NAME is an official system name from the list in the Assigned Numbers document + ServiceReady = 220, ///< Service ready for new user + ClosingConnection = 221, ///< Service closing control connection + DataConnectionOpened = 225, ///< Data connection open, no transfer in progress + ClosingDataConnection = 226, ///< Closing data connection, requested file action successful + EnteringPassiveMode = 227, ///< Entering passive mode + LoggedIn = 230, ///< User logged in, proceed. Logged out if appropriate + FileActionOk = 250, ///< Requested file action ok + DirectoryOk = 257, ///< PATHNAME created + + // 3xx: the command has been accepted, but the requested action + // is dormant, pending receipt of further information + NeedPassword = 331, ///< User name ok, need password + NeedAccountToLogIn = 332, ///< Need account for login + NeedInformation = 350, ///< Requested file action pending further information + + // 4xx: the command was not accepted and the requested action did not take place, + // but the error condition is temporary and the action may be requested again + ServiceUnavailable = 421, ///< Service not available, closing control connection + DataConnectionUnavailable = 425, ///< Can't open data connection + TransferAborted = 426, ///< Connection closed, transfer aborted + FileActionAborted = 450, ///< Requested file action not taken + LocalError = 451, ///< Requested action aborted, local error in processing + InsufficientStorageSpace = 452, ///< Requested action not taken; insufficient storage space in system, file unavailable + + // 5xx: the command was not accepted and + // the requested action did not take place + CommandUnknown = 500, ///< Syntax error, command unrecognized + ParametersUnknown = 501, ///< Syntax error in parameters or arguments + CommandNotImplemented = 502, ///< Command not implemented + BadCommandSequence = 503, ///< Bad sequence of commands + ParameterNotImplemented = 504, ///< Command not implemented for that parameter + NotLoggedIn = 530, ///< Not logged in + NeedAccountToStore = 532, ///< Need account for storing files + FileUnavailable = 550, ///< Requested action not taken, file unavailable + PageTypeUnknown = 551, ///< Requested action aborted, page type unknown + NotEnoughMemory = 552, ///< Requested file action aborted, exceeded storage allocation + FilenameNotAllowed = 553, ///< Requested action not taken, file name not allowed + + // 10xx: SFML custom codes + InvalidResponse = 1000, ///< Not part of the FTP standard, generated by SFML when a received response cannot be parsed + ConnectionFailed = 1001, ///< Not part of the FTP standard, generated by SFML when the low-level socket connection with the server fails + ConnectionClosed = 1002, ///< Not part of the FTP standard, generated by SFML when the low-level socket connection is unexpectedly closed + InvalidFile = 1003 ///< Not part of the FTP standard, generated by SFML when a local file cannot be read or written + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is used by the FTP client to build + /// the response. + /// + /// \param code Response status code + /// \param message Response message + /// + //////////////////////////////////////////////////////////// + explicit Response(Status code = InvalidResponse, const std::string& message = ""); + + //////////////////////////////////////////////////////////// + /// \brief Check if the status code means a success + /// + /// This function is defined for convenience, it is + /// equivalent to testing if the status code is < 400. + /// + /// \return True if the status is a success, false if it is a failure + /// + //////////////////////////////////////////////////////////// + bool isOk() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the status code of the response + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the full message contained in the response + /// + /// \return The response message + /// + //////////////////////////////////////////////////////////// + const std::string& getMessage() const; + + private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Status m_status; ///< Status code returned from the server + std::string m_message; ///< Last message received from the server + }; + + //////////////////////////////////////////////////////////// + /// \brief Specialization of FTP response returning a directory + /// + //////////////////////////////////////////////////////////// + class SFML_NETWORK_API DirectoryResponse : public Response + { + public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param response Source response + /// + //////////////////////////////////////////////////////////// + DirectoryResponse(const Response& response); + + //////////////////////////////////////////////////////////// + /// \brief Get the directory returned in the response + /// + /// \return Directory name + /// + //////////////////////////////////////////////////////////// + const std::string& getDirectory() const; + + private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::string m_directory; ///< Directory extracted from the response message + }; + + + //////////////////////////////////////////////////////////// + /// \brief Specialization of FTP response returning a + /// filename listing + //////////////////////////////////////////////////////////// + class SFML_NETWORK_API ListingResponse : public Response + { + public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param response Source response + /// \param data Data containing the raw listing + /// + //////////////////////////////////////////////////////////// + ListingResponse(const Response& response, const std::string& data); + + //////////////////////////////////////////////////////////// + /// \brief Return the array of directory/file names + /// + /// \return Array containing the requested listing + /// + //////////////////////////////////////////////////////////// + const std::vector& getListing() const; + + private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_listing; ///< Directory/file names extracted from the data + }; + + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Automatically closes the connection with the server if + /// it is still opened. + /// + //////////////////////////////////////////////////////////// + ~Ftp(); + + //////////////////////////////////////////////////////////// + /// \brief Connect to the specified FTP server + /// + /// The port has a default value of 21, which is the standard + /// port used by the FTP protocol. You shouldn't use a different + /// value, unless you really know what you do. + /// This function tries to connect to the server so it may take + /// a while to complete, especially if the server is not + /// reachable. To avoid blocking your application for too long, + /// you can use a timeout. The default value, Time::Zero, means that the + /// system timeout will be used (which is usually pretty long). + /// + /// \param server Name or address of the FTP server to connect to + /// \param port Port used for the connection + /// \param timeout Maximum time to wait + /// + /// \return Server response to the request + /// + /// \see disconnect + /// + //////////////////////////////////////////////////////////// + Response connect(const IpAddress& server, unsigned short port = 21, Time timeout = Time::Zero); + + //////////////////////////////////////////////////////////// + /// \brief Close the connection with the server + /// + /// \return Server response to the request + /// + /// \see connect + /// + //////////////////////////////////////////////////////////// + Response disconnect(); + + //////////////////////////////////////////////////////////// + /// \brief Log in using an anonymous account + /// + /// Logging in is mandatory after connecting to the server. + /// Users that are not logged in cannot perform any operation. + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response login(); + + //////////////////////////////////////////////////////////// + /// \brief Log in using a username and a password + /// + /// Logging in is mandatory after connecting to the server. + /// Users that are not logged in cannot perform any operation. + /// + /// \param name User name + /// \param password Password + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response login(const std::string& name, const std::string& password); + + //////////////////////////////////////////////////////////// + /// \brief Send a null command to keep the connection alive + /// + /// This command is useful because the server may close the + /// connection automatically if no command is sent. + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response keepAlive(); + + //////////////////////////////////////////////////////////// + /// \brief Get the current working directory + /// + /// The working directory is the root path for subsequent + /// operations involving directories and/or filenames. + /// + /// \return Server response to the request + /// + /// \see getDirectoryListing, changeDirectory, parentDirectory + /// + //////////////////////////////////////////////////////////// + DirectoryResponse getWorkingDirectory(); + + //////////////////////////////////////////////////////////// + /// \brief Get the contents of the given directory + /// + /// This function retrieves the sub-directories and files + /// contained in the given directory. It is not recursive. + /// The \a directory parameter is relative to the current + /// working directory. + /// + /// \param directory Directory to list + /// + /// \return Server response to the request + /// + /// \see getWorkingDirectory, changeDirectory, parentDirectory + /// + //////////////////////////////////////////////////////////// + ListingResponse getDirectoryListing(const std::string& directory = ""); + + //////////////////////////////////////////////////////////// + /// \brief Change the current working directory + /// + /// The new directory must be relative to the current one. + /// + /// \param directory New working directory + /// + /// \return Server response to the request + /// + /// \see getWorkingDirectory, getDirectoryListing, parentDirectory + /// + //////////////////////////////////////////////////////////// + Response changeDirectory(const std::string& directory); + + //////////////////////////////////////////////////////////// + /// \brief Go to the parent directory of the current one + /// + /// \return Server response to the request + /// + /// \see getWorkingDirectory, getDirectoryListing, changeDirectory + /// + //////////////////////////////////////////////////////////// + Response parentDirectory(); + + //////////////////////////////////////////////////////////// + /// \brief Create a new directory + /// + /// The new directory is created as a child of the current + /// working directory. + /// + /// \param name Name of the directory to create + /// + /// \return Server response to the request + /// + /// \see deleteDirectory + /// + //////////////////////////////////////////////////////////// + Response createDirectory(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief Remove an existing directory + /// + /// The directory to remove must be relative to the + /// current working directory. + /// Use this function with caution, the directory will + /// be removed permanently! + /// + /// \param name Name of the directory to remove + /// + /// \return Server response to the request + /// + /// \see createDirectory + /// + //////////////////////////////////////////////////////////// + Response deleteDirectory(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief Rename an existing file + /// + /// The filenames must be relative to the current working + /// directory. + /// + /// \param file File to rename + /// \param newName New name of the file + /// + /// \return Server response to the request + /// + /// \see deleteFile + /// + //////////////////////////////////////////////////////////// + Response renameFile(const std::string& file, const std::string& newName); + + //////////////////////////////////////////////////////////// + /// \brief Remove an existing file + /// + /// The file name must be relative to the current working + /// directory. + /// Use this function with caution, the file will be + /// removed permanently! + /// + /// \param name File to remove + /// + /// \return Server response to the request + /// + /// \see renameFile + /// + //////////////////////////////////////////////////////////// + Response deleteFile(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief Download a file from the server + /// + /// The filename of the distant file is relative to the + /// current working directory of the server, and the local + /// destination path is relative to the current directory + /// of your application. + /// If a file with the same filename as the distant file + /// already exists in the local destination path, it will + /// be overwritten. + /// + /// \param remoteFile Filename of the distant file to download + /// \param localPath The directory in which to put the file on the local computer + /// \param mode Transfer mode + /// + /// \return Server response to the request + /// + /// \see upload + /// + //////////////////////////////////////////////////////////// + Response download(const std::string& remoteFile, const std::string& localPath, TransferMode mode = Binary); + + //////////////////////////////////////////////////////////// + /// \brief Upload a file to the server + /// + /// The name of the local file is relative to the current + /// working directory of your application, and the + /// remote path is relative to the current directory of the + /// FTP server. + /// + /// \param localFile Path of the local file to upload + /// \param remotePath The directory in which to put the file on the server + /// \param mode Transfer mode + /// + /// \return Server response to the request + /// + /// \see download + /// + //////////////////////////////////////////////////////////// + Response upload(const std::string& localFile, const std::string& remotePath, TransferMode mode = Binary); + + //////////////////////////////////////////////////////////// + /// \brief Send a command to the FTP server + /// + /// While the most often used commands are provided as member + /// functions in the sf::Ftp class, this method can be used + /// to send any FTP command to the server. If the command + /// requires one or more parameters, they can be specified + /// in \a parameter. If the server returns information, you + /// can extract it from the response using Response::getMessage(). + /// + /// \param command Command to send + /// \param parameter Command parameter + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response sendCommand(const std::string& command, const std::string& parameter = ""); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Receive a response from the server + /// + /// This function must be called after each call to + /// sendCommand that expects a response. + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response getResponse(); + + //////////////////////////////////////////////////////////// + /// \brief Utility class for exchanging datas with the server + /// on the data channel + /// + //////////////////////////////////////////////////////////// + class DataChannel; + + friend class DataChannel; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + TcpSocket m_commandSocket; ///< Socket holding the control connection with the server + std::string m_receiveBuffer; ///< Received command data that is yet to be processed +}; + +} // namespace sf + + +#endif // SFML_FTP_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Ftp +/// \ingroup network +/// +/// sf::Ftp is a very simple FTP client that allows you +/// to communicate with a FTP server. The FTP protocol allows +/// you to manipulate a remote file system (list files, +/// upload, download, create, remove, ...). +/// +/// Using the FTP client consists of 4 parts: +/// \li Connecting to the FTP server +/// \li Logging in (either as a registered user or anonymously) +/// \li Sending commands to the server +/// \li Disconnecting (this part can be done implicitly by the destructor) +/// +/// Every command returns a FTP response, which contains the +/// status code as well as a message from the server. Some +/// commands such as getWorkingDirectory() and getDirectoryListing() +/// return additional data, and use a class derived from +/// sf::Ftp::Response to provide this data. The most often used +/// commands are directly provided as member functions, but it is +/// also possible to use specific commands with the sendCommand() function. +/// +/// Note that response statuses >= 1000 are not part of the FTP standard, +/// they are generated by SFML when an internal error occurs. +/// +/// All commands, especially upload and download, may take some +/// time to complete. This is important to know if you don't want +/// to block your application while the server is completing +/// the task. +/// +/// Usage example: +/// \code +/// // Create a new FTP client +/// sf::Ftp ftp; +/// +/// // Connect to the server +/// sf::Ftp::Response response = ftp.connect("ftp://ftp.myserver.com"); +/// if (response.isOk()) +/// std::cout << "Connected" << std::endl; +/// +/// // Log in +/// response = ftp.login("laurent", "dF6Zm89D"); +/// if (response.isOk()) +/// std::cout << "Logged in" << std::endl; +/// +/// // Print the working directory +/// sf::Ftp::DirectoryResponse directory = ftp.getWorkingDirectory(); +/// if (directory.isOk()) +/// std::cout << "Working directory: " << directory.getDirectory() << std::endl; +/// +/// // Create a new directory +/// response = ftp.createDirectory("files"); +/// if (response.isOk()) +/// std::cout << "Created new directory" << std::endl; +/// +/// // Upload a file to this new directory +/// response = ftp.upload("local-path/file.txt", "files", sf::Ftp::Ascii); +/// if (response.isOk()) +/// std::cout << "File uploaded" << std::endl; +/// +/// // Send specific commands (here: FEAT to list supported FTP features) +/// response = ftp.sendCommand("FEAT"); +/// if (response.isOk()) +/// std::cout << "Feature list:\n" << response.getMessage() << std::endl; +/// +/// // Disconnect from the server (optional) +/// ftp.disconnect(); +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Http.hpp b/include/SFML/Network/Http.hpp new file mode 100644 index 0000000..231da15 --- /dev/null +++ b/include/SFML/Network/Http.hpp @@ -0,0 +1,482 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_HTTP_HPP +#define SFML_HTTP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief A HTTP client +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API Http : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Define a HTTP request + /// + //////////////////////////////////////////////////////////// + class SFML_NETWORK_API Request + { + public: + + //////////////////////////////////////////////////////////// + /// \brief Enumerate the available HTTP methods for a request + /// + //////////////////////////////////////////////////////////// + enum Method + { + Get, ///< Request in get mode, standard method to retrieve a page + Post, ///< Request in post mode, usually to send data to a page + Head, ///< Request a page's header only + Put, ///< Request in put mode, useful for a REST API + Delete ///< Request in delete mode, useful for a REST API + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor creates a GET request, with the root + /// URI ("/") and an empty body. + /// + /// \param uri Target URI + /// \param method Method to use for the request + /// \param body Content of the request's body + /// + //////////////////////////////////////////////////////////// + Request(const std::string& uri = "/", Method method = Get, const std::string& body = ""); + + //////////////////////////////////////////////////////////// + /// \brief Set the value of a field + /// + /// The field is created if it doesn't exist. The name of + /// the field is case-insensitive. + /// By default, a request doesn't contain any field (but the + /// mandatory fields are added later by the HTTP client when + /// sending the request). + /// + /// \param field Name of the field to set + /// \param value Value of the field + /// + //////////////////////////////////////////////////////////// + void setField(const std::string& field, const std::string& value); + + //////////////////////////////////////////////////////////// + /// \brief Set the request method + /// + /// See the Method enumeration for a complete list of all + /// the availale methods. + /// The method is Http::Request::Get by default. + /// + /// \param method Method to use for the request + /// + //////////////////////////////////////////////////////////// + void setMethod(Method method); + + //////////////////////////////////////////////////////////// + /// \brief Set the requested URI + /// + /// The URI is the resource (usually a web page or a file) + /// that you want to get or post. + /// The URI is "/" (the root page) by default. + /// + /// \param uri URI to request, relative to the host + /// + //////////////////////////////////////////////////////////// + void setUri(const std::string& uri); + + //////////////////////////////////////////////////////////// + /// \brief Set the HTTP version for the request + /// + /// The HTTP version is 1.0 by default. + /// + /// \param major Major HTTP version number + /// \param minor Minor HTTP version number + /// + //////////////////////////////////////////////////////////// + void setHttpVersion(unsigned int major, unsigned int minor); + + //////////////////////////////////////////////////////////// + /// \brief Set the body of the request + /// + /// The body of a request is optional and only makes sense + /// for POST requests. It is ignored for all other methods. + /// The body is empty by default. + /// + /// \param body Content of the body + /// + //////////////////////////////////////////////////////////// + void setBody(const std::string& body); + + private: + + friend class Http; + + //////////////////////////////////////////////////////////// + /// \brief Prepare the final request to send to the server + /// + /// This is used internally by Http before sending the + /// request to the web server. + /// + /// \return String containing the request, ready to be sent + /// + //////////////////////////////////////////////////////////// + std::string prepare() const; + + //////////////////////////////////////////////////////////// + /// \brief Check if the request defines a field + /// + /// This function uses case-insensitive comparisons. + /// + /// \param field Name of the field to test + /// + /// \return True if the field exists, false otherwise + /// + //////////////////////////////////////////////////////////// + bool hasField(const std::string& field) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map FieldTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + FieldTable m_fields; ///< Fields of the header associated to their value + Method m_method; ///< Method to use for the request + std::string m_uri; ///< Target URI of the request + unsigned int m_majorVersion; ///< Major HTTP version + unsigned int m_minorVersion; ///< Minor HTTP version + std::string m_body; ///< Body of the request + }; + + //////////////////////////////////////////////////////////// + /// \brief Define a HTTP response + /// + //////////////////////////////////////////////////////////// + class SFML_NETWORK_API Response + { + public: + + //////////////////////////////////////////////////////////// + /// \brief Enumerate all the valid status codes for a response + /// + //////////////////////////////////////////////////////////// + enum Status + { + // 2xx: success + Ok = 200, ///< Most common code returned when operation was successful + Created = 201, ///< The resource has successfully been created + Accepted = 202, ///< The request has been accepted, but will be processed later by the server + NoContent = 204, ///< The server didn't send any data in return + ResetContent = 205, ///< The server informs the client that it should clear the view (form) that caused the request to be sent + PartialContent = 206, ///< The server has sent a part of the resource, as a response to a partial GET request + + // 3xx: redirection + MultipleChoices = 300, ///< The requested page can be accessed from several locations + MovedPermanently = 301, ///< The requested page has permanently moved to a new location + MovedTemporarily = 302, ///< The requested page has temporarily moved to a new location + NotModified = 304, ///< For conditional requests, means the requested page hasn't changed and doesn't need to be refreshed + + // 4xx: client error + BadRequest = 400, ///< The server couldn't understand the request (syntax error) + Unauthorized = 401, ///< The requested page needs an authentication to be accessed + Forbidden = 403, ///< The requested page cannot be accessed at all, even with authentication + NotFound = 404, ///< The requested page doesn't exist + RangeNotSatisfiable = 407, ///< The server can't satisfy the partial GET request (with a "Range" header field) + + // 5xx: server error + InternalServerError = 500, ///< The server encountered an unexpected error + NotImplemented = 501, ///< The server doesn't implement a requested feature + BadGateway = 502, ///< The gateway server has received an error from the source server + ServiceNotAvailable = 503, ///< The server is temporarily unavailable (overloaded, in maintenance, ...) + GatewayTimeout = 504, ///< The gateway server couldn't receive a response from the source server + VersionNotSupported = 505, ///< The server doesn't support the requested HTTP version + + // 10xx: SFML custom codes + InvalidResponse = 1000, ///< Response is not a valid HTTP one + ConnectionFailed = 1001 ///< Connection with server failed + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs an empty response. + /// + //////////////////////////////////////////////////////////// + Response(); + + //////////////////////////////////////////////////////////// + /// \brief Get the value of a field + /// + /// If the field \a field is not found in the response header, + /// the empty string is returned. This function uses + /// case-insensitive comparisons. + /// + /// \param field Name of the field to get + /// + /// \return Value of the field, or empty string if not found + /// + //////////////////////////////////////////////////////////// + const std::string& getField(const std::string& field) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the response status code + /// + /// The status code should be the first thing to be checked + /// after receiving a response, it defines whether it is a + /// success, a failure or anything else (see the Status + /// enumeration). + /// + /// \return Status code of the response + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the major HTTP version number of the response + /// + /// \return Major HTTP version number + /// + /// \see getMinorHttpVersion + /// + //////////////////////////////////////////////////////////// + unsigned int getMajorHttpVersion() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the minor HTTP version number of the response + /// + /// \return Minor HTTP version number + /// + /// \see getMajorHttpVersion + /// + //////////////////////////////////////////////////////////// + unsigned int getMinorHttpVersion() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the body of the response + /// + /// The body of a response may contain: + /// \li the requested page (for GET requests) + /// \li a response from the server (for POST requests) + /// \li nothing (for HEAD requests) + /// \li an error message (in case of an error) + /// + /// \return The response body + /// + //////////////////////////////////////////////////////////// + const std::string& getBody() const; + + private: + + friend class Http; + + //////////////////////////////////////////////////////////// + /// \brief Construct the header from a response string + /// + /// This function is used by Http to build the response + /// of a request. + /// + /// \param data Content of the response to parse + /// + //////////////////////////////////////////////////////////// + void parse(const std::string& data); + + + //////////////////////////////////////////////////////////// + /// \brief Read values passed in the answer header + /// + /// This function is used by Http to extract values passed + /// in the response. + /// + /// \param in String stream containing the header values + /// + //////////////////////////////////////////////////////////// + void parseFields(std::istream &in); + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map FieldTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + FieldTable m_fields; ///< Fields of the header + Status m_status; ///< Status code + unsigned int m_majorVersion; ///< Major HTTP version + unsigned int m_minorVersion; ///< Minor HTTP version + std::string m_body; ///< Body of the response + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Http(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the HTTP client with the target host + /// + /// This is equivalent to calling setHost(host, port). + /// The port has a default value of 0, which means that the + /// HTTP client will use the right port according to the + /// protocol used (80 for HTTP). You should leave it like + /// this unless you really need a port other than the + /// standard one, or use an unknown protocol. + /// + /// \param host Web server to connect to + /// \param port Port to use for connection + /// + //////////////////////////////////////////////////////////// + Http(const std::string& host, unsigned short port = 0); + + //////////////////////////////////////////////////////////// + /// \brief Set the target host + /// + /// This function just stores the host address and port, it + /// doesn't actually connect to it until you send a request. + /// The port has a default value of 0, which means that the + /// HTTP client will use the right port according to the + /// protocol used (80 for HTTP). You should leave it like + /// this unless you really need a port other than the + /// standard one, or use an unknown protocol. + /// + /// \param host Web server to connect to + /// \param port Port to use for connection + /// + //////////////////////////////////////////////////////////// + void setHost(const std::string& host, unsigned short port = 0); + + //////////////////////////////////////////////////////////// + /// \brief Send a HTTP request and return the server's response. + /// + /// You must have a valid host before sending a request (see setHost). + /// Any missing mandatory header field in the request will be added + /// with an appropriate value. + /// Warning: this function waits for the server's response and may + /// not return instantly; use a thread if you don't want to block your + /// application, or use a timeout to limit the time to wait. A value + /// of Time::Zero means that the client will use the system default timeout + /// (which is usually pretty long). + /// + /// \param request Request to send + /// \param timeout Maximum time to wait + /// + /// \return Server's response + /// + //////////////////////////////////////////////////////////// + Response sendRequest(const Request& request, Time timeout = Time::Zero); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + TcpSocket m_connection; ///< Connection to the host + IpAddress m_host; ///< Web host address + std::string m_hostName; ///< Web host name + unsigned short m_port; ///< Port used for connection with host +}; + +} // namespace sf + + +#endif // SFML_HTTP_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Http +/// \ingroup network +/// +/// sf::Http is a very simple HTTP client that allows you +/// to communicate with a web server. You can retrieve +/// web pages, send data to an interactive resource, +/// download a remote file, etc. The HTTPS protocol is +/// not supported. +/// +/// The HTTP client is split into 3 classes: +/// \li sf::Http::Request +/// \li sf::Http::Response +/// \li sf::Http +/// +/// sf::Http::Request builds the request that will be +/// sent to the server. A request is made of: +/// \li a method (what you want to do) +/// \li a target URI (usually the name of the web page or file) +/// \li one or more header fields (options that you can pass to the server) +/// \li an optional body (for POST requests) +/// +/// sf::Http::Response parse the response from the web server +/// and provides getters to read them. The response contains: +/// \li a status code +/// \li header fields (that may be answers to the ones that you requested) +/// \li a body, which contains the contents of the requested resource +/// +/// sf::Http provides a simple function, SendRequest, to send a +/// sf::Http::Request and return the corresponding sf::Http::Response +/// from the server. +/// +/// Usage example: +/// \code +/// // Create a new HTTP client +/// sf::Http http; +/// +/// // We'll work on http://www.sfml-dev.org +/// http.setHost("http://www.sfml-dev.org"); +/// +/// // Prepare a request to get the 'features.php' page +/// sf::Http::Request request("features.php"); +/// +/// // Send the request +/// sf::Http::Response response = http.sendRequest(request); +/// +/// // Check the status code and display the result +/// sf::Http::Response::Status status = response.getStatus(); +/// if (status == sf::Http::Response::Ok) +/// { +/// std::cout << response.getBody() << std::endl; +/// } +/// else +/// { +/// std::cout << "Error " << status << std::endl; +/// } +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/IpAddress.hpp b/include/SFML/Network/IpAddress.hpp new file mode 100644 index 0000000..b6852a2 --- /dev/null +++ b/include/SFML/Network/IpAddress.hpp @@ -0,0 +1,328 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_IPADDRESS_HPP +#define SFML_IPADDRESS_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Encapsulate an IPv4 network address +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API IpAddress +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor creates an empty (invalid) address + /// + //////////////////////////////////////////////////////////// + IpAddress(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the address from a string + /// + /// Here \a address can be either a decimal address + /// (ex: "192.168.1.56") or a network name (ex: "localhost"). + /// + /// \param address IP address or network name + /// + //////////////////////////////////////////////////////////// + IpAddress(const std::string& address); + + //////////////////////////////////////////////////////////// + /// \brief Construct the address from a string + /// + /// Here \a address can be either a decimal address + /// (ex: "192.168.1.56") or a network name (ex: "localhost"). + /// This is equivalent to the constructor taking a std::string + /// parameter, it is defined for convenience so that the + /// implicit conversions from literal strings to IpAddress work. + /// + /// \param address IP address or network name + /// + //////////////////////////////////////////////////////////// + IpAddress(const char* address); + + //////////////////////////////////////////////////////////// + /// \brief Construct the address from 4 bytes + /// + /// Calling IpAddress(a, b, c, d) is equivalent to calling + /// IpAddress("a.b.c.d"), but safer as it doesn't have to + /// parse a string to get the address components. + /// + /// \param byte0 First byte of the address + /// \param byte1 Second byte of the address + /// \param byte2 Third byte of the address + /// \param byte3 Fourth byte of the address + /// + //////////////////////////////////////////////////////////// + IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3); + + //////////////////////////////////////////////////////////// + /// \brief Construct the address from a 32-bits integer + /// + /// This constructor uses the internal representation of + /// the address directly. It should be used for optimization + /// purposes, and only if you got that representation from + /// IpAddress::toInteger(). + /// + /// \param address 4 bytes of the address packed into a 32-bits integer + /// + /// \see toInteger + /// + //////////////////////////////////////////////////////////// + explicit IpAddress(Uint32 address); + + //////////////////////////////////////////////////////////// + /// \brief Get a string representation of the address + /// + /// The returned string is the decimal representation of the + /// IP address (like "192.168.1.56"), even if it was constructed + /// from a host name. + /// + /// \return String representation of the address + /// + /// \see toInteger + /// + //////////////////////////////////////////////////////////// + std::string toString() const; + + //////////////////////////////////////////////////////////// + /// \brief Get an integer representation of the address + /// + /// The returned number is the internal representation of the + /// address, and should be used for optimization purposes only + /// (like sending the address through a socket). + /// The integer produced by this function can then be converted + /// back to a sf::IpAddress with the proper constructor. + /// + /// \return 32-bits unsigned integer representation of the address + /// + /// \see toString + /// + //////////////////////////////////////////////////////////// + Uint32 toInteger() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the computer's local address + /// + /// The local address is the address of the computer from the + /// LAN point of view, i.e. something like 192.168.1.56. It is + /// meaningful only for communications over the local network. + /// Unlike getPublicAddress, this function is fast and may be + /// used safely anywhere. + /// + /// \return Local IP address of the computer + /// + /// \see getPublicAddress + /// + //////////////////////////////////////////////////////////// + static IpAddress getLocalAddress(); + + //////////////////////////////////////////////////////////// + /// \brief Get the computer's public address + /// + /// The public address is the address of the computer from the + /// internet point of view, i.e. something like 89.54.1.169. + /// It is necessary for communications over the world wide web. + /// The only way to get a public address is to ask it to a + /// distant website; as a consequence, this function depends on + /// both your network connection and the server, and may be + /// very slow. You should use it as few as possible. Because + /// this function depends on the network connection and on a distant + /// server, you may use a time limit if you don't want your program + /// to be possibly stuck waiting in case there is a problem; this + /// limit is deactivated by default. + /// + /// \param timeout Maximum time to wait + /// + /// \return Public IP address of the computer + /// + /// \see getLocalAddress + /// + //////////////////////////////////////////////////////////// + static IpAddress getPublicAddress(Time timeout = Time::Zero); + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const IpAddress None; ///< Value representing an empty/invalid address + static const IpAddress Any; ///< Value representing any address (0.0.0.0) + static const IpAddress LocalHost; ///< The "localhost" address (for connecting a computer to itself locally) + static const IpAddress Broadcast; ///< The "broadcast" address (for sending UDP messages to everyone on a local network) + +private: + + friend SFML_NETWORK_API bool operator <(const IpAddress& left, const IpAddress& right); + + //////////////////////////////////////////////////////////// + /// \brief Resolve the given address string + /// + /// \param address Address string + /// + //////////////////////////////////////////////////////////// + void resolve(const std::string& address); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Uint32 m_address; ///< Address stored as an unsigned 32 bits integer + bool m_valid; ///< Is the address valid? +}; + +//////////////////////////////////////////////////////////// +/// \brief Overload of == operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if both addresses are equal +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator ==(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of != operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if both addresses are different +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator !=(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of < operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if \a left is lesser than \a right +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator <(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of > operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if \a left is greater than \a right +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator >(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of <= operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if \a left is lesser or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator <=(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of >= operator to compare two IP addresses +/// +/// \param left Left operand (a IP address) +/// \param right Right operand (a IP address) +/// +/// \return True if \a left is greater or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API bool operator >=(const IpAddress& left, const IpAddress& right); + +//////////////////////////////////////////////////////////// +/// \brief Overload of >> operator to extract an IP address from an input stream +/// +/// \param stream Input stream +/// \param address IP address to extract +/// +/// \return Reference to the input stream +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API std::istream& operator >>(std::istream& stream, IpAddress& address); + +//////////////////////////////////////////////////////////// +/// \brief Overload of << operator to print an IP address to an output stream +/// +/// \param stream Output stream +/// \param address IP address to print +/// +/// \return Reference to the output stream +/// +//////////////////////////////////////////////////////////// +SFML_NETWORK_API std::ostream& operator <<(std::ostream& stream, const IpAddress& address); + +} // namespace sf + + +#endif // SFML_IPADDRESS_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::IpAddress +/// \ingroup network +/// +/// sf::IpAddress is a utility class for manipulating network +/// addresses. It provides a set a implicit constructors and +/// conversion functions to easily build or transform an IP +/// address from/to various representations. +/// +/// Usage example: +/// \code +/// sf::IpAddress a0; // an invalid address +/// sf::IpAddress a1 = sf::IpAddress::None; // an invalid address (same as a0) +/// sf::IpAddress a2("127.0.0.1"); // the local host address +/// sf::IpAddress a3 = sf::IpAddress::Broadcast; // the broadcast address +/// sf::IpAddress a4(192, 168, 1, 56); // a local address +/// sf::IpAddress a5("my_computer"); // a local address created from a network name +/// sf::IpAddress a6("89.54.1.169"); // a distant address +/// sf::IpAddress a7("www.google.com"); // a distant address created from a network name +/// sf::IpAddress a8 = sf::IpAddress::getLocalAddress(); // my address on the local network +/// sf::IpAddress a9 = sf::IpAddress::getPublicAddress(); // my address on the internet +/// \endcode +/// +/// Note that sf::IpAddress currently doesn't support IPv6 +/// nor other types of network addresses. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Packet.hpp b/include/SFML/Network/Packet.hpp new file mode 100644 index 0000000..7810c2e --- /dev/null +++ b/include/SFML/Network/Packet.hpp @@ -0,0 +1,412 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_PACKET_HPP +#define SFML_PACKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class String; +class TcpSocket; +class UdpSocket; + +//////////////////////////////////////////////////////////// +/// \brief Utility class to build blocks of data to transfer +/// over the network +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API Packet +{ + // A bool-like type that cannot be converted to integer or pointer types + typedef bool (Packet::*BoolType)(std::size_t); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty packet. + /// + //////////////////////////////////////////////////////////// + Packet(); + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Packet(); + + //////////////////////////////////////////////////////////// + /// \brief Append data to the end of the packet + /// + /// \param data Pointer to the sequence of bytes to append + /// \param sizeInBytes Number of bytes to append + /// + /// \see clear + /// + //////////////////////////////////////////////////////////// + void append(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Clear the packet + /// + /// After calling Clear, the packet is empty. + /// + /// \see append + /// + //////////////////////////////////////////////////////////// + void clear(); + + //////////////////////////////////////////////////////////// + /// \brief Get a pointer to the data contained in the packet + /// + /// Warning: the returned pointer may become invalid after + /// you append data to the packet, therefore it should never + /// be stored. + /// The return pointer is NULL if the packet is empty. + /// + /// \return Pointer to the data + /// + /// \see getDataSize + /// + //////////////////////////////////////////////////////////// + const void* getData() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the data contained in the packet + /// + /// This function returns the number of bytes pointed to by + /// what getData returns. + /// + /// \return Data size, in bytes + /// + /// \see getData + /// + //////////////////////////////////////////////////////////// + std::size_t getDataSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Tell if the reading position has reached the + /// end of the packet + /// + /// This function is useful to know if there is some data + /// left to be read, without actually reading it. + /// + /// \return True if all data was read, false otherwise + /// + /// \see operator bool + /// + //////////////////////////////////////////////////////////// + bool endOfPacket() const; + +public: + + //////////////////////////////////////////////////////////// + /// \brief Test the validity of the packet, for reading + /// + /// This operator allows to test the packet as a boolean + /// variable, to check if a reading operation was successful. + /// + /// A packet will be in an invalid state if it has no more + /// data to read. + /// + /// This behavior is the same as standard C++ streams. + /// + /// Usage example: + /// \code + /// float x; + /// packet >> x; + /// if (packet) + /// { + /// // ok, x was extracted successfully + /// } + /// + /// // -- or -- + /// + /// float x; + /// if (packet >> x) + /// { + /// // ok, x was extracted successfully + /// } + /// \endcode + /// + /// Don't focus on the return type, it's equivalent to bool but + /// it disallows unwanted implicit conversions to integer or + /// pointer types. + /// + /// \return True if last data extraction from packet was successful + /// + /// \see endOfPacket + /// + //////////////////////////////////////////////////////////// + operator BoolType() const; + + //////////////////////////////////////////////////////////// + /// Overloads of operator >> to read data from the packet + /// + //////////////////////////////////////////////////////////// + Packet& operator >>(bool& data); + Packet& operator >>(Int8& data); + Packet& operator >>(Uint8& data); + Packet& operator >>(Int16& data); + Packet& operator >>(Uint16& data); + Packet& operator >>(Int32& data); + Packet& operator >>(Uint32& data); + Packet& operator >>(Int64& data); + Packet& operator >>(Uint64& data); + Packet& operator >>(float& data); + Packet& operator >>(double& data); + Packet& operator >>(char* data); + Packet& operator >>(std::string& data); + Packet& operator >>(wchar_t* data); + Packet& operator >>(std::wstring& data); + Packet& operator >>(String& data); + + //////////////////////////////////////////////////////////// + /// Overloads of operator << to write data into the packet + /// + //////////////////////////////////////////////////////////// + Packet& operator <<(bool data); + Packet& operator <<(Int8 data); + Packet& operator <<(Uint8 data); + Packet& operator <<(Int16 data); + Packet& operator <<(Uint16 data); + Packet& operator <<(Int32 data); + Packet& operator <<(Uint32 data); + Packet& operator <<(Int64 data); + Packet& operator <<(Uint64 data); + Packet& operator <<(float data); + Packet& operator <<(double data); + Packet& operator <<(const char* data); + Packet& operator <<(const std::string& data); + Packet& operator <<(const wchar_t* data); + Packet& operator <<(const std::wstring& data); + Packet& operator <<(const String& data); + +protected: + + friend class TcpSocket; + friend class UdpSocket; + + //////////////////////////////////////////////////////////// + /// \brief Called before the packet is sent over the network + /// + /// This function can be defined by derived classes to + /// transform the data before it is sent; this can be + /// used for compression, encryption, etc. + /// The function must return a pointer to the modified data, + /// as well as the number of bytes pointed. + /// The default implementation provides the packet's data + /// without transforming it. + /// + /// \param size Variable to fill with the size of data to send + /// + /// \return Pointer to the array of bytes to send + /// + /// \see onReceive + /// + //////////////////////////////////////////////////////////// + virtual const void* onSend(std::size_t& size); + + //////////////////////////////////////////////////////////// + /// \brief Called after the packet is received over the network + /// + /// This function can be defined by derived classes to + /// transform the data after it is received; this can be + /// used for decompression, decryption, etc. + /// The function receives a pointer to the received data, + /// and must fill the packet with the transformed bytes. + /// The default implementation fills the packet directly + /// without transforming the data. + /// + /// \param data Pointer to the received bytes + /// \param size Number of bytes + /// + /// \see onSend + /// + //////////////////////////////////////////////////////////// + virtual void onReceive(const void* data, std::size_t size); + +private: + + //////////////////////////////////////////////////////////// + /// Disallow comparisons between packets + /// + //////////////////////////////////////////////////////////// + bool operator ==(const Packet& right) const; + bool operator !=(const Packet& right) const; + + //////////////////////////////////////////////////////////// + /// \brief Check if the packet can extract a given number of bytes + /// + /// This function updates accordingly the state of the packet. + /// + /// \param size Size to check + /// + /// \return True if \a size bytes can be read from the packet + /// + //////////////////////////////////////////////////////////// + bool checkSize(std::size_t size); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_data; ///< Data stored in the packet + std::size_t m_readPos; ///< Current reading position in the packet + std::size_t m_sendPos; ///< Current send position in the packet (for handling partial sends) + bool m_isValid; ///< Reading state of the packet +}; + +} // namespace sf + + +#endif // SFML_PACKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Packet +/// \ingroup network +/// +/// Packets provide a safe and easy way to serialize data, +/// in order to send it over the network using sockets +/// (sf::TcpSocket, sf::UdpSocket). +/// +/// Packets solve 2 fundamental problems that arise when +/// transferring data over the network: +/// \li data is interpreted correctly according to the endianness +/// \li the bounds of the packet are preserved (one send == one receive) +/// +/// The sf::Packet class provides both input and output modes. +/// It is designed to follow the behavior of standard C++ streams, +/// using operators >> and << to extract and insert data. +/// +/// It is recommended to use only fixed-size types (like sf::Int32, etc.), +/// to avoid possible differences between the sender and the receiver. +/// Indeed, the native C++ types may have different sizes on two platforms +/// and your data may be corrupted if that happens. +/// +/// Usage example: +/// \code +/// sf::Uint32 x = 24; +/// std::string s = "hello"; +/// double d = 5.89; +/// +/// // Group the variables to send into a packet +/// sf::Packet packet; +/// packet << x << s << d; +/// +/// // Send it over the network (socket is a valid sf::TcpSocket) +/// socket.send(packet); +/// +/// ----------------------------------------------------------------- +/// +/// // Receive the packet at the other end +/// sf::Packet packet; +/// socket.receive(packet); +/// +/// // Extract the variables contained in the packet +/// sf::Uint32 x; +/// std::string s; +/// double d; +/// if (packet >> x >> s >> d) +/// { +/// // Data extracted successfully... +/// } +/// \endcode +/// +/// Packets have built-in operator >> and << overloads for +/// standard types: +/// \li bool +/// \li fixed-size integer types (sf::Int8/16/32, sf::Uint8/16/32) +/// \li floating point numbers (float, double) +/// \li string types (char*, wchar_t*, std::string, std::wstring, sf::String) +/// +/// Like standard streams, it is also possible to define your own +/// overloads of operators >> and << in order to handle your +/// custom types. +/// +/// \code +/// struct MyStruct +/// { +/// float number; +/// sf::Int8 integer; +/// std::string str; +/// }; +/// +/// sf::Packet& operator <<(sf::Packet& packet, const MyStruct& m) +/// { +/// return packet << m.number << m.integer << m.str; +/// } +/// +/// sf::Packet& operator >>(sf::Packet& packet, MyStruct& m) +/// { +/// return packet >> m.number >> m.integer >> m.str; +/// } +/// \endcode +/// +/// Packets also provide an extra feature that allows to apply +/// custom transformations to the data before it is sent, +/// and after it is received. This is typically used to +/// handle automatic compression or encryption of the data. +/// This is achieved by inheriting from sf::Packet, and overriding +/// the onSend and onReceive functions. +/// +/// Here is an example: +/// \code +/// class ZipPacket : public sf::Packet +/// { +/// virtual const void* onSend(std::size_t& size) +/// { +/// const void* srcData = getData(); +/// std::size_t srcSize = getDataSize(); +/// +/// return MySuperZipFunction(srcData, srcSize, &size); +/// } +/// +/// virtual void onReceive(const void* data, std::size_t size) +/// { +/// std::size_t dstSize; +/// const void* dstData = MySuperUnzipFunction(data, size, &dstSize); +/// +/// append(dstData, dstSize); +/// } +/// }; +/// +/// // Use like regular packets: +/// ZipPacket packet; +/// packet << x << s << d; +/// ... +/// \endcode +/// +/// \see sf::TcpSocket, sf::UdpSocket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Socket.hpp b/include/SFML/Network/Socket.hpp new file mode 100644 index 0000000..57d58f7 --- /dev/null +++ b/include/SFML/Network/Socket.hpp @@ -0,0 +1,219 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKET_HPP +#define SFML_SOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +class SocketSelector; + +//////////////////////////////////////////////////////////// +/// \brief Base class for all the socket types +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API Socket : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Status codes that may be returned by socket functions + /// + //////////////////////////////////////////////////////////// + enum Status + { + Done, ///< The socket has sent / received the data + NotReady, ///< The socket is not ready to send / receive data yet + Partial, ///< The socket sent a part of the data + Disconnected, ///< The TCP socket has been disconnected + Error ///< An unexpected error happened + }; + + //////////////////////////////////////////////////////////// + /// \brief Some special values used by sockets + /// + //////////////////////////////////////////////////////////// + enum + { + AnyPort = 0 ///< Special value that tells the system to pick any available port + }; + +public: + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Socket(); + + //////////////////////////////////////////////////////////// + /// \brief Set the blocking state of the socket + /// + /// In blocking mode, calls will not return until they have + /// completed their task. For example, a call to Receive in + /// blocking mode won't return until some data was actually + /// received. + /// In non-blocking mode, calls will always return immediately, + /// using the return code to signal whether there was data + /// available or not. + /// By default, all sockets are blocking. + /// + /// \param blocking True to set the socket as blocking, false for non-blocking + /// + /// \see isBlocking + /// + //////////////////////////////////////////////////////////// + void setBlocking(bool blocking); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the socket is in blocking or non-blocking mode + /// + /// \return True if the socket is blocking, false otherwise + /// + /// \see setBlocking + /// + //////////////////////////////////////////////////////////// + bool isBlocking() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Types of protocols that the socket can use + /// + //////////////////////////////////////////////////////////// + enum Type + { + Tcp, ///< TCP protocol + Udp ///< UDP protocol + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor can only be accessed by derived classes. + /// + /// \param type Type of the socket (TCP or UDP) + /// + //////////////////////////////////////////////////////////// + Socket(Type type); + + //////////////////////////////////////////////////////////// + /// \brief Return the internal handle of the socket + /// + /// The returned handle may be invalid if the socket + /// was not created yet (or already destroyed). + /// This function can only be accessed by derived classes. + /// + /// \return The internal (OS-specific) handle of the socket + /// + //////////////////////////////////////////////////////////// + SocketHandle getHandle() const; + + //////////////////////////////////////////////////////////// + /// \brief Create the internal representation of the socket + /// + /// This function can only be accessed by derived classes. + /// + //////////////////////////////////////////////////////////// + void create(); + + //////////////////////////////////////////////////////////// + /// \brief Create the internal representation of the socket + /// from a socket handle + /// + /// This function can only be accessed by derived classes. + /// + /// \param handle OS-specific handle of the socket to wrap + /// + //////////////////////////////////////////////////////////// + void create(SocketHandle handle); + + //////////////////////////////////////////////////////////// + /// \brief Close the socket gracefully + /// + /// This function can only be accessed by derived classes. + /// + //////////////////////////////////////////////////////////// + void close(); + +private: + + friend class SocketSelector; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Type m_type; ///< Type of the socket (TCP or UDP) + SocketHandle m_socket; ///< Socket descriptor + bool m_isBlocking; ///< Current blocking mode of the socket +}; + +} // namespace sf + + +#endif // SFML_SOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Socket +/// \ingroup network +/// +/// This class mainly defines internal stuff to be used by +/// derived classes. +/// +/// The only public features that it defines, and which +/// is therefore common to all the socket classes, is the +/// blocking state. All sockets can be set as blocking or +/// non-blocking. +/// +/// In blocking mode, socket functions will hang until +/// the operation completes, which means that the entire +/// program (well, in fact the current thread if you use +/// multiple ones) will be stuck waiting for your socket +/// operation to complete. +/// +/// In non-blocking mode, all the socket functions will +/// return immediately. If the socket is not ready to complete +/// the requested operation, the function simply returns +/// the proper status code (Socket::NotReady). +/// +/// The default mode, which is blocking, is the one that is +/// generally used, in combination with threads or selectors. +/// The non-blocking mode is rather used in real-time +/// applications that run an endless loop that can poll +/// the socket often enough, and cannot afford blocking +/// this loop. +/// +/// \see sf::TcpListener, sf::TcpSocket, sf::UdpSocket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/SocketHandle.hpp b/include/SFML/Network/SocketHandle.hpp new file mode 100644 index 0000000..5faef7a --- /dev/null +++ b/include/SFML/Network/SocketHandle.hpp @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETHANDLE_HPP +#define SFML_SOCKETHANDLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + +#if defined(SFML_SYSTEM_WINDOWS) + #include +#endif + + +namespace sf +{ +//////////////////////////////////////////////////////////// +// Define the low-level socket handle type, specific to +// each platform +//////////////////////////////////////////////////////////// +#if defined(SFML_SYSTEM_WINDOWS) + + typedef UINT_PTR SocketHandle; + +#else + + typedef int SocketHandle; + +#endif + +} // namespace sf + + +#endif // SFML_SOCKETHANDLE_HPP diff --git a/include/SFML/Network/SocketSelector.hpp b/include/SFML/Network/SocketSelector.hpp new file mode 100644 index 0000000..13f9665 --- /dev/null +++ b/include/SFML/Network/SocketSelector.hpp @@ -0,0 +1,263 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETSELECTOR_HPP +#define SFML_SOCKETSELECTOR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Socket; + +//////////////////////////////////////////////////////////// +/// \brief Multiplexer that allows to read from multiple sockets +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API SocketSelector +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SocketSelector(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SocketSelector(const SocketSelector& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SocketSelector(); + + //////////////////////////////////////////////////////////// + /// \brief Add a new socket to the selector + /// + /// This function keeps a weak reference to the socket, + /// so you have to make sure that the socket is not destroyed + /// while it is stored in the selector. + /// This function does nothing if the socket is not valid. + /// + /// \param socket Reference to the socket to add + /// + /// \see remove, clear + /// + //////////////////////////////////////////////////////////// + void add(Socket& socket); + + //////////////////////////////////////////////////////////// + /// \brief Remove a socket from the selector + /// + /// This function doesn't destroy the socket, it simply + /// removes the reference that the selector has to it. + /// + /// \param socket Reference to the socket to remove + /// + /// \see add, clear + /// + //////////////////////////////////////////////////////////// + void remove(Socket& socket); + + //////////////////////////////////////////////////////////// + /// \brief Remove all the sockets stored in the selector + /// + /// This function doesn't destroy any instance, it simply + /// removes all the references that the selector has to + /// external sockets. + /// + /// \see add, remove + /// + //////////////////////////////////////////////////////////// + void clear(); + + //////////////////////////////////////////////////////////// + /// \brief Wait until one or more sockets are ready to receive + /// + /// This function returns as soon as at least one socket has + /// some data available to be received. To know which sockets are + /// ready, use the isReady function. + /// If you use a timeout and no socket is ready before the timeout + /// is over, the function returns false. + /// + /// \param timeout Maximum time to wait, (use Time::Zero for infinity) + /// + /// \return True if there are sockets ready, false otherwise + /// + /// \see isReady + /// + //////////////////////////////////////////////////////////// + bool wait(Time timeout = Time::Zero); + + //////////////////////////////////////////////////////////// + /// \brief Test a socket to know if it is ready to receive data + /// + /// This function must be used after a call to Wait, to know + /// which sockets are ready to receive data. If a socket is + /// ready, a call to receive will never block because we know + /// that there is data available to read. + /// Note that if this function returns true for a TcpListener, + /// this means that it is ready to accept a new connection. + /// + /// \param socket Socket to test + /// + /// \return True if the socket is ready to read, false otherwise + /// + /// \see isReady + /// + //////////////////////////////////////////////////////////// + bool isReady(Socket& socket) const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + SocketSelector& operator =(const SocketSelector& right); + +private: + + struct SocketSelectorImpl; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketSelectorImpl* m_impl; ///< Opaque pointer to the implementation (which requires OS-specific types) +}; + +} // namespace sf + + +#endif // SFML_SOCKETSELECTOR_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SocketSelector +/// \ingroup network +/// +/// Socket selectors provide a way to wait until some data is +/// available on a set of sockets, instead of just one. This +/// is convenient when you have multiple sockets that may +/// possibly receive data, but you don't know which one will +/// be ready first. In particular, it avoids to use a thread +/// for each socket; with selectors, a single thread can handle +/// all the sockets. +/// +/// All types of sockets can be used in a selector: +/// \li sf::TcpListener +/// \li sf::TcpSocket +/// \li sf::UdpSocket +/// +/// A selector doesn't store its own copies of the sockets +/// (socket classes are not copyable anyway), it simply keeps +/// a reference to the original sockets that you pass to the +/// "add" function. Therefore, you can't use the selector as a +/// socket container, you must store them outside and make sure +/// that they are alive as long as they are used in the selector. +/// +/// Using a selector is simple: +/// \li populate the selector with all the sockets that you want to observe +/// \li make it wait until there is data available on any of the sockets +/// \li test each socket to find out which ones are ready +/// +/// Usage example: +/// \code +/// // Create a socket to listen to new connections +/// sf::TcpListener listener; +/// listener.listen(55001); +/// +/// // Create a list to store the future clients +/// std::list clients; +/// +/// // Create a selector +/// sf::SocketSelector selector; +/// +/// // Add the listener to the selector +/// selector.add(listener); +/// +/// // Endless loop that waits for new connections +/// while (running) +/// { +/// // Make the selector wait for data on any socket +/// if (selector.wait()) +/// { +/// // Test the listener +/// if (selector.isReady(listener)) +/// { +/// // The listener is ready: there is a pending connection +/// sf::TcpSocket* client = new sf::TcpSocket; +/// if (listener.accept(*client) == sf::Socket::Done) +/// { +/// // Add the new client to the clients list +/// clients.push_back(client); +/// +/// // Add the new client to the selector so that we will +/// // be notified when he sends something +/// selector.add(*client); +/// } +/// else +/// { +/// // Error, we won't get a new connection, delete the socket +/// delete client; +/// } +/// } +/// else +/// { +/// // The listener socket is not ready, test all other sockets (the clients) +/// for (std::list::iterator it = clients.begin(); it != clients.end(); ++it) +/// { +/// sf::TcpSocket& client = **it; +/// if (selector.isReady(client)) +/// { +/// // The client has sent some data, we can receive it +/// sf::Packet packet; +/// if (client.receive(packet) == sf::Socket::Done) +/// { +/// ... +/// } +/// } +/// } +/// } +/// } +/// } +/// \endcode +/// +/// \see sf::Socket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/TcpListener.hpp b/include/SFML/Network/TcpListener.hpp new file mode 100644 index 0000000..1115eef --- /dev/null +++ b/include/SFML/Network/TcpListener.hpp @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TCPLISTENER_HPP +#define SFML_TCPLISTENER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class TcpSocket; + +//////////////////////////////////////////////////////////// +/// \brief Socket that listens to new TCP connections +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API TcpListener : public Socket +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TcpListener(); + + //////////////////////////////////////////////////////////// + /// \brief Get the port to which the socket is bound locally + /// + /// If the socket is not listening to a port, this function + /// returns 0. + /// + /// \return Port to which the socket is bound + /// + /// \see listen + /// + //////////////////////////////////////////////////////////// + unsigned short getLocalPort() const; + + //////////////////////////////////////////////////////////// + /// \brief Start listening for connections + /// + /// This functions makes the socket listen to the specified + /// port, waiting for new connections. + /// If the socket was previously listening to another port, + /// it will be stopped first and bound to the new port. + /// + /// \param port Port to listen for new connections + /// \param address Address of the interface to listen on + /// + /// \return Status code + /// + /// \see accept, close + /// + //////////////////////////////////////////////////////////// + Status listen(unsigned short port, const IpAddress& address = IpAddress::Any); + + //////////////////////////////////////////////////////////// + /// \brief Stop listening and close the socket + /// + /// This function gracefully stops the listener. If the + /// socket is not listening, this function has no effect. + /// + /// \see listen + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + /// \brief Accept a new connection + /// + /// If the socket is in blocking mode, this function will + /// not return until a connection is actually received. + /// + /// \param socket Socket that will hold the new connection + /// + /// \return Status code + /// + /// \see listen + /// + //////////////////////////////////////////////////////////// + Status accept(TcpSocket& socket); +}; + + +} // namespace sf + + +#endif // SFML_TCPLISTENER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::TcpListener +/// \ingroup network +/// +/// A listener socket is a special type of socket that listens to +/// a given port and waits for connections on that port. +/// This is all it can do. +/// +/// When a new connection is received, you must call accept and +/// the listener returns a new instance of sf::TcpSocket that +/// is properly initialized and can be used to communicate with +/// the new client. +/// +/// Listener sockets are specific to the TCP protocol, +/// UDP sockets are connectionless and can therefore communicate +/// directly. As a consequence, a listener socket will always +/// return the new connections as sf::TcpSocket instances. +/// +/// A listener is automatically closed on destruction, like all +/// other types of socket. However if you want to stop listening +/// before the socket is destroyed, you can call its close() +/// function. +/// +/// Usage example: +/// \code +/// // Create a listener socket and make it wait for new +/// // connections on port 55001 +/// sf::TcpListener listener; +/// listener.listen(55001); +/// +/// // Endless loop that waits for new connections +/// while (running) +/// { +/// sf::TcpSocket client; +/// if (listener.accept(client) == sf::Socket::Done) +/// { +/// // A new client just connected! +/// std::cout << "New connection received from " << client.getRemoteAddress() << std::endl; +/// doSomethingWith(client); +/// } +/// } +/// \endcode +/// +/// \see sf::TcpSocket, sf::Socket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/TcpSocket.hpp b/include/SFML/Network/TcpSocket.hpp new file mode 100644 index 0000000..012cca0 --- /dev/null +++ b/include/SFML/Network/TcpSocket.hpp @@ -0,0 +1,315 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TCPSOCKET_HPP +#define SFML_TCPSOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class TcpListener; +class IpAddress; +class Packet; + +//////////////////////////////////////////////////////////// +/// \brief Specialized socket using the TCP protocol +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API TcpSocket : public Socket +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TcpSocket(); + + //////////////////////////////////////////////////////////// + /// \brief Get the port to which the socket is bound locally + /// + /// If the socket is not connected, this function returns 0. + /// + /// \return Port to which the socket is bound + /// + /// \see connect, getRemotePort + /// + //////////////////////////////////////////////////////////// + unsigned short getLocalPort() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the address of the connected peer + /// + /// It the socket is not connected, this function returns + /// sf::IpAddress::None. + /// + /// \return Address of the remote peer + /// + /// \see getRemotePort + /// + //////////////////////////////////////////////////////////// + IpAddress getRemoteAddress() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the port of the connected peer to which + /// the socket is connected + /// + /// If the socket is not connected, this function returns 0. + /// + /// \return Remote port to which the socket is connected + /// + /// \see getRemoteAddress + /// + //////////////////////////////////////////////////////////// + unsigned short getRemotePort() const; + + //////////////////////////////////////////////////////////// + /// \brief Connect the socket to a remote peer + /// + /// In blocking mode, this function may take a while, especially + /// if the remote peer is not reachable. The last parameter allows + /// you to stop trying to connect after a given timeout. + /// If the socket was previously connected, it is first disconnected. + /// + /// \param remoteAddress Address of the remote peer + /// \param remotePort Port of the remote peer + /// \param timeout Optional maximum time to wait + /// + /// \return Status code + /// + /// \see disconnect + /// + //////////////////////////////////////////////////////////// + Status connect(const IpAddress& remoteAddress, unsigned short remotePort, Time timeout = Time::Zero); + + //////////////////////////////////////////////////////////// + /// \brief Disconnect the socket from its remote peer + /// + /// This function gracefully closes the connection. If the + /// socket is not connected, this function has no effect. + /// + /// \see connect + /// + //////////////////////////////////////////////////////////// + void disconnect(); + + //////////////////////////////////////////////////////////// + /// \brief Send raw data to the remote peer + /// + /// To be able to handle partial sends over non-blocking + /// sockets, use the send(const void*, std::size_t, std::size_t&) + /// overload instead. + /// This function will fail if the socket is not connected. + /// + /// \param data Pointer to the sequence of bytes to send + /// \param size Number of bytes to send + /// + /// \return Status code + /// + /// \see receive + /// + //////////////////////////////////////////////////////////// + Status send(const void* data, std::size_t size); + + //////////////////////////////////////////////////////////// + /// \brief Send raw data to the remote peer + /// + /// This function will fail if the socket is not connected. + /// + /// \param data Pointer to the sequence of bytes to send + /// \param size Number of bytes to send + /// \param sent The number of bytes sent will be written here + /// + /// \return Status code + /// + /// \see receive + /// + //////////////////////////////////////////////////////////// + Status send(const void* data, std::size_t size, std::size_t& sent); + + //////////////////////////////////////////////////////////// + /// \brief Receive raw data from the remote peer + /// + /// In blocking mode, this function will wait until some + /// bytes are actually received. + /// This function will fail if the socket is not connected. + /// + /// \param data Pointer to the array to fill with the received bytes + /// \param size Maximum number of bytes that can be received + /// \param received This variable is filled with the actual number of bytes received + /// + /// \return Status code + /// + /// \see send + /// + //////////////////////////////////////////////////////////// + Status receive(void* data, std::size_t size, std::size_t& received); + + //////////////////////////////////////////////////////////// + /// \brief Send a formatted packet of data to the remote peer + /// + /// In non-blocking mode, if this function returns sf::Socket::Partial, + /// you \em must retry sending the same unmodified packet before sending + /// anything else in order to guarantee the packet arrives at the remote + /// peer uncorrupted. + /// This function will fail if the socket is not connected. + /// + /// \param packet Packet to send + /// + /// \return Status code + /// + /// \see receive + /// + //////////////////////////////////////////////////////////// + Status send(Packet& packet); + + //////////////////////////////////////////////////////////// + /// \brief Receive a formatted packet of data from the remote peer + /// + /// In blocking mode, this function will wait until the whole packet + /// has been received. + /// This function will fail if the socket is not connected. + /// + /// \param packet Packet to fill with the received data + /// + /// \return Status code + /// + /// \see send + /// + //////////////////////////////////////////////////////////// + Status receive(Packet& packet); + +private: + + friend class TcpListener; + + //////////////////////////////////////////////////////////// + /// \brief Structure holding the data of a pending packet + /// + //////////////////////////////////////////////////////////// + struct PendingPacket + { + PendingPacket(); + + Uint32 Size; ///< Data of packet size + std::size_t SizeReceived; ///< Number of size bytes received so far + std::vector Data; ///< Data of the packet + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + PendingPacket m_pendingPacket; ///< Temporary data of the packet currently being received +}; + +} // namespace sf + + +#endif // SFML_TCPSOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::TcpSocket +/// \ingroup network +/// +/// TCP is a connected protocol, which means that a TCP +/// socket can only communicate with the host it is connected +/// to. It can't send or receive anything if it is not connected. +/// +/// The TCP protocol is reliable but adds a slight overhead. +/// It ensures that your data will always be received in order +/// and without errors (no data corrupted, lost or duplicated). +/// +/// When a socket is connected to a remote host, you can +/// retrieve informations about this host with the +/// getRemoteAddress and getRemotePort functions. You can +/// also get the local port to which the socket is bound +/// (which is automatically chosen when the socket is connected), +/// with the getLocalPort function. +/// +/// Sending and receiving data can use either the low-level +/// or the high-level functions. The low-level functions +/// process a raw sequence of bytes, and cannot ensure that +/// one call to Send will exactly match one call to Receive +/// at the other end of the socket. +/// +/// The high-level interface uses packets (see sf::Packet), +/// which are easier to use and provide more safety regarding +/// the data that is exchanged. You can look at the sf::Packet +/// class to get more details about how they work. +/// +/// The socket is automatically disconnected when it is destroyed, +/// but if you want to explicitly close the connection while +/// the socket instance is still alive, you can call disconnect. +/// +/// Usage example: +/// \code +/// // ----- The client ----- +/// +/// // Create a socket and connect it to 192.168.1.50 on port 55001 +/// sf::TcpSocket socket; +/// socket.connect("192.168.1.50", 55001); +/// +/// // Send a message to the connected host +/// std::string message = "Hi, I am a client"; +/// socket.send(message.c_str(), message.size() + 1); +/// +/// // Receive an answer from the server +/// char buffer[1024]; +/// std::size_t received = 0; +/// socket.receive(buffer, sizeof(buffer), received); +/// std::cout << "The server said: " << buffer << std::endl; +/// +/// // ----- The server ----- +/// +/// // Create a listener to wait for incoming connections on port 55001 +/// sf::TcpListener listener; +/// listener.listen(55001); +/// +/// // Wait for a connection +/// sf::TcpSocket socket; +/// listener.accept(socket); +/// std::cout << "New client connected: " << socket.getRemoteAddress() << std::endl; +/// +/// // Receive a message from the client +/// char buffer[1024]; +/// std::size_t received = 0; +/// socket.receive(buffer, sizeof(buffer), received); +/// std::cout << "The client said: " << buffer << std::endl; +/// +/// // Send an answer +/// std::string message = "Welcome, client"; +/// socket.send(message.c_str(), message.size() + 1); +/// \endcode +/// +/// \see sf::Socket, sf::UdpSocket, sf::Packet +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/UdpSocket.hpp b/include/SFML/Network/UdpSocket.hpp new file mode 100644 index 0000000..86fd1f6 --- /dev/null +++ b/include/SFML/Network/UdpSocket.hpp @@ -0,0 +1,286 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_UDPSOCKET_HPP +#define SFML_UDPSOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +class Packet; + +//////////////////////////////////////////////////////////// +/// \brief Specialized socket using the UDP protocol +/// +//////////////////////////////////////////////////////////// +class SFML_NETWORK_API UdpSocket : public Socket +{ +public: + + //////////////////////////////////////////////////////////// + // Constants + //////////////////////////////////////////////////////////// + enum + { + MaxDatagramSize = 65507 ///< The maximum number of bytes that can be sent in a single UDP datagram + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + UdpSocket(); + + //////////////////////////////////////////////////////////// + /// \brief Get the port to which the socket is bound locally + /// + /// If the socket is not bound to a port, this function + /// returns 0. + /// + /// \return Port to which the socket is bound + /// + /// \see bind + /// + //////////////////////////////////////////////////////////// + unsigned short getLocalPort() const; + + //////////////////////////////////////////////////////////// + /// \brief Bind the socket to a specific port + /// + /// Binding the socket to a port is necessary for being + /// able to receive data on that port. + /// You can use the special value Socket::AnyPort to tell the + /// system to automatically pick an available port, and then + /// call getLocalPort to retrieve the chosen port. + /// + /// \param port Port to bind the socket to + /// \param address Address of the interface to bind to + /// + /// \return Status code + /// + /// \see unbind, getLocalPort + /// + //////////////////////////////////////////////////////////// + Status bind(unsigned short port, const IpAddress& address = IpAddress::Any); + + //////////////////////////////////////////////////////////// + /// \brief Unbind the socket from the local port to which it is bound + /// + /// The port that the socket was previously bound to is immediately + /// made available to the operating system after this function is called. + /// This means that a subsequent call to bind() will be able to re-bind + /// the port if no other process has done so in the mean time. + /// If the socket is not bound to a port, this function has no effect. + /// + /// \see bind + /// + //////////////////////////////////////////////////////////// + void unbind(); + + //////////////////////////////////////////////////////////// + /// \brief Send raw data to a remote peer + /// + /// Make sure that \a size is not greater than + /// UdpSocket::MaxDatagramSize, otherwise this function will + /// fail and no data will be sent. + /// + /// \param data Pointer to the sequence of bytes to send + /// \param size Number of bytes to send + /// \param remoteAddress Address of the receiver + /// \param remotePort Port of the receiver to send the data to + /// + /// \return Status code + /// + /// \see receive + /// + //////////////////////////////////////////////////////////// + Status send(const void* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Receive raw data from a remote peer + /// + /// In blocking mode, this function will wait until some + /// bytes are actually received. + /// Be careful to use a buffer which is large enough for + /// the data that you intend to receive, if it is too small + /// then an error will be returned and *all* the data will + /// be lost. + /// + /// \param data Pointer to the array to fill with the received bytes + /// \param size Maximum number of bytes that can be received + /// \param received This variable is filled with the actual number of bytes received + /// \param remoteAddress Address of the peer that sent the data + /// \param remotePort Port of the peer that sent the data + /// + /// \return Status code + /// + /// \see send + /// + //////////////////////////////////////////////////////////// + Status receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Send a formatted packet of data to a remote peer + /// + /// Make sure that the packet size is not greater than + /// UdpSocket::MaxDatagramSize, otherwise this function will + /// fail and no data will be sent. + /// + /// \param packet Packet to send + /// \param remoteAddress Address of the receiver + /// \param remotePort Port of the receiver to send the data to + /// + /// \return Status code + /// + /// \see receive + /// + //////////////////////////////////////////////////////////// + Status send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Receive a formatted packet of data from a remote peer + /// + /// In blocking mode, this function will wait until the whole packet + /// has been received. + /// + /// \param packet Packet to fill with the received data + /// \param remoteAddress Address of the peer that sent the data + /// \param remotePort Port of the peer that sent the data + /// + /// \return Status code + /// + /// \see send + /// + //////////////////////////////////////////////////////////// + Status receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_buffer; ///< Temporary buffer holding the received data in Receive(Packet) +}; + +} // namespace sf + + +#endif // SFML_UDPSOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::UdpSocket +/// \ingroup network +/// +/// A UDP socket is a connectionless socket. Instead of +/// connecting once to a remote host, like TCP sockets, +/// it can send to and receive from any host at any time. +/// +/// It is a datagram protocol: bounded blocks of data (datagrams) +/// are transfered over the network rather than a continuous +/// stream of data (TCP). Therefore, one call to send will always +/// match one call to receive (if the datagram is not lost), +/// with the same data that was sent. +/// +/// The UDP protocol is lightweight but unreliable. Unreliable +/// means that datagrams may be duplicated, be lost or +/// arrive reordered. However, if a datagram arrives, its +/// data is guaranteed to be valid. +/// +/// UDP is generally used for real-time communication +/// (audio or video streaming, real-time games, etc.) where +/// speed is crucial and lost data doesn't matter much. +/// +/// Sending and receiving data can use either the low-level +/// or the high-level functions. The low-level functions +/// process a raw sequence of bytes, whereas the high-level +/// interface uses packets (see sf::Packet), which are easier +/// to use and provide more safety regarding the data that is +/// exchanged. You can look at the sf::Packet class to get +/// more details about how they work. +/// +/// It is important to note that UdpSocket is unable to send +/// datagrams bigger than MaxDatagramSize. In this case, it +/// returns an error and doesn't send anything. This applies +/// to both raw data and packets. Indeed, even packets are +/// unable to split and recompose data, due to the unreliability +/// of the protocol (dropped, mixed or duplicated datagrams may +/// lead to a big mess when trying to recompose a packet). +/// +/// If the socket is bound to a port, it is automatically +/// unbound from it when the socket is destroyed. However, +/// you can unbind the socket explicitly with the Unbind +/// function if necessary, to stop receiving messages or +/// make the port available for other sockets. +/// +/// Usage example: +/// \code +/// // ----- The client ----- +/// +/// // Create a socket and bind it to the port 55001 +/// sf::UdpSocket socket; +/// socket.bind(55001); +/// +/// // Send a message to 192.168.1.50 on port 55002 +/// std::string message = "Hi, I am " + sf::IpAddress::getLocalAddress().toString(); +/// socket.send(message.c_str(), message.size() + 1, "192.168.1.50", 55002); +/// +/// // Receive an answer (most likely from 192.168.1.50, but could be anyone else) +/// char buffer[1024]; +/// std::size_t received = 0; +/// sf::IpAddress sender; +/// unsigned short port; +/// socket.receive(buffer, sizeof(buffer), received, sender, port); +/// std::cout << sender.ToString() << " said: " << buffer << std::endl; +/// +/// // ----- The server ----- +/// +/// // Create a socket and bind it to the port 55002 +/// sf::UdpSocket socket; +/// socket.bind(55002); +/// +/// // Receive a message from anyone +/// char buffer[1024]; +/// std::size_t received = 0; +/// sf::IpAddress sender; +/// unsigned short port; +/// socket.receive(buffer, sizeof(buffer), received, sender, port); +/// std::cout << sender.ToString() << " said: " << buffer << std::endl; +/// +/// // Send an answer +/// std::string message = "Welcome " + sender.toString(); +/// socket.send(message.c_str(), message.size() + 1, sender, port); +/// \endcode +/// +/// \see sf::Socket, sf::TcpSocket, sf::Packet +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/OpenGL.hpp b/include/SFML/OpenGL.hpp new file mode 100644 index 0000000..245d976 --- /dev/null +++ b/include/SFML/OpenGL.hpp @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_OPENGL_HPP +#define SFML_OPENGL_HPP + + +//////////////////////////////////////////////////////////// +/// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +/// This file just includes the OpenGL headers, +/// which have actually different paths on each system +//////////////////////////////////////////////////////////// +#if defined(SFML_SYSTEM_WINDOWS) + + // The Visual C++ version of gl.h uses WINGDIAPI and APIENTRY but doesn't define them + #ifdef _MSC_VER + #include + #endif + + #include + +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) + + #if defined(SFML_OPENGL_ES) + #include + #include + #else + #include + #endif + +#elif defined(SFML_SYSTEM_MACOS) + + #include + +#elif defined (SFML_SYSTEM_IOS) + + #include + #include + +#elif defined (SFML_SYSTEM_ANDROID) + + #include + #include + + // We're not using OpenGL ES 2+ yet, but we can use the sRGB extension + #include + +#endif + + +#endif // SFML_OPENGL_HPP diff --git a/include/SFML/System.hpp b/include/SFML/System.hpp new file mode 100644 index 0000000..499d423 --- /dev/null +++ b/include/SFML/System.hpp @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SYSTEM_HPP +#define SFML_SYSTEM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // SFML_SYSTEM_HPP + +//////////////////////////////////////////////////////////// +/// \defgroup system System module +/// +/// Base module of SFML, defining various utilities. It provides +/// vector classes, Unicode strings and conversion functions, +/// threads and mutexes, timing classes. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Clock.hpp b/include/SFML/System/Clock.hpp new file mode 100644 index 0000000..1062b22 --- /dev/null +++ b/include/SFML/System/Clock.hpp @@ -0,0 +1,117 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CLOCK_HPP +#define SFML_CLOCK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility class that measures the elapsed time +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API Clock +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// The clock starts automatically after being constructed. + /// + //////////////////////////////////////////////////////////// + Clock(); + + //////////////////////////////////////////////////////////// + /// \brief Get the elapsed time + /// + /// This function returns the time elapsed since the last call + /// to restart() (or the construction of the instance if restart() + /// has not been called). + /// + /// \return Time elapsed + /// + //////////////////////////////////////////////////////////// + Time getElapsedTime() const; + + //////////////////////////////////////////////////////////// + /// \brief Restart the clock + /// + /// This function puts the time counter back to zero. + /// It also returns the time elapsed since the clock was started. + /// + /// \return Time elapsed + /// + //////////////////////////////////////////////////////////// + Time restart(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Time m_startTime; ///< Time of last reset, in microseconds +}; + +} // namespace sf + + +#endif // SFML_CLOCK_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Clock +/// \ingroup system +/// +/// sf::Clock is a lightweight class for measuring time. +/// +/// Its provides the most precise time that the underlying +/// OS can achieve (generally microseconds or nanoseconds). +/// It also ensures monotonicity, which means that the returned +/// time can never go backward, even if the system time is +/// changed. +/// +/// Usage example: +/// \code +/// sf::Clock clock; +/// ... +/// Time time1 = clock.getElapsedTime(); +/// ... +/// Time time2 = clock.restart(); +/// \endcode +/// +/// The sf::Time value returned by the clock can then be +/// converted to a number of seconds, milliseconds or even +/// microseconds. +/// +/// \see sf::Time +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Err.hpp b/include/SFML/System/Err.hpp new file mode 100644 index 0000000..b2f0976 --- /dev/null +++ b/include/SFML/System/Err.hpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_ERR_HPP +#define SFML_ERR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Standard stream used by SFML to output warnings and errors +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API std::ostream& err(); + +} // namespace sf + + +#endif // SFML_ERR_HPP + + +//////////////////////////////////////////////////////////// +/// \fn sf::err +/// \ingroup system +/// +/// By default, sf::err() outputs to the same location as std::cerr, +/// (-> the stderr descriptor) which is the console if there's +/// one available. +/// +/// It is a standard std::ostream instance, so it supports all the +/// insertion operations defined by the STL +/// (operator <<, manipulators, etc.). +/// +/// sf::err() can be redirected to write to another output, independently +/// of std::cerr, by using the rdbuf() function provided by the +/// std::ostream class. +/// +/// Example: +/// \code +/// // Redirect to a file +/// std::ofstream file("sfml-log.txt"); +/// std::streambuf* previous = sf::err().rdbuf(file.rdbuf()); +/// +/// // Redirect to nothing +/// sf::err().rdbuf(NULL); +/// +/// // Restore the original output +/// sf::err().rdbuf(previous); +/// \endcode +/// +/// \return Reference to std::ostream representing the SFML error stream +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Export.hpp b/include/SFML/System/Export.hpp new file mode 100644 index 0000000..df41668 --- /dev/null +++ b/include/SFML/System/Export.hpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SYSTEM_EXPORT_HPP +#define SFML_SYSTEM_EXPORT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_SYSTEM_EXPORTS) + + #define SFML_SYSTEM_API SFML_API_EXPORT + +#else + + #define SFML_SYSTEM_API SFML_API_IMPORT + +#endif + + +#endif // SFML_SYSTEM_EXPORT_HPP diff --git a/include/SFML/System/FileInputStream.hpp b/include/SFML/System/FileInputStream.hpp new file mode 100644 index 0000000..b4e4377 --- /dev/null +++ b/include/SFML/System/FileInputStream.hpp @@ -0,0 +1,169 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_FILEINPUTSTREAM_HPP +#define SFML_FILEINPUTSTREAM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#ifdef ANDROID +namespace sf +{ +namespace priv +{ +class SFML_SYSTEM_API ResourceStream; +} +} +#endif + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of input stream based on a file +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API FileInputStream : public InputStream, NonCopyable +{ +public: + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + FileInputStream(); + + //////////////////////////////////////////////////////////// + /// \brief Default destructor + /// + //////////////////////////////////////////////////////////// + virtual ~FileInputStream(); + + //////////////////////////////////////////////////////////// + /// \brief Open the stream from a file path + /// + /// \param filename Name of the file to open + /// + /// \return True on success, false on error + /// + //////////////////////////////////////////////////////////// + bool open(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Read data from the stream + /// + /// After reading, the stream's reading position must be + /// advanced by the amount of bytes read. + /// + /// \param data Buffer where to copy the read data + /// \param size Desired number of bytes to read + /// + /// \return The number of bytes actually read, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 read(void* data, Int64 size); + + //////////////////////////////////////////////////////////// + /// \brief Change the current reading position + /// + /// \param position The position to seek to, from the beginning + /// + /// \return The position actually sought to, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 seek(Int64 position); + + //////////////////////////////////////////////////////////// + /// \brief Get the current reading position in the stream + /// + /// \return The current position, or -1 on error. + /// + //////////////////////////////////////////////////////////// + virtual Int64 tell(); + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the stream + /// + /// \return The total number of bytes available in the stream, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 getSize(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// +#ifdef ANDROID + priv::ResourceStream* m_file; +#else + std::FILE* m_file; ///< stdio file stream +#endif +}; + +} // namespace sf + + +#endif // SFML_FILEINPUTSTREAM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::FileInputStream +/// \ingroup system +/// +/// This class is a specialization of InputStream that +/// reads from a file on disk. +/// +/// It wraps a file in the common InputStream interface +/// and therefore allows to use generic classes or functions +/// that accept such a stream, with a file on disk as the data +/// source. +/// +/// In addition to the virtual functions inherited from +/// InputStream, FileInputStream adds a function to +/// specify the file to open. +/// +/// SFML resource classes can usually be loaded directly from +/// a filename, so this class shouldn't be useful to you unless +/// you create your own algorithms that operate on an InputStream. +/// +/// Usage example: +/// \code +/// void process(InputStream& stream); +/// +/// FileInputStream stream; +/// if (stream.open("some_file.dat")) +/// process(stream); +/// \endcode +/// +/// InputStream, MemoryInputStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/InputStream.hpp b/include/SFML/System/InputStream.hpp new file mode 100644 index 0000000..ae60b2b --- /dev/null +++ b/include/SFML/System/InputStream.hpp @@ -0,0 +1,152 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_INPUTSTREAM_HPP +#define SFML_INPUTSTREAM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract class for custom file input streams +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API InputStream +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~InputStream() {} + + //////////////////////////////////////////////////////////// + /// \brief Read data from the stream + /// + /// After reading, the stream's reading position must be + /// advanced by the amount of bytes read. + /// + /// \param data Buffer where to copy the read data + /// \param size Desired number of bytes to read + /// + /// \return The number of bytes actually read, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 read(void* data, Int64 size) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Change the current reading position + /// + /// \param position The position to seek to, from the beginning + /// + /// \return The position actually sought to, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 seek(Int64 position) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Get the current reading position in the stream + /// + /// \return The current position, or -1 on error. + /// + //////////////////////////////////////////////////////////// + virtual Int64 tell() = 0; + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the stream + /// + /// \return The total number of bytes available in the stream, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 getSize() = 0; +}; + +} // namespace sf + + +#endif // SFML_INPUTSTREAM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::InputStream +/// \ingroup system +/// +/// This class allows users to define their own file input sources +/// from which SFML can load resources. +/// +/// SFML resource classes like sf::Texture and +/// sf::SoundBuffer provide loadFromFile and loadFromMemory functions, +/// which read data from conventional sources. However, if you +/// have data coming from a different source (over a network, +/// embedded, encrypted, compressed, etc) you can derive your +/// own class from sf::InputStream and load SFML resources with +/// their loadFromStream function. +/// +/// Usage example: +/// \code +/// // custom stream class that reads from inside a zip file +/// class ZipStream : public sf::InputStream +/// { +/// public: +/// +/// ZipStream(std::string archive); +/// +/// bool open(std::string filename); +/// +/// Int64 read(void* data, Int64 size); +/// +/// Int64 seek(Int64 position); +/// +/// Int64 tell(); +/// +/// Int64 getSize(); +/// +/// private: +/// +/// ... +/// }; +/// +/// // now you can load textures... +/// sf::Texture texture; +/// ZipStream stream("resources.zip"); +/// stream.open("images/img.png"); +/// texture.loadFromStream(stream); +/// +/// // musics... +/// sf::Music music; +/// ZipStream stream("resources.zip"); +/// stream.open("musics/msc.ogg"); +/// music.openFromStream(stream); +/// +/// // etc. +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Lock.hpp b/include/SFML/System/Lock.hpp new file mode 100644 index 0000000..d36fea6 --- /dev/null +++ b/include/SFML/System/Lock.hpp @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_LOCK_HPP +#define SFML_LOCK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Mutex; + +//////////////////////////////////////////////////////////// +/// \brief Automatic wrapper for locking and unlocking mutexes +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API Lock : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Construct the lock with a target mutex + /// + /// The mutex passed to sf::Lock is automatically locked. + /// + /// \param mutex Mutex to lock + /// + //////////////////////////////////////////////////////////// + explicit Lock(Mutex& mutex); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// The destructor of sf::Lock automatically unlocks its mutex. + /// + //////////////////////////////////////////////////////////// + ~Lock(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Mutex& m_mutex; ///< Mutex to lock / unlock +}; + +} // namespace sf + + +#endif // SFML_LOCK_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Lock +/// \ingroup system +/// +/// sf::Lock is a RAII wrapper for sf::Mutex. By unlocking +/// it in its destructor, it ensures that the mutex will +/// always be released when the current scope (most likely +/// a function) ends. +/// This is even more important when an exception or an early +/// return statement can interrupt the execution flow of the +/// function. +/// +/// For maximum robustness, sf::Lock should always be used +/// to lock/unlock a mutex. +/// +/// Usage example: +/// \code +/// sf::Mutex mutex; +/// +/// void function() +/// { +/// sf::Lock lock(mutex); // mutex is now locked +/// +/// functionThatMayThrowAnException(); // mutex is unlocked if this function throws +/// +/// if (someCondition) +/// return; // mutex is unlocked +/// +/// } // mutex is unlocked +/// \endcode +/// +/// Because the mutex is not explicitly unlocked in the code, +/// it may remain locked longer than needed. If the region +/// of the code that needs to be protected by the mutex is +/// not the entire function, a good practice is to create a +/// smaller, inner scope so that the lock is limited to this +/// part of the code. +/// +/// \code +/// sf::Mutex mutex; +/// +/// void function() +/// { +/// { +/// sf::Lock lock(mutex); +/// codeThatRequiresProtection(); +/// +/// } // mutex is unlocked here +/// +/// codeThatDoesntCareAboutTheMutex(); +/// } +/// \endcode +/// +/// Having a mutex locked longer than required is a bad practice +/// which can lead to bad performances. Don't forget that when +/// a mutex is locked, other threads may be waiting doing nothing +/// until it is released. +/// +/// \see sf::Mutex +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/MemoryInputStream.hpp b/include/SFML/System/MemoryInputStream.hpp new file mode 100644 index 0000000..16e71f2 --- /dev/null +++ b/include/SFML/System/MemoryInputStream.hpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_MEMORYINPUTSTREAM_HPP +#define SFML_MEMORYINPUTSTREAM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of input stream based on a memory chunk +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API MemoryInputStream : public InputStream +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + MemoryInputStream(); + + //////////////////////////////////////////////////////////// + /// \brief Open the stream from its data + /// + /// \param data Pointer to the data in memory + /// \param sizeInBytes Size of the data, in bytes + /// + //////////////////////////////////////////////////////////// + void open(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Read data from the stream + /// + /// After reading, the stream's reading position must be + /// advanced by the amount of bytes read. + /// + /// \param data Buffer where to copy the read data + /// \param size Desired number of bytes to read + /// + /// \return The number of bytes actually read, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 read(void* data, Int64 size); + + //////////////////////////////////////////////////////////// + /// \brief Change the current reading position + /// + /// \param position The position to seek to, from the beginning + /// + /// \return The position actually sought to, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 seek(Int64 position); + + //////////////////////////////////////////////////////////// + /// \brief Get the current reading position in the stream + /// + /// \return The current position, or -1 on error. + /// + //////////////////////////////////////////////////////////// + virtual Int64 tell(); + + //////////////////////////////////////////////////////////// + /// \brief Return the size of the stream + /// + /// \return The total number of bytes available in the stream, or -1 on error + /// + //////////////////////////////////////////////////////////// + virtual Int64 getSize(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + const char* m_data; ///< Pointer to the data in memory + Int64 m_size; ///< Total size of the data + Int64 m_offset; ///< Current reading position +}; + +} // namespace sf + + +#endif // SFML_MEMORYINPUTSTREAM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::MemoryInputStream +/// \ingroup system +/// +/// This class is a specialization of InputStream that +/// reads from data in memory. +/// +/// It wraps a memory chunk in the common InputStream interface +/// and therefore allows to use generic classes or functions +/// that accept such a stream, with content already loaded in memory. +/// +/// In addition to the virtual functions inherited from +/// InputStream, MemoryInputStream adds a function to +/// specify the pointer and size of the data in memory. +/// +/// SFML resource classes can usually be loaded directly from +/// memory, so this class shouldn't be useful to you unless +/// you create your own algorithms that operate on an InputStream. +/// +/// Usage example: +/// \code +/// void process(InputStream& stream); +/// +/// MemoryInputStream stream; +/// stream.open(thePtr, theSize); +/// process(stream); +/// \endcode +/// +/// InputStream, FileInputStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Mutex.hpp b/include/SFML/System/Mutex.hpp new file mode 100644 index 0000000..f2abdb3 --- /dev/null +++ b/include/SFML/System/Mutex.hpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_MUTEX_HPP +#define SFML_MUTEX_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +namespace priv +{ + class MutexImpl; +} + +//////////////////////////////////////////////////////////// +/// \brief Blocks concurrent access to shared resources +/// from multiple threads +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API Mutex : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Mutex(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Mutex(); + + //////////////////////////////////////////////////////////// + /// \brief Lock the mutex + /// + /// If the mutex is already locked in another thread, + /// this call will block the execution until the mutex + /// is released. + /// + /// \see unlock + /// + //////////////////////////////////////////////////////////// + void lock(); + + //////////////////////////////////////////////////////////// + /// \brief Unlock the mutex + /// + /// \see lock + /// + //////////////////////////////////////////////////////////// + void unlock(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::MutexImpl* m_mutexImpl; ///< OS-specific implementation +}; + +} // namespace sf + + +#endif // SFML_MUTEX_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Mutex +/// \ingroup system +/// +/// Mutex stands for "MUTual EXclusion". A mutex is a +/// synchronization object, used when multiple threads are involved. +/// +/// When you want to protect a part of the code from being accessed +/// simultaneously by multiple threads, you typically use a +/// mutex. When a thread is locked by a mutex, any other thread +/// trying to lock it will be blocked until the mutex is released +/// by the thread that locked it. This way, you can allow only +/// one thread at a time to access a critical region of your code. +/// +/// Usage example: +/// \code +/// Database database; // this is a critical resource that needs some protection +/// sf::Mutex mutex; +/// +/// void thread1() +/// { +/// mutex.lock(); // this call will block the thread if the mutex is already locked by thread2 +/// database.write(...); +/// mutex.unlock(); // if thread2 was waiting, it will now be unblocked +/// } +/// +/// void thread2() +/// { +/// mutex.lock(); // this call will block the thread if the mutex is already locked by thread1 +/// database.write(...); +/// mutex.unlock(); // if thread1 was waiting, it will now be unblocked +/// } +/// \endcode +/// +/// Be very careful with mutexes. A bad usage can lead to bad problems, +/// like deadlocks (two threads are waiting for each other and the +/// application is globally stuck). +/// +/// To make the usage of mutexes more robust, particularly in +/// environments where exceptions can be thrown, you should +/// use the helper class sf::Lock to lock/unlock mutexes. +/// +/// SFML mutexes are recursive, which means that you can lock +/// a mutex multiple times in the same thread without creating +/// a deadlock. In this case, the first call to lock() behaves +/// as usual, and the following ones have no effect. +/// However, you must call unlock() exactly as many times as you +/// called lock(). If you don't, the mutex won't be released. +/// +/// \see sf::Lock +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/NativeActivity.hpp b/include/SFML/System/NativeActivity.hpp new file mode 100644 index 0000000..59d32db --- /dev/null +++ b/include/SFML/System/NativeActivity.hpp @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NATIVEACTIVITY_HPP +#define SFML_NATIVEACTIVITY_HPP + + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +#if !defined(SFML_SYSTEM_ANDROID) +#error NativeActivity.hpp: This header is Android only. +#endif + + +struct ANativeActivity; + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \ingroup system +/// \brief Return a pointer to the Android native activity +/// +/// You shouldn't have to use this function, unless you want +/// to implement very specific details, that SFML doesn't +/// support, or to use a workaround for a known issue. +/// +/// \return Pointer to Android native activity structure +/// +/// \sfplatform{Android,SFML/System/NativeActivity.hpp} +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API ANativeActivity* getNativeActivity(); + +} // namespace sf + + +#endif // SFML_NATIVEACTIVITY_HPP diff --git a/include/SFML/System/NonCopyable.hpp b/include/SFML/System/NonCopyable.hpp new file mode 100644 index 0000000..4094376 --- /dev/null +++ b/include/SFML/System/NonCopyable.hpp @@ -0,0 +1,119 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NONCOPYABLE_HPP +#define SFML_NONCOPYABLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility class that makes any derived +/// class non-copyable +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API NonCopyable +{ +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Because this class has a copy constructor, the compiler + /// will not automatically generate the default constructor. + /// That's why we must define it explicitly. + /// + //////////////////////////////////////////////////////////// + NonCopyable() {} + +private: + + //////////////////////////////////////////////////////////// + /// \brief Disabled copy constructor + /// + /// By making the copy constructor private, the compiler will + /// trigger an error if anyone outside tries to use it. + /// To prevent NonCopyable or friend classes from using it, + /// we also give no definition, so that the linker will + /// produce an error if the first protection was inefficient. + /// + //////////////////////////////////////////////////////////// + NonCopyable(const NonCopyable&); + + //////////////////////////////////////////////////////////// + /// \brief Disabled assignment operator + /// + /// By making the assignment operator private, the compiler will + /// trigger an error if anyone outside tries to use it. + /// To prevent NonCopyable or friend classes from using it, + /// we also give no definition, so that the linker will + /// produce an error if the first protection was inefficient. + /// + //////////////////////////////////////////////////////////// + NonCopyable& operator =(const NonCopyable&); +}; + +} // namespace sf + + +#endif // SFML_NONCOPYABLE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::NonCopyable +/// \ingroup system +/// +/// This class makes its instances non-copyable, by explicitly +/// disabling its copy constructor and its assignment operator. +/// +/// To create a non-copyable class, simply inherit from +/// sf::NonCopyable. +/// +/// The type of inheritance (public or private) doesn't matter, +/// the copy constructor and assignment operator are declared private +/// in sf::NonCopyable so they will end up being inaccessible in both +/// cases. Thus you can use a shorter syntax for inheriting from it +/// (see below). +/// +/// Usage example: +/// \code +/// class MyNonCopyableClass : sf::NonCopyable +/// { +/// ... +/// }; +/// \endcode +/// +/// Deciding whether the instances of a class can be copied +/// or not is a very important design choice. You are strongly +/// encouraged to think about it before writing a class, +/// and to use sf::NonCopyable when necessary to prevent +/// many potential future errors when using it. This is also +/// a very important indication to users of your class. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Sleep.hpp b/include/SFML/System/Sleep.hpp new file mode 100644 index 0000000..6da6860 --- /dev/null +++ b/include/SFML/System/Sleep.hpp @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SLEEP_HPP +#define SFML_SLEEP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \ingroup system +/// \brief Make the current thread sleep for a given duration +/// +/// sf::sleep is the best way to block a program or one of its +/// threads, as it doesn't consume any CPU power. +/// +/// \param duration Time to sleep +/// +//////////////////////////////////////////////////////////// +void SFML_SYSTEM_API sleep(Time duration); + +} // namespace sf + + +#endif // SFML_SLEEP_HPP diff --git a/include/SFML/System/String.hpp b/include/SFML/System/String.hpp new file mode 100644 index 0000000..6001083 --- /dev/null +++ b/include/SFML/System/String.hpp @@ -0,0 +1,669 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_STRING_HPP +#define SFML_STRING_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility string class that automatically handles +/// conversions between types and encodings +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API String +{ +public: + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::basic_string::iterator Iterator; ///< Iterator type + typedef std::basic_string::const_iterator ConstIterator; ///< Read-only iterator type + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const std::size_t InvalidPos; ///< Represents an invalid position in the string + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor creates an empty string. + /// + //////////////////////////////////////////////////////////// + String(); + + //////////////////////////////////////////////////////////// + /// \brief Construct from a single ANSI character and a locale + /// + /// The source character is converted to UTF-32 according + /// to the given locale. + /// + /// \param ansiChar ANSI character to convert + /// \param locale Locale to use for conversion + /// + //////////////////////////////////////////////////////////// + String(char ansiChar, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Construct from single wide character + /// + /// \param wideChar Wide character to convert + /// + //////////////////////////////////////////////////////////// + String(wchar_t wideChar); + + //////////////////////////////////////////////////////////// + /// \brief Construct from single UTF-32 character + /// + /// \param utf32Char UTF-32 character to convert + /// + //////////////////////////////////////////////////////////// + String(Uint32 utf32Char); + + //////////////////////////////////////////////////////////// + /// \brief Construct from a null-terminated C-style ANSI string and a locale + /// + /// The source string is converted to UTF-32 according + /// to the given locale. + /// + /// \param ansiString ANSI string to convert + /// \param locale Locale to use for conversion + /// + //////////////////////////////////////////////////////////// + String(const char* ansiString, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Construct from an ANSI string and a locale + /// + /// The source string is converted to UTF-32 according + /// to the given locale. + /// + /// \param ansiString ANSI string to convert + /// \param locale Locale to use for conversion + /// + //////////////////////////////////////////////////////////// + String(const std::string& ansiString, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Construct from null-terminated C-style wide string + /// + /// \param wideString Wide string to convert + /// + //////////////////////////////////////////////////////////// + String(const wchar_t* wideString); + + //////////////////////////////////////////////////////////// + /// \brief Construct from a wide string + /// + /// \param wideString Wide string to convert + /// + //////////////////////////////////////////////////////////// + String(const std::wstring& wideString); + + //////////////////////////////////////////////////////////// + /// \brief Construct from a null-terminated C-style UTF-32 string + /// + /// \param utf32String UTF-32 string to assign + /// + //////////////////////////////////////////////////////////// + String(const Uint32* utf32String); + + //////////////////////////////////////////////////////////// + /// \brief Construct from an UTF-32 string + /// + /// \param utf32String UTF-32 string to assign + /// + //////////////////////////////////////////////////////////// + String(const std::basic_string& utf32String); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + String(const String& copy); + + //////////////////////////////////////////////////////////// + /// \brief Create a new sf::String from a UTF-8 encoded string + /// + /// \param begin Forward iterator to the beginning of the UTF-8 sequence + /// \param end Forward iterator to the end of the UTF-8 sequence + /// + /// \return A sf::String containing the source string + /// + /// \see fromUtf16, fromUtf32 + /// + //////////////////////////////////////////////////////////// + template + static String fromUtf8(T begin, T end); + + //////////////////////////////////////////////////////////// + /// \brief Create a new sf::String from a UTF-16 encoded string + /// + /// \param begin Forward iterator to the beginning of the UTF-16 sequence + /// \param end Forward iterator to the end of the UTF-16 sequence + /// + /// \return A sf::String containing the source string + /// + /// \see fromUtf8, fromUtf32 + /// + //////////////////////////////////////////////////////////// + template + static String fromUtf16(T begin, T end); + + //////////////////////////////////////////////////////////// + /// \brief Create a new sf::String from a UTF-32 encoded string + /// + /// This function is provided for consistency, it is equivalent to + /// using the constructors that takes a const sf::Uint32* or + /// a std::basic_string. + /// + /// \param begin Forward iterator to the beginning of the UTF-32 sequence + /// \param end Forward iterator to the end of the UTF-32 sequence + /// + /// \return A sf::String containing the source string + /// + /// \see fromUtf8, fromUtf16 + /// + //////////////////////////////////////////////////////////// + template + static String fromUtf32(T begin, T end); + + //////////////////////////////////////////////////////////// + /// \brief Implicit conversion operator to std::string (ANSI string) + /// + /// The current global locale is used for conversion. If you + /// want to explicitly specify a locale, see toAnsiString. + /// Characters that do not fit in the target encoding are + /// discarded from the returned string. + /// This operator is defined for convenience, and is equivalent + /// to calling toAnsiString(). + /// + /// \return Converted ANSI string + /// + /// \see toAnsiString, operator std::wstring + /// + //////////////////////////////////////////////////////////// + operator std::string() const; + + //////////////////////////////////////////////////////////// + /// \brief Implicit conversion operator to std::wstring (wide string) + /// + /// Characters that do not fit in the target encoding are + /// discarded from the returned string. + /// This operator is defined for convenience, and is equivalent + /// to calling toWideString(). + /// + /// \return Converted wide string + /// + /// \see toWideString, operator std::string + /// + //////////////////////////////////////////////////////////// + operator std::wstring() const; + + //////////////////////////////////////////////////////////// + /// \brief Convert the Unicode string to an ANSI string + /// + /// The UTF-32 string is converted to an ANSI string in + /// the encoding defined by \a locale. + /// Characters that do not fit in the target encoding are + /// discarded from the returned string. + /// + /// \param locale Locale to use for conversion + /// + /// \return Converted ANSI string + /// + /// \see toWideString, operator std::string + /// + //////////////////////////////////////////////////////////// + std::string toAnsiString(const std::locale& locale = std::locale()) const; + + //////////////////////////////////////////////////////////// + /// \brief Convert the Unicode string to a wide string + /// + /// Characters that do not fit in the target encoding are + /// discarded from the returned string. + /// + /// \return Converted wide string + /// + /// \see toAnsiString, operator std::wstring + /// + //////////////////////////////////////////////////////////// + std::wstring toWideString() const; + + //////////////////////////////////////////////////////////// + /// \brief Convert the Unicode string to a UTF-8 string + /// + /// \return Converted UTF-8 string + /// + /// \see toUtf16, toUtf32 + /// + //////////////////////////////////////////////////////////// + std::basic_string toUtf8() const; + + //////////////////////////////////////////////////////////// + /// \brief Convert the Unicode string to a UTF-16 string + /// + /// \return Converted UTF-16 string + /// + /// \see toUtf8, toUtf32 + /// + //////////////////////////////////////////////////////////// + std::basic_string toUtf16() const; + + //////////////////////////////////////////////////////////// + /// \brief Convert the Unicode string to a UTF-32 string + /// + /// This function doesn't perform any conversion, since the + /// string is already stored as UTF-32 internally. + /// + /// \return Converted UTF-32 string + /// + /// \see toUtf8, toUtf16 + /// + //////////////////////////////////////////////////////////// + std::basic_string toUtf32() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + String& operator =(const String& right); + + //////////////////////////////////////////////////////////// + /// \brief Overload of += operator to append an UTF-32 string + /// + /// \param right String to append + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + String& operator +=(const String& right); + + //////////////////////////////////////////////////////////// + /// \brief Overload of [] operator to access a character by its position + /// + /// This function provides read-only access to characters. + /// Note: the behavior is undefined if \a index is out of range. + /// + /// \param index Index of the character to get + /// + /// \return Character at position \a index + /// + //////////////////////////////////////////////////////////// + Uint32 operator [](std::size_t index) const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of [] operator to access a character by its position + /// + /// This function provides read and write access to characters. + /// Note: the behavior is undefined if \a index is out of range. + /// + /// \param index Index of the character to get + /// + /// \return Reference to the character at position \a index + /// + //////////////////////////////////////////////////////////// + Uint32& operator [](std::size_t index); + + //////////////////////////////////////////////////////////// + /// \brief Clear the string + /// + /// This function removes all the characters from the string. + /// + /// \see isEmpty, erase + /// + //////////////////////////////////////////////////////////// + void clear(); + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the string + /// + /// \return Number of characters in the string + /// + /// \see isEmpty + /// + //////////////////////////////////////////////////////////// + std::size_t getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Check whether the string is empty or not + /// + /// \return True if the string is empty (i.e. contains no character) + /// + /// \see clear, getSize + /// + //////////////////////////////////////////////////////////// + bool isEmpty() const; + + //////////////////////////////////////////////////////////// + /// \brief Erase one or more characters from the string + /// + /// This function removes a sequence of \a count characters + /// starting from \a position. + /// + /// \param position Position of the first character to erase + /// \param count Number of characters to erase + /// + //////////////////////////////////////////////////////////// + void erase(std::size_t position, std::size_t count = 1); + + //////////////////////////////////////////////////////////// + /// \brief Insert one or more characters into the string + /// + /// This function inserts the characters of \a str + /// into the string, starting from \a position. + /// + /// \param position Position of insertion + /// \param str Characters to insert + /// + //////////////////////////////////////////////////////////// + void insert(std::size_t position, const String& str); + + //////////////////////////////////////////////////////////// + /// \brief Find a sequence of one or more characters in the string + /// + /// This function searches for the characters of \a str + /// in the string, starting from \a start. + /// + /// \param str Characters to find + /// \param start Where to begin searching + /// + /// \return Position of \a str in the string, or String::InvalidPos if not found + /// + //////////////////////////////////////////////////////////// + std::size_t find(const String& str, std::size_t start = 0) const; + + //////////////////////////////////////////////////////////// + /// \brief Replace a substring with another string + /// + /// This function replaces the substring that starts at index \a position + /// and spans \a length characters with the string \a replaceWith. + /// + /// \param position Index of the first character to be replaced + /// \param length Number of characters to replace. You can pass InvalidPos to + /// replace all characters until the end of the string. + /// \param replaceWith String that replaces the given substring. + /// + //////////////////////////////////////////////////////////// + void replace(std::size_t position, std::size_t length, const String& replaceWith); + + //////////////////////////////////////////////////////////// + /// \brief Replace all occurrences of a substring with a replacement string + /// + /// This function replaces all occurrences of \a searchFor in this string + /// with the string \a replaceWith. + /// + /// \param searchFor The value being searched for + /// \param replaceWith The value that replaces found \a searchFor values + /// + //////////////////////////////////////////////////////////// + void replace(const String& searchFor, const String& replaceWith); + + //////////////////////////////////////////////////////////// + /// \brief Return a part of the string + /// + /// This function returns the substring that starts at index \a position + /// and spans \a length characters. + /// + /// \param position Index of the first character + /// \param length Number of characters to include in the substring (if + /// the string is shorter, as many characters as possible + /// are included). \ref InvalidPos can be used to include all + /// characters until the end of the string. + /// + /// \return String object containing a substring of this object + /// + //////////////////////////////////////////////////////////// + String substring(std::size_t position, std::size_t length = InvalidPos) const; + + //////////////////////////////////////////////////////////// + /// \brief Get a pointer to the C-style array of characters + /// + /// This functions provides a read-only access to a + /// null-terminated C-style representation of the string. + /// The returned pointer is temporary and is meant only for + /// immediate use, thus it is not recommended to store it. + /// + /// \return Read-only pointer to the array of characters + /// + //////////////////////////////////////////////////////////// + const Uint32* getData() const; + + //////////////////////////////////////////////////////////// + /// \brief Return an iterator to the beginning of the string + /// + /// \return Read-write iterator to the beginning of the string characters + /// + /// \see end + /// + //////////////////////////////////////////////////////////// + Iterator begin(); + + //////////////////////////////////////////////////////////// + /// \brief Return an iterator to the beginning of the string + /// + /// \return Read-only iterator to the beginning of the string characters + /// + /// \see end + /// + //////////////////////////////////////////////////////////// + ConstIterator begin() const; + + //////////////////////////////////////////////////////////// + /// \brief Return an iterator to the end of the string + /// + /// The end iterator refers to 1 position past the last character; + /// thus it represents an invalid character and should never be + /// accessed. + /// + /// \return Read-write iterator to the end of the string characters + /// + /// \see begin + /// + //////////////////////////////////////////////////////////// + Iterator end(); + + //////////////////////////////////////////////////////////// + /// \brief Return an iterator to the end of the string + /// + /// The end iterator refers to 1 position past the last character; + /// thus it represents an invalid character and should never be + /// accessed. + /// + /// \return Read-only iterator to the end of the string characters + /// + /// \see begin + /// + //////////////////////////////////////////////////////////// + ConstIterator end() const; + +private: + + friend SFML_SYSTEM_API bool operator ==(const String& left, const String& right); + friend SFML_SYSTEM_API bool operator <(const String& left, const String& right); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::basic_string m_string; ///< Internal string of UTF-32 characters +}; + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of == operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if both strings are equal +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator ==(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of != operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if both strings are different +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator !=(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of < operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if \a left is lexicographically before \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator <(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of > operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if \a left is lexicographically after \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator >(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of <= operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if \a left is lexicographically before or equivalent to \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator <=(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of >= operator to compare two UTF-32 strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return True if \a left is lexicographically after or equivalent to \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator >=(const String& left, const String& right); + +//////////////////////////////////////////////////////////// +/// \relates String +/// \brief Overload of binary + operator to concatenate two strings +/// +/// \param left Left operand (a string) +/// \param right Right operand (a string) +/// +/// \return Concatenated string +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API String operator +(const String& left, const String& right); + +#include + +} // namespace sf + + +#endif // SFML_STRING_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::String +/// \ingroup system +/// +/// sf::String is a utility string class defined mainly for +/// convenience. It is a Unicode string (implemented using +/// UTF-32), thus it can store any character in the world +/// (European, Chinese, Arabic, Hebrew, etc.). +/// +/// It automatically handles conversions from/to ANSI and +/// wide strings, so that you can work with standard string +/// classes and still be compatible with functions taking a +/// sf::String. +/// +/// \code +/// sf::String s; +/// +/// std::string s1 = s; // automatically converted to ANSI string +/// std::wstring s2 = s; // automatically converted to wide string +/// s = "hello"; // automatically converted from ANSI string +/// s = L"hello"; // automatically converted from wide string +/// s += 'a'; // automatically converted from ANSI string +/// s += L'a'; // automatically converted from wide string +/// \endcode +/// +/// Conversions involving ANSI strings use the default user locale. However +/// it is possible to use a custom locale if necessary: +/// \code +/// std::locale locale; +/// sf::String s; +/// ... +/// std::string s1 = s.toAnsiString(locale); +/// s = sf::String("hello", locale); +/// \endcode +/// +/// sf::String defines the most important functions of the +/// standard std::string class: removing, random access, iterating, +/// appending, comparing, etc. However it is a simple class +/// provided for convenience, and you may have to consider using +/// a more optimized class if your program requires complex string +/// handling. The automatic conversion functions will then take +/// care of converting your string to sf::String whenever SFML +/// requires it. +/// +/// Please note that SFML also defines a low-level, generic +/// interface for Unicode handling, see the sf::Utf classes. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/String.inl b/include/SFML/System/String.inl new file mode 100644 index 0000000..9ce4017 --- /dev/null +++ b/include/SFML/System/String.inl @@ -0,0 +1,53 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +template +String String::fromUtf8(T begin, T end) +{ + String string; + Utf8::toUtf32(begin, end, std::back_inserter(string.m_string)); + return string; +} + + +//////////////////////////////////////////////////////////// +template +String String::fromUtf16(T begin, T end) +{ + String string; + Utf16::toUtf32(begin, end, std::back_inserter(string.m_string)); + return string; +} + + +//////////////////////////////////////////////////////////// +template +String String::fromUtf32(T begin, T end) +{ + String string; + string.m_string.assign(begin, end); + return string; +} diff --git a/include/SFML/System/Thread.hpp b/include/SFML/System/Thread.hpp new file mode 100644 index 0000000..3a90ab6 --- /dev/null +++ b/include/SFML/System/Thread.hpp @@ -0,0 +1,282 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_THREAD_HPP +#define SFML_THREAD_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + class ThreadImpl; + struct ThreadFunc; +} + +//////////////////////////////////////////////////////////// +/// \brief Utility class to manipulate threads +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API Thread : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Construct the thread from a functor with no argument + /// + /// This constructor works for function objects, as well + /// as free functions. + /// + /// Use this constructor for this kind of function: + /// \code + /// void function(); + /// + /// // --- or ---- + /// + /// struct Functor + /// { + /// void operator()(); + /// }; + /// \endcode + /// Note: this does *not* run the thread, use launch(). + /// + /// \param function Functor or free function to use as the entry point of the thread + /// + //////////////////////////////////////////////////////////// + template + Thread(F function); + + //////////////////////////////////////////////////////////// + /// \brief Construct the thread from a functor with an argument + /// + /// This constructor works for function objects, as well + /// as free functions. + /// It is a template, which means that the argument can + /// have any type (int, std::string, void*, Toto, ...). + /// + /// Use this constructor for this kind of function: + /// \code + /// void function(int arg); + /// + /// // --- or ---- + /// + /// struct Functor + /// { + /// void operator()(std::string arg); + /// }; + /// \endcode + /// Note: this does *not* run the thread, use launch(). + /// + /// \param function Functor or free function to use as the entry point of the thread + /// \param argument argument to forward to the function + /// + //////////////////////////////////////////////////////////// + template + Thread(F function, A argument); + + //////////////////////////////////////////////////////////// + /// \brief Construct the thread from a member function and an object + /// + /// This constructor is a template, which means that you can + /// use it with any class. + /// Use this constructor for this kind of function: + /// \code + /// class MyClass + /// { + /// public: + /// + /// void function(); + /// }; + /// \endcode + /// Note: this does *not* run the thread, use launch(). + /// + /// \param function Entry point of the thread + /// \param object Pointer to the object to use + /// + //////////////////////////////////////////////////////////// + template + Thread(void(C::*function)(), C* object); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// This destructor calls wait(), so that the internal thread + /// cannot survive after its sf::Thread instance is destroyed. + /// + //////////////////////////////////////////////////////////// + ~Thread(); + + //////////////////////////////////////////////////////////// + /// \brief Run the thread + /// + /// This function starts the entry point passed to the + /// thread's constructor, and returns immediately. + /// After this function returns, the thread's function is + /// running in parallel to the calling code. + /// + //////////////////////////////////////////////////////////// + void launch(); + + //////////////////////////////////////////////////////////// + /// \brief Wait until the thread finishes + /// + /// This function will block the execution until the + /// thread's function ends. + /// Warning: if the thread function never ends, the calling + /// thread will block forever. + /// If this function is called from its owner thread, it + /// returns without doing anything. + /// + //////////////////////////////////////////////////////////// + void wait(); + + //////////////////////////////////////////////////////////// + /// \brief Terminate the thread + /// + /// This function immediately stops the thread, without waiting + /// for its function to finish. + /// Terminating a thread with this function is not safe, + /// and can lead to local variables not being destroyed + /// on some operating systems. You should rather try to make + /// the thread function terminate by itself. + /// + //////////////////////////////////////////////////////////// + void terminate(); + +private: + + friend class priv::ThreadImpl; + + //////////////////////////////////////////////////////////// + /// \brief Internal entry point of the thread + /// + /// This function is called by the thread implementation. + /// + //////////////////////////////////////////////////////////// + void run(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::ThreadImpl* m_impl; ///< OS-specific implementation of the thread + priv::ThreadFunc* m_entryPoint; ///< Abstraction of the function to run +}; + +#include + +} // namespace sf + +#endif // SFML_THREAD_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Thread +/// \ingroup system +/// +/// Threads provide a way to run multiple parts of the code +/// in parallel. When you launch a new thread, the execution +/// is split and both the new thread and the caller run +/// in parallel. +/// +/// To use a sf::Thread, you construct it directly with the +/// function to execute as the entry point of the thread. +/// sf::Thread has multiple template constructors, which means +/// that you can use several types of entry points: +/// \li non-member functions with no argument +/// \li non-member functions with one argument of any type +/// \li functors with no argument (this one is particularly useful for compatibility with boost/std::%bind) +/// \li functors with one argument of any type +/// \li member functions from any class with no argument +/// +/// The function argument, if any, is copied in the sf::Thread +/// instance, as well as the functor (if the corresponding +/// constructor is used). Class instances, however, are passed +/// by pointer so you must make sure that the object won't be +/// destroyed while the thread is still using it. +/// +/// The thread ends when its function is terminated. If the +/// owner sf::Thread instance is destroyed before the +/// thread is finished, the destructor will wait (see wait()) +/// +/// Usage examples: +/// \code +/// // example 1: non member function with one argument +/// +/// void threadFunc(int argument) +/// { +/// ... +/// } +/// +/// sf::Thread thread(&threadFunc, 5); +/// thread.launch(); // start the thread (internally calls threadFunc(5)) +/// \endcode +/// +/// \code +/// // example 2: member function +/// +/// class Task +/// { +/// public: +/// void run() +/// { +/// ... +/// } +/// }; +/// +/// Task task; +/// sf::Thread thread(&Task::run, &task); +/// thread.launch(); // start the thread (internally calls task.run()) +/// \endcode +/// +/// \code +/// // example 3: functor +/// +/// struct Task +/// { +/// void operator()() +/// { +/// ... +/// } +/// }; +/// +/// sf::Thread thread(Task()); +/// thread.launch(); // start the thread (internally calls operator() on the Task instance) +/// \endcode +/// +/// Creating parallel threads of execution can be dangerous: +/// all threads inside the same process share the same memory space, +/// which means that you may end up accessing the same variable +/// from multiple threads at the same time. To prevent this +/// kind of situations, you can use mutexes (see sf::Mutex). +/// +/// \see sf::Mutex +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Thread.inl b/include/SFML/System/Thread.inl new file mode 100644 index 0000000..180b20a --- /dev/null +++ b/include/SFML/System/Thread.inl @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +namespace priv +{ +// Base class for abstract thread functions +struct ThreadFunc +{ + virtual ~ThreadFunc() {} + virtual void run() = 0; +}; + +// Specialization using a functor (including free functions) with no argument +template +struct ThreadFunctor : ThreadFunc +{ + ThreadFunctor(T functor) : m_functor(functor) {} + virtual void run() {m_functor();} + T m_functor; +}; + +// Specialization using a functor (including free functions) with one argument +template +struct ThreadFunctorWithArg : ThreadFunc +{ + ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {} + virtual void run() {m_function(m_arg);} + F m_function; + A m_arg; +}; + +// Specialization using a member function +template +struct ThreadMemberFunc : ThreadFunc +{ + ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {} + virtual void run() {(m_object->*m_function)();} + void(C::*m_function)(); + C* m_object; +}; + +} // namespace priv + + +//////////////////////////////////////////////////////////// +template +Thread::Thread(F functor) : +m_impl (NULL), +m_entryPoint(new priv::ThreadFunctor(functor)) +{ +} + + +//////////////////////////////////////////////////////////// +template +Thread::Thread(F function, A argument) : +m_impl (NULL), +m_entryPoint(new priv::ThreadFunctorWithArg(function, argument)) +{ +} + + +//////////////////////////////////////////////////////////// +template +Thread::Thread(void(C::*function)(), C* object) : +m_impl (NULL), +m_entryPoint(new priv::ThreadMemberFunc(function, object)) +{ +} diff --git a/include/SFML/System/ThreadLocal.hpp b/include/SFML/System/ThreadLocal.hpp new file mode 100644 index 0000000..7516702 --- /dev/null +++ b/include/SFML/System/ThreadLocal.hpp @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_THREADLOCAL_HPP +#define SFML_THREADLOCAL_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + class ThreadLocalImpl; +} + +//////////////////////////////////////////////////////////// +/// \brief Defines variables with thread-local storage +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API ThreadLocal : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param value Optional value to initialize the variable + /// + //////////////////////////////////////////////////////////// + ThreadLocal(void* value = NULL); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~ThreadLocal(); + + //////////////////////////////////////////////////////////// + /// \brief Set the thread-specific value of the variable + /// + /// \param value Value of the variable for the current thread + /// + //////////////////////////////////////////////////////////// + void setValue(void* value); + + //////////////////////////////////////////////////////////// + /// \brief Retrieve the thread-specific value of the variable + /// + /// \return Value of the variable for the current thread + /// + //////////////////////////////////////////////////////////// + void* getValue() const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::ThreadLocalImpl* m_impl; ///< Pointer to the OS specific implementation +}; + +} // namespace sf + + +#endif // SFML_THREADLOCAL_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::ThreadLocal +/// \ingroup system +/// +/// This class manipulates void* parameters and thus is not +/// appropriate for strongly-typed variables. You should rather +/// use the sf::ThreadLocalPtr template class. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/ThreadLocalPtr.hpp b/include/SFML/System/ThreadLocalPtr.hpp new file mode 100644 index 0000000..c776b45 --- /dev/null +++ b/include/SFML/System/ThreadLocalPtr.hpp @@ -0,0 +1,158 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_THREADLOCALPTR_HPP +#define SFML_THREADLOCALPTR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Pointer to a thread-local variable +/// +//////////////////////////////////////////////////////////// +template +class ThreadLocalPtr : private ThreadLocal +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param value Optional value to initialize the variable + /// + //////////////////////////////////////////////////////////// + ThreadLocalPtr(T* value = NULL); + + //////////////////////////////////////////////////////////// + /// \brief Overload of unary operator * + /// + /// Like raw pointers, applying the * operator returns a + /// reference to the pointed-to object. + /// + /// \return Reference to the thread-local variable + /// + //////////////////////////////////////////////////////////// + T& operator *() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of operator -> + /// + /// Similarly to raw pointers, applying the -> operator + /// returns the pointed-to object. + /// + /// \return Pointer to the thread-local variable + /// + //////////////////////////////////////////////////////////// + T* operator ->() const; + + //////////////////////////////////////////////////////////// + /// \brief Conversion operator to implicitly convert the + /// pointer to its raw pointer type (T*) + /// + /// \return Pointer to the actual object + /// + //////////////////////////////////////////////////////////// + operator T*() const; + + //////////////////////////////////////////////////////////// + /// \brief Assignment operator for a raw pointer parameter + /// + /// \param value Pointer to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + ThreadLocalPtr& operator =(T* value); + + //////////////////////////////////////////////////////////// + /// \brief Assignment operator for a ThreadLocalPtr parameter + /// + /// \param right ThreadLocalPtr to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + ThreadLocalPtr& operator =(const ThreadLocalPtr& right); +}; + +} // namespace sf + +#include + + +#endif // SFML_THREADLOCALPTR_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::ThreadLocalPtr +/// \ingroup system +/// +/// sf::ThreadLocalPtr is a type-safe wrapper for storing +/// pointers to thread-local variables. A thread-local +/// variable holds a different value for each different +/// thread, unlike normal variables that are shared. +/// +/// Its usage is completely transparent, so that it is similar +/// to manipulating the raw pointer directly (like any smart pointer). +/// +/// Usage example: +/// \code +/// MyClass object1; +/// MyClass object2; +/// sf::ThreadLocalPtr objectPtr; +/// +/// void thread1() +/// { +/// objectPtr = &object1; // doesn't impact thread2 +/// ... +/// } +/// +/// void thread2() +/// { +/// objectPtr = &object2; // doesn't impact thread1 +/// ... +/// } +/// +/// int main() +/// { +/// // Create and launch the two threads +/// sf::Thread t1(&thread1); +/// sf::Thread t2(&thread2); +/// t1.launch(); +/// t2.launch(); +/// +/// return 0; +/// } +/// \endcode +/// +/// ThreadLocalPtr is designed for internal use; however you +/// can use it if you feel like it fits well your implementation. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/ThreadLocalPtr.inl b/include/SFML/System/ThreadLocalPtr.inl new file mode 100644 index 0000000..149213d --- /dev/null +++ b/include/SFML/System/ThreadLocalPtr.inl @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +namespace sf +{ +//////////////////////////////////////////////////////////// +template +ThreadLocalPtr::ThreadLocalPtr(T* value) : +ThreadLocal(value) +{ +} + + +//////////////////////////////////////////////////////////// +template +T& ThreadLocalPtr::operator *() const +{ + return *static_cast(getValue()); +} + + +//////////////////////////////////////////////////////////// +template +T* ThreadLocalPtr::operator ->() const +{ + return static_cast(getValue()); +} + + +//////////////////////////////////////////////////////////// +template +ThreadLocalPtr::operator T*() const +{ + return static_cast(getValue()); +} + + +//////////////////////////////////////////////////////////// +template +ThreadLocalPtr& ThreadLocalPtr::operator =(T* value) +{ + setValue(value); + return *this; +} + + +//////////////////////////////////////////////////////////// +template +ThreadLocalPtr& ThreadLocalPtr::operator =(const ThreadLocalPtr& right) +{ + setValue(right.getValue()); + return *this; +} + +} // namespace sf diff --git a/include/SFML/System/Time.hpp b/include/SFML/System/Time.hpp new file mode 100644 index 0000000..e3601fb --- /dev/null +++ b/include/SFML/System/Time.hpp @@ -0,0 +1,488 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TIME_HPP +#define SFML_TIME_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Represents a time value +/// +//////////////////////////////////////////////////////////// +class SFML_SYSTEM_API Time +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Sets the time value to zero. + /// + //////////////////////////////////////////////////////////// + Time(); + + //////////////////////////////////////////////////////////// + /// \brief Return the time value as a number of seconds + /// + /// \return Time in seconds + /// + /// \see asMilliseconds, asMicroseconds + /// + //////////////////////////////////////////////////////////// + float asSeconds() const; + + //////////////////////////////////////////////////////////// + /// \brief Return the time value as a number of milliseconds + /// + /// \return Time in milliseconds + /// + /// \see asSeconds, asMicroseconds + /// + //////////////////////////////////////////////////////////// + Int32 asMilliseconds() const; + + //////////////////////////////////////////////////////////// + /// \brief Return the time value as a number of microseconds + /// + /// \return Time in microseconds + /// + /// \see asSeconds, asMilliseconds + /// + //////////////////////////////////////////////////////////// + Int64 asMicroseconds() const; + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const Time Zero; ///< Predefined "zero" time value + +private: + + friend SFML_SYSTEM_API Time seconds(float); + friend SFML_SYSTEM_API Time milliseconds(Int32); + friend SFML_SYSTEM_API Time microseconds(Int64); + + //////////////////////////////////////////////////////////// + /// \brief Construct from a number of microseconds + /// + /// This function is internal. To construct time values, + /// use sf::seconds, sf::milliseconds or sf::microseconds instead. + /// + /// \param microseconds Number of microseconds + /// + //////////////////////////////////////////////////////////// + explicit Time(Int64 microseconds); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Int64 m_microseconds; ///< Time value stored as microseconds +}; + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Construct a time value from a number of seconds +/// +/// \param amount Number of seconds +/// +/// \return Time value constructed from the amount of seconds +/// +/// \see milliseconds, microseconds +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time seconds(float amount); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Construct a time value from a number of milliseconds +/// +/// \param amount Number of milliseconds +/// +/// \return Time value constructed from the amount of milliseconds +/// +/// \see seconds, microseconds +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time milliseconds(Int32 amount); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Construct a time value from a number of microseconds +/// +/// \param amount Number of microseconds +/// +/// \return Time value constructed from the amount of microseconds +/// +/// \see seconds, milliseconds +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time microseconds(Int64 amount); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of == operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if both time values are equal +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator ==(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of != operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if both time values are different +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator !=(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of < operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if \a left is lesser than \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator <(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of > operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if \a left is greater than \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator >(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of <= operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if \a left is lesser or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator <=(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of >= operator to compare two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return True if \a left is greater or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API bool operator >=(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of unary - operator to negate a time value +/// +/// \param right Right operand (a time) +/// +/// \return Opposite of the time value +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator -(Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary + operator to add two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return Sum of the two times values +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator +(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary += operator to add/assign two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return Sum of the two times values +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator +=(Time& left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary - operator to subtract two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return Difference of the two times values +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator -(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary -= operator to subtract/assign two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return Difference of the two times values +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator -=(Time& left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary * operator to scale a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator *(Time left, float right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary * operator to scale a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator *(Time left, Int64 right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary * operator to scale a time value +/// +/// \param left Left operand (a number) +/// \param right Right operand (a time) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator *(float left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary * operator to scale a time value +/// +/// \param left Left operand (a number) +/// \param right Right operand (a time) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator *(Int64 left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary *= operator to scale/assign a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator *=(Time& left, float right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary *= operator to scale/assign a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left multiplied by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator *=(Time& left, Int64 right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary / operator to scale a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left divided by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator /(Time left, float right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary / operator to scale a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left divided by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator /(Time left, Int64 right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary /= operator to scale/assign a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left divided by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator /=(Time& left, float right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary /= operator to scale/assign a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a number) +/// +/// \return \a left divided by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator /=(Time& left, Int64 right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary / operator to compute the ratio of two time values +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return \a left divided by \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API float operator /(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary % operator to compute remainder of a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return \a left modulo \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time operator %(Time left, Time right); + +//////////////////////////////////////////////////////////// +/// \relates Time +/// \brief Overload of binary %= operator to compute/assign remainder of a time value +/// +/// \param left Left operand (a time) +/// \param right Right operand (a time) +/// +/// \return \a left modulo \a right +/// +//////////////////////////////////////////////////////////// +SFML_SYSTEM_API Time& operator %=(Time& left, Time right); + +} // namespace sf + + +#endif // SFML_TIME_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Time +/// \ingroup system +/// +/// sf::Time encapsulates a time value in a flexible way. +/// It allows to define a time value either as a number of +/// seconds, milliseconds or microseconds. It also works the +/// other way round: you can read a time value as either +/// a number of seconds, milliseconds or microseconds. +/// +/// By using such a flexible interface, the API doesn't +/// impose any fixed type or resolution for time values, +/// and let the user choose its own favorite representation. +/// +/// Time values support the usual mathematical operations: +/// you can add or subtract two times, multiply or divide +/// a time by a number, compare two times, etc. +/// +/// Since they represent a time span and not an absolute time +/// value, times can also be negative. +/// +/// Usage example: +/// \code +/// sf::Time t1 = sf::seconds(0.1f); +/// Int32 milli = t1.asMilliseconds(); // 100 +/// +/// sf::Time t2 = sf::milliseconds(30); +/// Int64 micro = t2.asMicroseconds(); // 30000 +/// +/// sf::Time t3 = sf::microseconds(-800000); +/// float sec = t3.asSeconds(); // -0.8 +/// \endcode +/// +/// \code +/// void update(sf::Time elapsed) +/// { +/// position += speed * elapsed.asSeconds(); +/// } +/// +/// update(sf::milliseconds(100)); +/// \endcode +/// +/// \see sf::Clock +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Utf.hpp b/include/SFML/System/Utf.hpp new file mode 100644 index 0000000..a0b0561 --- /dev/null +++ b/include/SFML/System/Utf.hpp @@ -0,0 +1,763 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_UTF_HPP +#define SFML_UTF_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +template +class Utf; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-8 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<8> +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-8 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-8 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-8 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-8. + /// + /// \param input Codepoint to encode as UTF-8 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out encode(Uint32 input, Out output, Uint8 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-8 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-8 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static std::size_t count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-8 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toWide(In begin, In end, Out output, wchar_t replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-8 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the sf::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf32(In begin, In end, Out output); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-16 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<16> +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-16 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-16 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-16 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-16. + /// + /// \param input Codepoint to encode as UTF-16 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out encode(Uint32 input, Out output, Uint16 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-16 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-16 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static std::size_t count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-16 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toWide(In begin, In end, Out output, wchar_t replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-16 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the sf::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf32(In begin, In end, Out output); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-32 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<32> +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-32 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// For UTF-32, the character value is the same as the codepoint. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-32 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-32. + /// For UTF-32, the codepoint is the same as the character value. + /// + /// \param input Codepoint to encode as UTF-32 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out encode(Uint32 input, Out output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-32 character + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-32 sequence + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static std::size_t count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-32 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out fromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toWide(In begin, In end, Out output, wchar_t replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-32 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the sf::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out toUtf32(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single ANSI character to UTF-32 + /// + /// This function does not exist in other specializations + /// of sf::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input ANSI character + /// \param locale Locale to use for conversion + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template + static Uint32 decodeAnsi(In input, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single wide character to UTF-32 + /// + /// This function does not exist in other specializations + /// of sf::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input wide character + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template + static Uint32 decodeWide(In input); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to ANSI + /// + /// This function does not exist in other specializations + /// of sf::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to skip it) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out encodeAnsi(Uint32 codepoint, Out output, char replacement = 0, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to wide + /// + /// This function does not exist in other specializations + /// of sf::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to wide (use 0 to skip it) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out encodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0); +}; + +#include + +// Make typedefs to get rid of the template syntax +typedef Utf<8> Utf8; +typedef Utf<16> Utf16; +typedef Utf<32> Utf32; + +} // namespace sf + + +#endif // SFML_UTF_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Utf +/// \ingroup system +/// +/// Utility class providing generic functions for UTF conversions. +/// +/// sf::Utf is a low-level, generic interface for counting, iterating, +/// encoding and decoding Unicode characters and strings. It is able +/// to handle ANSI, wide, latin-1, UTF-8, UTF-16 and UTF-32 encodings. +/// +/// sf::Utf functions are all static, these classes are not meant to +/// be instantiated. All the functions are template, so that you +/// can use any character / string type for a given encoding. +/// +/// It has 3 specializations: +/// \li sf::Utf<8> (typedef'd to sf::Utf8) +/// \li sf::Utf<16> (typedef'd to sf::Utf16) +/// \li sf::Utf<32> (typedef'd to sf::Utf32) +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Utf.inl b/include/SFML/System/Utf.inl new file mode 100644 index 0000000..b7a2ae4 --- /dev/null +++ b/include/SFML/System/Utf.inl @@ -0,0 +1,752 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +// References: +// +// http://www.unicode.org/ +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h +// http://people.w3.org/rishida/scripts/uniview/conversion +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +template +In Utf<8>::decode(In begin, In end, Uint32& output, Uint32 replacement) +{ + // Some useful precomputed data + static const int trailing[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 + }; + static const Uint32 offsets[6] = + { + 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080 + }; + + // decode the character + int trailingBytes = trailing[static_cast(*begin)]; + if (begin + trailingBytes < end) + { + output = 0; + switch (trailingBytes) + { + case 5: output += static_cast(*begin++); output <<= 6; + case 4: output += static_cast(*begin++); output <<= 6; + case 3: output += static_cast(*begin++); output <<= 6; + case 2: output += static_cast(*begin++); output <<= 6; + case 1: output += static_cast(*begin++); output <<= 6; + case 0: output += static_cast(*begin++); + } + output -= offsets[trailingBytes]; + } + else + { + // Incomplete character + begin = end; + output = replacement; + } + + return begin; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::encode(Uint32 input, Out output, Uint8 replacement) +{ + // Some useful precomputed data + static const Uint8 firstBytes[7] = + { + 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC + }; + + // encode the character + if ((input > 0x0010FFFF) || ((input >= 0xD800) && (input <= 0xDBFF))) + { + // Invalid character + if (replacement) + *output++ = replacement; + } + else + { + // Valid character + + // Get the number of bytes to write + std::size_t bytestoWrite = 1; + if (input < 0x80) bytestoWrite = 1; + else if (input < 0x800) bytestoWrite = 2; + else if (input < 0x10000) bytestoWrite = 3; + else if (input <= 0x0010FFFF) bytestoWrite = 4; + + // Extract the bytes to write + Uint8 bytes[4]; + switch (bytestoWrite) + { + case 4: bytes[3] = static_cast((input | 0x80) & 0xBF); input >>= 6; + case 3: bytes[2] = static_cast((input | 0x80) & 0xBF); input >>= 6; + case 2: bytes[1] = static_cast((input | 0x80) & 0xBF); input >>= 6; + case 1: bytes[0] = static_cast (input | firstBytes[bytestoWrite]); + } + + // Add them to the output + output = std::copy(bytes, bytes + bytestoWrite, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +In Utf<8>::next(In begin, In end) +{ + Uint32 codepoint; + return decode(begin, end, codepoint); +} + + +//////////////////////////////////////////////////////////// +template +std::size_t Utf<8>::count(In begin, In end) +{ + std::size_t length = 0; + while (begin < end) + { + begin = next(begin, end); + ++length; + } + + return length; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::fromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::decodeAnsi(*begin++, locale); + output = encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::fromWide(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::decodeWide(*begin++); + output = encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::fromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + output = encode(*begin++, output); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<32>::encodeAnsi(codepoint, output, replacement, locale); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<32>::encodeWide(codepoint, output, replacement); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + *output++ = codepoint < 256 ? static_cast(codepoint) : replacement; + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toUtf8(In begin, In end, Out output) +{ + return std::copy(begin, end, output); +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toUtf16(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<16>::encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<8>::toUtf32(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + *output++ = codepoint; + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +In Utf<16>::decode(In begin, In end, Uint32& output, Uint32 replacement) +{ + Uint16 first = *begin++; + + // If it's a surrogate pair, first convert to a single UTF-32 character + if ((first >= 0xD800) && (first <= 0xDBFF)) + { + if (begin < end) + { + Uint32 second = *begin++; + if ((second >= 0xDC00) && (second <= 0xDFFF)) + { + // The second element is valid: convert the two elements to a UTF-32 character + output = static_cast(((first - 0xD800) << 10) + (second - 0xDC00) + 0x0010000); + } + else + { + // Invalid character + output = replacement; + } + } + else + { + // Invalid character + begin = end; + output = replacement; + } + } + else + { + // We can make a direct copy + output = first; + } + + return begin; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::encode(Uint32 input, Out output, Uint16 replacement) +{ + if (input <= 0xFFFF) + { + // The character can be copied directly, we just need to check if it's in the valid range + if ((input >= 0xD800) && (input <= 0xDFFF)) + { + // Invalid character (this range is reserved) + if (replacement) + *output++ = replacement; + } + else + { + // Valid character directly convertible to a single UTF-16 character + *output++ = static_cast(input); + } + } + else if (input > 0x0010FFFF) + { + // Invalid character (greater than the maximum Unicode value) + if (replacement) + *output++ = replacement; + } + else + { + // The input character will be converted to two UTF-16 elements + input -= 0x0010000; + *output++ = static_cast((input >> 10) + 0xD800); + *output++ = static_cast((input & 0x3FFUL) + 0xDC00); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +In Utf<16>::next(In begin, In end) +{ + Uint32 codepoint; + return decode(begin, end, codepoint); +} + + +//////////////////////////////////////////////////////////// +template +std::size_t Utf<16>::count(In begin, In end) +{ + std::size_t length = 0; + while (begin < end) + { + begin = next(begin, end); + ++length; + } + + return length; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::fromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::decodeAnsi(*begin++, locale); + output = encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::fromWide(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::decodeWide(*begin++); + output = encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::fromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + return std::copy(begin, end, output); +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<32>::encodeAnsi(codepoint, output, replacement, locale); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<32>::encodeWide(codepoint, output, replacement); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + *output++ = *begin < 256 ? static_cast(*begin) : replacement; + begin++; + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toUtf8(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + output = Utf<8>::encode(codepoint, output); + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toUtf16(In begin, In end, Out output) +{ + return std::copy(begin, end, output); +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<16>::toUtf32(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = decode(begin, end, codepoint); + *output++ = codepoint; + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +In Utf<32>::decode(In begin, In /*end*/, Uint32& output, Uint32 /*replacement*/) +{ + output = *begin++; + return begin; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::encode(Uint32 input, Out output, Uint32 /*replacement*/) +{ + *output++ = input; + return output; +} + + +//////////////////////////////////////////////////////////// +template +In Utf<32>::next(In begin, In /*end*/) +{ + return ++begin; +} + + +//////////////////////////////////////////////////////////// +template +std::size_t Utf<32>::count(In begin, In end) +{ + return begin - end; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::fromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + *output++ = decodeAnsi(*begin++, locale); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::fromWide(In begin, In end, Out output) +{ + while (begin < end) + *output++ = decodeWide(*begin++); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::fromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + return std::copy(begin, end, output); +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + output = encodeAnsi(*begin++, output, replacement, locale); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + output = encodeWide(*begin++, output, replacement); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + *output++ = *begin < 256 ? static_cast(*begin) : replacement; + begin++; + } + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toUtf8(In begin, In end, Out output) +{ + while (begin < end) + output = Utf<8>::encode(*begin++, output); + + return output; +} + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toUtf16(In begin, In end, Out output) +{ + while (begin < end) + output = Utf<16>::encode(*begin++, output); + + return output; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::toUtf32(In begin, In end, Out output) +{ + return std::copy(begin, end, output); +} + + +//////////////////////////////////////////////////////////// +template +Uint32 Utf<32>::decodeAnsi(In input, const std::locale& locale) +{ + // On Windows, GCC's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + + #if defined(SFML_SYSTEM_WINDOWS) && /* if Windows ... */ \ + (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \ + !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */ + + (void)locale; // to avoid warnings + + wchar_t character = 0; + mbtowc(&character, &input, 1); + return static_cast(character); + + #else + + // Get the facet of the locale which deals with character conversion + const std::ctype& facet = std::use_facet< std::ctype >(locale); + + // Use the facet to convert each character of the input string + return static_cast(facet.widen(input)); + + #endif +} + + +//////////////////////////////////////////////////////////// +template +Uint32 Utf<32>::decodeWide(In input) +{ + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, + // and UCS-4 *is* UTF-32). + + return input; +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::encodeAnsi(Uint32 codepoint, Out output, char replacement, const std::locale& locale) +{ + // On Windows, gcc's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + + #if defined(SFML_SYSTEM_WINDOWS) && /* if Windows ... */ \ + (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \ + !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */ + + (void)locale; // to avoid warnings + + char character = 0; + if (wctomb(&character, static_cast(codepoint)) >= 0) + *output++ = character; + else if (replacement) + *output++ = replacement; + + return output; + + #else + + // Get the facet of the locale which deals with character conversion + const std::ctype& facet = std::use_facet< std::ctype >(locale); + + // Use the facet to convert each character of the input string + *output++ = facet.narrow(static_cast(codepoint), replacement); + + return output; + + #endif +} + + +//////////////////////////////////////////////////////////// +template +Out Utf<32>::encodeWide(Uint32 codepoint, Out output, wchar_t replacement) +{ + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). + // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). + + switch (sizeof(wchar_t)) + { + case 4: + { + *output++ = static_cast(codepoint); + break; + } + + default: + { + if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF))) + { + *output++ = static_cast(codepoint); + } + else if (replacement) + { + *output++ = replacement; + } + break; + } + } + + return output; +} diff --git a/include/SFML/System/Vector2.hpp b/include/SFML/System/Vector2.hpp new file mode 100644 index 0000000..a88334d --- /dev/null +++ b/include/SFML/System/Vector2.hpp @@ -0,0 +1,301 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VECTOR2_HPP +#define SFML_VECTOR2_HPP + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility template class for manipulating +/// 2-dimensional vectors +/// +//////////////////////////////////////////////////////////// +template +class Vector2 +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates a Vector2(0, 0). + /// + //////////////////////////////////////////////////////////// + Vector2(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vector from its coordinates + /// + /// \param X X coordinate + /// \param Y Y coordinate + /// + //////////////////////////////////////////////////////////// + Vector2(T X, T Y); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vector from another type of vector + /// + /// This constructor doesn't replace the copy constructor, + /// it's called only when U != T. + /// A call to this constructor will fail to compile if U + /// is not convertible to T. + /// + /// \param vector Vector to convert + /// + //////////////////////////////////////////////////////////// + template + explicit Vector2(const Vector2& vector); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + T x; ///< X coordinate of the vector + T y; ///< Y coordinate of the vector +}; + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of unary operator - +/// +/// \param right Vector to negate +/// +/// \return Memberwise opposite of the vector +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator -(const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator += +/// +/// This operator performs a memberwise addition of both vectors, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector2& operator +=(Vector2& left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator -= +/// +/// This operator performs a memberwise subtraction of both vectors, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector2& operator -=(Vector2& left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator + +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Memberwise addition of both vectors +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator +(const Vector2& left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator - +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Memberwise subtraction of both vectors +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator -(const Vector2& left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator * +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Memberwise multiplication by \a right +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator *(const Vector2& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator * +/// +/// \param left Left operand (a scalar value) +/// \param right Right operand (a vector) +/// +/// \return Memberwise multiplication by \a left +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator *(T left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator *= +/// +/// This operator performs a memberwise multiplication by \a right, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector2& operator *=(Vector2& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator / +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Memberwise division by \a right +/// +//////////////////////////////////////////////////////////// +template +Vector2 operator /(const Vector2& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator /= +/// +/// This operator performs a memberwise division by \a right, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector2& operator /=(Vector2& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator == +/// +/// This operator compares strict equality between two vectors. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return True if \a left is equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator ==(const Vector2& left, const Vector2& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector2 +/// \brief Overload of binary operator != +/// +/// This operator compares strict difference between two vectors. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return True if \a left is not equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator !=(const Vector2& left, const Vector2& right); + +#include + +// Define the most common types +typedef Vector2 Vector2i; +typedef Vector2 Vector2u; +typedef Vector2 Vector2f; + +} // namespace sf + + +#endif // SFML_VECTOR2_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Vector2 +/// \ingroup system +/// +/// sf::Vector2 is a simple class that defines a mathematical +/// vector with two coordinates (x and y). It can be used to +/// represent anything that has two dimensions: a size, a point, +/// a velocity, etc. +/// +/// The template parameter T is the type of the coordinates. It +/// can be any type that supports arithmetic operations (+, -, /, *) +/// and comparisons (==, !=), for example int or float. +/// +/// You generally don't have to care about the templated form (sf::Vector2), +/// the most common specializations have special typedefs: +/// \li sf::Vector2 is sf::Vector2f +/// \li sf::Vector2 is sf::Vector2i +/// \li sf::Vector2 is sf::Vector2u +/// +/// The sf::Vector2 class has a small and simple interface, its x and y members +/// can be accessed directly (there are no accessors like setX(), getX()) and it +/// contains no mathematical function like dot product, cross product, length, etc. +/// +/// Usage example: +/// \code +/// sf::Vector2f v1(16.5f, 24.f); +/// v1.x = 18.2f; +/// float y = v1.y; +/// +/// sf::Vector2f v2 = v1 * 5.f; +/// sf::Vector2f v3; +/// v3 = v1 + v2; +/// +/// bool different = (v2 != v3); +/// \endcode +/// +/// Note: for 3-dimensional vectors, see sf::Vector3. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Vector2.inl b/include/SFML/System/Vector2.inl new file mode 100644 index 0000000..0e49e4e --- /dev/null +++ b/include/SFML/System/Vector2.inl @@ -0,0 +1,161 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +template +inline Vector2::Vector2() : +x(0), +y(0) +{ + +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2::Vector2(T X, T Y) : +x(X), +y(Y) +{ + +} + + +//////////////////////////////////////////////////////////// +template +template +inline Vector2::Vector2(const Vector2& vector) : +x(static_cast(vector.x)), +y(static_cast(vector.y)) +{ +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator -(const Vector2& right) +{ + return Vector2(-right.x, -right.y); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2& operator +=(Vector2& left, const Vector2& right) +{ + left.x += right.x; + left.y += right.y; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2& operator -=(Vector2& left, const Vector2& right) +{ + left.x -= right.x; + left.y -= right.y; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator +(const Vector2& left, const Vector2& right) +{ + return Vector2(left.x + right.x, left.y + right.y); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator -(const Vector2& left, const Vector2& right) +{ + return Vector2(left.x - right.x, left.y - right.y); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator *(const Vector2& left, T right) +{ + return Vector2(left.x * right, left.y * right); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator *(T left, const Vector2& right) +{ + return Vector2(right.x * left, right.y * left); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2& operator *=(Vector2& left, T right) +{ + left.x *= right; + left.y *= right; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2 operator /(const Vector2& left, T right) +{ + return Vector2(left.x / right, left.y / right); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector2& operator /=(Vector2& left, T right) +{ + left.x /= right; + left.y /= right; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator ==(const Vector2& left, const Vector2& right) +{ + return (left.x == right.x) && (left.y == right.y); +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator !=(const Vector2& left, const Vector2& right) +{ + return (left.x != right.x) || (left.y != right.y); +} diff --git a/include/SFML/System/Vector3.hpp b/include/SFML/System/Vector3.hpp new file mode 100644 index 0000000..dcde39b --- /dev/null +++ b/include/SFML/System/Vector3.hpp @@ -0,0 +1,302 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VECTOR3_HPP +#define SFML_VECTOR3_HPP + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Utility template class for manipulating +/// 3-dimensional vectors +/// +//////////////////////////////////////////////////////////// +template +class Vector3 +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates a Vector3(0, 0, 0). + /// + //////////////////////////////////////////////////////////// + Vector3(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vector from its coordinates + /// + /// \param X X coordinate + /// \param Y Y coordinate + /// \param Z Z coordinate + /// + //////////////////////////////////////////////////////////// + Vector3(T X, T Y, T Z); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vector from another type of vector + /// + /// This constructor doesn't replace the copy constructor, + /// it's called only when U != T. + /// A call to this constructor will fail to compile if U + /// is not convertible to T. + /// + /// \param vector Vector to convert + /// + //////////////////////////////////////////////////////////// + template + explicit Vector3(const Vector3& vector); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + T x; ///< X coordinate of the vector + T y; ///< Y coordinate of the vector + T z; ///< Z coordinate of the vector +}; + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of unary operator - +/// +/// \param left Vector to negate +/// +/// \return Memberwise opposite of the vector +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator -(const Vector3& left); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator += +/// +/// This operator performs a memberwise addition of both vectors, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector3& operator +=(Vector3& left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator -= +/// +/// This operator performs a memberwise subtraction of both vectors, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector3& operator -=(Vector3& left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator + +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Memberwise addition of both vectors +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator +(const Vector3& left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator - +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return Memberwise subtraction of both vectors +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator -(const Vector3& left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator * +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Memberwise multiplication by \a right +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator *(const Vector3& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator * +/// +/// \param left Left operand (a scalar value) +/// \param right Right operand (a vector) +/// +/// \return Memberwise multiplication by \a left +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator *(T left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator *= +/// +/// This operator performs a memberwise multiplication by \a right, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector3& operator *=(Vector3& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator / +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Memberwise division by \a right +/// +//////////////////////////////////////////////////////////// +template +Vector3 operator /(const Vector3& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator /= +/// +/// This operator performs a memberwise division by \a right, +/// and assigns the result to \a left. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a scalar value) +/// +/// \return Reference to \a left +/// +//////////////////////////////////////////////////////////// +template +Vector3& operator /=(Vector3& left, T right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator == +/// +/// This operator compares strict equality between two vectors. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return True if \a left is equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator ==(const Vector3& left, const Vector3& right); + +//////////////////////////////////////////////////////////// +/// \relates Vector3 +/// \brief Overload of binary operator != +/// +/// This operator compares strict difference between two vectors. +/// +/// \param left Left operand (a vector) +/// \param right Right operand (a vector) +/// +/// \return True if \a left is not equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator !=(const Vector3& left, const Vector3& right); + +#include + +// Define the most common types +typedef Vector3 Vector3i; +typedef Vector3 Vector3f; + +} // namespace sf + + +#endif // SFML_VECTOR3_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Vector3 +/// \ingroup system +/// +/// sf::Vector3 is a simple class that defines a mathematical +/// vector with three coordinates (x, y and z). It can be used to +/// represent anything that has three dimensions: a size, a point, +/// a velocity, etc. +/// +/// The template parameter T is the type of the coordinates. It +/// can be any type that supports arithmetic operations (+, -, /, *) +/// and comparisons (==, !=), for example int or float. +/// +/// You generally don't have to care about the templated form (sf::Vector3), +/// the most common specializations have special typedefs: +/// \li sf::Vector3 is sf::Vector3f +/// \li sf::Vector3 is sf::Vector3i +/// +/// The sf::Vector3 class has a small and simple interface, its x and y members +/// can be accessed directly (there are no accessors like setX(), getX()) and it +/// contains no mathematical function like dot product, cross product, length, etc. +/// +/// Usage example: +/// \code +/// sf::Vector3f v1(16.5f, 24.f, -8.2f); +/// v1.x = 18.2f; +/// float y = v1.y; +/// float z = v1.z; +/// +/// sf::Vector3f v2 = v1 * 5.f; +/// sf::Vector3f v3; +/// v3 = v1 + v2; +/// +/// bool different = (v2 != v3); +/// \endcode +/// +/// Note: for 2-dimensional vectors, see sf::Vector2. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/System/Vector3.inl b/include/SFML/System/Vector3.inl new file mode 100644 index 0000000..29d3e56 --- /dev/null +++ b/include/SFML/System/Vector3.inl @@ -0,0 +1,168 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +template +inline Vector3::Vector3() : +x(0), +y(0), +z(0) +{ + +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3::Vector3(T X, T Y, T Z) : +x(X), +y(Y), +z(Z) +{ + +} + + +//////////////////////////////////////////////////////////// +template +template +inline Vector3::Vector3(const Vector3& vector) : +x(static_cast(vector.x)), +y(static_cast(vector.y)), +z(static_cast(vector.z)) +{ +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator -(const Vector3& left) +{ + return Vector3(-left.x, -left.y, -left.z); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3& operator +=(Vector3& left, const Vector3& right) +{ + left.x += right.x; + left.y += right.y; + left.z += right.z; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3& operator -=(Vector3& left, const Vector3& right) +{ + left.x -= right.x; + left.y -= right.y; + left.z -= right.z; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator +(const Vector3& left, const Vector3& right) +{ + return Vector3(left.x + right.x, left.y + right.y, left.z + right.z); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator -(const Vector3& left, const Vector3& right) +{ + return Vector3(left.x - right.x, left.y - right.y, left.z - right.z); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator *(const Vector3& left, T right) +{ + return Vector3(left.x * right, left.y * right, left.z * right); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator *(T left, const Vector3& right) +{ + return Vector3(right.x * left, right.y * left, right.z * left); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3& operator *=(Vector3& left, T right) +{ + left.x *= right; + left.y *= right; + left.z *= right; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3 operator /(const Vector3& left, T right) +{ + return Vector3(left.x / right, left.y / right, left.z / right); +} + + +//////////////////////////////////////////////////////////// +template +inline Vector3& operator /=(Vector3& left, T right) +{ + left.x /= right; + left.y /= right; + left.z /= right; + + return left; +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator ==(const Vector3& left, const Vector3& right) +{ + return (left.x == right.x) && (left.y == right.y) && (left.z == right.z); +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator !=(const Vector3& left, const Vector3& right) +{ + return (left.x != right.x) || (left.y != right.y) || (left.z != right.z); +} diff --git a/include/SFML/Window.hpp b/include/SFML/Window.hpp new file mode 100644 index 0000000..2a96efe --- /dev/null +++ b/include/SFML/Window.hpp @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SFML_WINDOW_HPP +#define SFML_SFML_WINDOW_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#endif // SFML_SFML_WINDOW_HPP + +//////////////////////////////////////////////////////////// +/// \defgroup window Window module +/// +/// Provides OpenGL-based windows, and abstractions for +/// events and input handling. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Context.hpp b/include/SFML/Window/Context.hpp new file mode 100644 index 0000000..e59e772 --- /dev/null +++ b/include/SFML/Window/Context.hpp @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONTEXT_HPP +#define SFML_CONTEXT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + class GlContext; +} + +typedef void (*GlFunctionPointer)(); + +//////////////////////////////////////////////////////////// +/// \brief Class holding a valid drawing context +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Context : GlResource, NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// The constructor creates and activates the context + /// + //////////////////////////////////////////////////////////// + Context(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// The destructor deactivates and destroys the context + /// + //////////////////////////////////////////////////////////// + ~Context(); + + //////////////////////////////////////////////////////////// + /// \brief Activate or deactivate explicitly the context + /// + /// \param active True to activate, false to deactivate + /// + /// \return True on success, false on failure + /// + //////////////////////////////////////////////////////////// + bool setActive(bool active); + + //////////////////////////////////////////////////////////// + /// \brief Get the settings of the context + /// + /// Note that these settings may be different than the ones + /// passed to the constructor; they are indeed adjusted if the + /// original settings are not directly supported by the system. + /// + /// \return Structure containing the settings + /// + //////////////////////////////////////////////////////////// + const ContextSettings& getSettings() const; + + //////////////////////////////////////////////////////////// + /// \brief Check whether a given OpenGL extension is available + /// + /// \param name Name of the extension to check for + /// + /// \return True if available, false if unavailable + /// + //////////////////////////////////////////////////////////// + static bool isExtensionAvailable(const char* name); + + //////////////////////////////////////////////////////////// + /// \brief Get the address of an OpenGL function + /// + /// \param name Name of the function to get the address of + /// + /// \return Address of the OpenGL function, 0 on failure + /// + //////////////////////////////////////////////////////////// + static GlFunctionPointer getFunction(const char* name); + + //////////////////////////////////////////////////////////// + /// \brief Get the currently active context + /// + /// \return The currently active context or NULL if none is active + /// + //////////////////////////////////////////////////////////// + static const Context* getActiveContext(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a in-memory context + /// + /// This constructor is for internal use, you don't need + /// to bother with it. + /// + /// \param settings Creation parameters + /// \param width Back buffer width + /// \param height Back buffer height + /// + //////////////////////////////////////////////////////////// + Context(const ContextSettings& settings, unsigned int width, unsigned int height); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::GlContext* m_context; ///< Internal OpenGL context +}; + +} // namespace sf + + +#endif // SFML_CONTEXT_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::Context +/// \ingroup window +/// +/// If you need to make OpenGL calls without having an +/// active window (like in a thread), you can use an +/// instance of this class to get a valid context. +/// +/// Having a valid context is necessary for *every* OpenGL call. +/// +/// Note that a context is only active in its current thread, +/// if you create a new thread it will have no valid context +/// by default. +/// +/// To use a sf::Context instance, just construct it and let it +/// live as long as you need a valid context. No explicit activation +/// is needed, all it has to do is to exist. Its destructor +/// will take care of deactivating and freeing all the attached +/// resources. +/// +/// Usage example: +/// \code +/// void threadFunction(void*) +/// { +/// sf::Context context; +/// // from now on, you have a valid context +/// +/// // you can make OpenGL calls +/// glClear(GL_DEPTH_BUFFER_BIT); +/// } +/// // the context is automatically deactivated and destroyed +/// // by the sf::Context destructor +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/ContextSettings.hpp b/include/SFML/Window/ContextSettings.hpp new file mode 100644 index 0000000..1dd52f2 --- /dev/null +++ b/include/SFML/Window/ContextSettings.hpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONTEXTSETTINGS_HPP +#define SFML_CONTEXTSETTINGS_HPP + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Structure defining the settings of the OpenGL +/// context attached to a window +/// +//////////////////////////////////////////////////////////// +struct ContextSettings +{ + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the context attribute flags + /// + //////////////////////////////////////////////////////////// + enum Attribute + { + Default = 0, ///< Non-debug, compatibility context (this and the core attribute are mutually exclusive) + Core = 1 << 0, ///< Core attribute + Debug = 1 << 2 ///< Debug attribute + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param depth Depth buffer bits + /// \param stencil Stencil buffer bits + /// \param antialiasing Antialiasing level + /// \param major Major number of the context version + /// \param minor Minor number of the context version + /// \param attributes Attribute flags of the context + /// \param sRgb sRGB capable framebuffer + /// + //////////////////////////////////////////////////////////// + explicit ContextSettings(unsigned int depth = 0, unsigned int stencil = 0, unsigned int antialiasing = 0, unsigned int major = 1, unsigned int minor = 1, unsigned int attributes = Default, bool sRgb = false) : + depthBits (depth), + stencilBits (stencil), + antialiasingLevel(antialiasing), + majorVersion (major), + minorVersion (minor), + attributeFlags (attributes), + sRgbCapable (sRgb) + { + } + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int depthBits; ///< Bits of the depth buffer + unsigned int stencilBits; ///< Bits of the stencil buffer + unsigned int antialiasingLevel; ///< Level of antialiasing + unsigned int majorVersion; ///< Major number of the context version to create + unsigned int minorVersion; ///< Minor number of the context version to create + Uint32 attributeFlags; ///< The attribute flags to create the context with + bool sRgbCapable; ///< Whether the context framebuffer is sRGB capable +}; + +} // namespace sf + + +#endif // SFML_CONTEXTSETTINGS_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::ContextSettings +/// \ingroup window +/// +/// ContextSettings allows to define several advanced settings +/// of the OpenGL context attached to a window. All these +/// settings with the exception of the compatibility flag +/// and anti-aliasing level have no impact on the regular +/// SFML rendering (graphics module), so you may need to use +/// this structure only if you're using SFML as a windowing +/// system for custom OpenGL rendering. +/// +/// The depthBits and stencilBits members define the number +/// of bits per pixel requested for the (respectively) depth +/// and stencil buffers. +/// +/// antialiasingLevel represents the requested number of +/// multisampling levels for anti-aliasing. +/// +/// majorVersion and minorVersion define the version of the +/// OpenGL context that you want. Only versions greater or +/// equal to 3.0 are relevant; versions lesser than 3.0 are +/// all handled the same way (i.e. you can use any version +/// < 3.0 if you don't want an OpenGL 3 context). +/// +/// When requesting a context with a version greater or equal +/// to 3.2, you have the option of specifying whether the +/// context should follow the core or compatibility profile +/// of all newer (>= 3.2) OpenGL specifications. For versions +/// 3.0 and 3.1 there is only the core profile. By default +/// a compatibility context is created. You only need to specify +/// the core flag if you want a core profile context to use with +/// your own OpenGL rendering. +/// Warning: The graphics module will not function if you +/// request a core profile context. Make sure the attributes are +/// set to Default if you want to use the graphics module. +/// +/// Setting the debug attribute flag will request a context with +/// additional debugging features enabled. Depending on the +/// system, this might be required for advanced OpenGL debugging. +/// OpenGL debugging is disabled by default. +/// +/// Special Note for OS X: +/// Apple only supports choosing between either a legacy context +/// (OpenGL 2.1) or a core context (OpenGL version depends on the +/// operating system version but is at least 3.2). Compatibility +/// contexts are not supported. Further information is available on the +/// +/// OpenGL Capabilities Tables page. OS X also currently does +/// not support debug contexts. +/// +/// Please note that these values are only a hint. +/// No failure will be reported if one or more of these values +/// are not supported by the system; instead, SFML will try to +/// find the closest valid match. You can then retrieve the +/// settings that the window actually used to create its context, +/// with Window::getSettings(). +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Event.hpp b/include/SFML/Window/Event.hpp new file mode 100644 index 0000000..0850adf --- /dev/null +++ b/include/SFML/Window/Event.hpp @@ -0,0 +1,284 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_EVENT_HPP +#define SFML_EVENT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Defines a system event and its parameters +/// +//////////////////////////////////////////////////////////// +class Event +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Size events parameters (Resized) + /// + //////////////////////////////////////////////////////////// + struct SizeEvent + { + unsigned int width; ///< New width, in pixels + unsigned int height; ///< New height, in pixels + }; + + //////////////////////////////////////////////////////////// + /// \brief Keyboard event parameters (KeyPressed, KeyReleased) + /// + //////////////////////////////////////////////////////////// + struct KeyEvent + { + Keyboard::Key code; ///< Code of the key that has been pressed + bool alt; ///< Is the Alt key pressed? + bool control; ///< Is the Control key pressed? + bool shift; ///< Is the Shift key pressed? + bool system; ///< Is the System key pressed? + }; + + //////////////////////////////////////////////////////////// + /// \brief Text event parameters (TextEntered) + /// + //////////////////////////////////////////////////////////// + struct TextEvent + { + Uint32 unicode; ///< UTF-32 Unicode value of the character + }; + + //////////////////////////////////////////////////////////// + /// \brief Mouse move event parameters (MouseMoved) + /// + //////////////////////////////////////////////////////////// + struct MouseMoveEvent + { + int x; ///< X position of the mouse pointer, relative to the left of the owner window + int y; ///< Y position of the mouse pointer, relative to the top of the owner window + }; + + //////////////////////////////////////////////////////////// + /// \brief Mouse buttons events parameters + /// (MouseButtonPressed, MouseButtonReleased) + /// + //////////////////////////////////////////////////////////// + struct MouseButtonEvent + { + Mouse::Button button; ///< Code of the button that has been pressed + int x; ///< X position of the mouse pointer, relative to the left of the owner window + int y; ///< Y position of the mouse pointer, relative to the top of the owner window + }; + + //////////////////////////////////////////////////////////// + /// \brief Mouse wheel events parameters (MouseWheelMoved) + /// + /// \deprecated This event is deprecated and potentially inaccurate. + /// Use MouseWheelScrollEvent instead. + /// + //////////////////////////////////////////////////////////// + struct MouseWheelEvent + { + int delta; ///< Number of ticks the wheel has moved (positive is up, negative is down) + int x; ///< X position of the mouse pointer, relative to the left of the owner window + int y; ///< Y position of the mouse pointer, relative to the top of the owner window + }; + + //////////////////////////////////////////////////////////// + /// \brief Mouse wheel events parameters (MouseWheelScrolled) + /// + //////////////////////////////////////////////////////////// + struct MouseWheelScrollEvent + { + Mouse::Wheel wheel; ///< Which wheel (for mice with multiple ones) + float delta; ///< Wheel offset (positive is up/left, negative is down/right). High-precision mice may use non-integral offsets. + int x; ///< X position of the mouse pointer, relative to the left of the owner window + int y; ///< Y position of the mouse pointer, relative to the top of the owner window + }; + + //////////////////////////////////////////////////////////// + /// \brief Joystick connection events parameters + /// (JoystickConnected, JoystickDisconnected) + /// + //////////////////////////////////////////////////////////// + struct JoystickConnectEvent + { + unsigned int joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1]) + }; + + //////////////////////////////////////////////////////////// + /// \brief Joystick axis move event parameters (JoystickMoved) + /// + //////////////////////////////////////////////////////////// + struct JoystickMoveEvent + { + unsigned int joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1]) + Joystick::Axis axis; ///< Axis on which the joystick moved + float position; ///< New position on the axis (in range [-100 .. 100]) + }; + + //////////////////////////////////////////////////////////// + /// \brief Joystick buttons events parameters + /// (JoystickButtonPressed, JoystickButtonReleased) + /// + //////////////////////////////////////////////////////////// + struct JoystickButtonEvent + { + unsigned int joystickId; ///< Index of the joystick (in range [0 .. Joystick::Count - 1]) + unsigned int button; ///< Index of the button that has been pressed (in range [0 .. Joystick::ButtonCount - 1]) + }; + + //////////////////////////////////////////////////////////// + /// \brief Touch events parameters (TouchBegan, TouchMoved, TouchEnded) + /// + //////////////////////////////////////////////////////////// + struct TouchEvent + { + unsigned int finger; ///< Index of the finger in case of multi-touch events + int x; ///< X position of the touch, relative to the left of the owner window + int y; ///< Y position of the touch, relative to the top of the owner window + }; + + //////////////////////////////////////////////////////////// + /// \brief Sensor event parameters (SensorChanged) + /// + //////////////////////////////////////////////////////////// + struct SensorEvent + { + Sensor::Type type; ///< Type of the sensor + float x; ///< Current value of the sensor on X axis + float y; ///< Current value of the sensor on Y axis + float z; ///< Current value of the sensor on Z axis + }; + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the different types of events + /// + //////////////////////////////////////////////////////////// + enum EventType + { + Closed, ///< The window requested to be closed (no data) + Resized, ///< The window was resized (data in event.size) + LostFocus, ///< The window lost the focus (no data) + GainedFocus, ///< The window gained the focus (no data) + TextEntered, ///< A character was entered (data in event.text) + KeyPressed, ///< A key was pressed (data in event.key) + KeyReleased, ///< A key was released (data in event.key) + MouseWheelMoved, ///< The mouse wheel was scrolled (data in event.mouseWheel) (deprecated) + MouseWheelScrolled, ///< The mouse wheel was scrolled (data in event.mouseWheelScroll) + MouseButtonPressed, ///< A mouse button was pressed (data in event.mouseButton) + MouseButtonReleased, ///< A mouse button was released (data in event.mouseButton) + MouseMoved, ///< The mouse cursor moved (data in event.mouseMove) + MouseEntered, ///< The mouse cursor entered the area of the window (no data) + MouseLeft, ///< The mouse cursor left the area of the window (no data) + JoystickButtonPressed, ///< A joystick button was pressed (data in event.joystickButton) + JoystickButtonReleased, ///< A joystick button was released (data in event.joystickButton) + JoystickMoved, ///< The joystick moved along an axis (data in event.joystickMove) + JoystickConnected, ///< A joystick was connected (data in event.joystickConnect) + JoystickDisconnected, ///< A joystick was disconnected (data in event.joystickConnect) + TouchBegan, ///< A touch event began (data in event.touch) + TouchMoved, ///< A touch moved (data in event.touch) + TouchEnded, ///< A touch event ended (data in event.touch) + SensorChanged, ///< A sensor value changed (data in event.sensor) + + Count ///< Keep last -- the total number of event types + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + EventType type; ///< Type of the event + + union + { + SizeEvent size; ///< Size event parameters (Event::Resized) + KeyEvent key; ///< Key event parameters (Event::KeyPressed, Event::KeyReleased) + TextEvent text; ///< Text event parameters (Event::TextEntered) + MouseMoveEvent mouseMove; ///< Mouse move event parameters (Event::MouseMoved) + MouseButtonEvent mouseButton; ///< Mouse button event parameters (Event::MouseButtonPressed, Event::MouseButtonReleased) + MouseWheelEvent mouseWheel; ///< Mouse wheel event parameters (Event::MouseWheelMoved) (deprecated) + MouseWheelScrollEvent mouseWheelScroll; ///< Mouse wheel event parameters (Event::MouseWheelScrolled) + JoystickMoveEvent joystickMove; ///< Joystick move event parameters (Event::JoystickMoved) + JoystickButtonEvent joystickButton; ///< Joystick button event parameters (Event::JoystickButtonPressed, Event::JoystickButtonReleased) + JoystickConnectEvent joystickConnect; ///< Joystick (dis)connect event parameters (Event::JoystickConnected, Event::JoystickDisconnected) + TouchEvent touch; ///< Touch events parameters (Event::TouchBegan, Event::TouchMoved, Event::TouchEnded) + SensorEvent sensor; ///< Sensor event parameters (Event::SensorChanged) + }; +}; + +} // namespace sf + + +#endif // SFML_EVENT_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Event +/// \ingroup window +/// +/// sf::Event holds all the informations about a system event +/// that just happened. Events are retrieved using the +/// sf::Window::pollEvent and sf::Window::waitEvent functions. +/// +/// A sf::Event instance contains the type of the event +/// (mouse moved, key pressed, window closed, ...) as well +/// as the details about this particular event. Please note that +/// the event parameters are defined in a union, which means that +/// only the member matching the type of the event will be properly +/// filled; all other members will have undefined values and must not +/// be read if the type of the event doesn't match. For example, +/// if you received a KeyPressed event, then you must read the +/// event.key member, all other members such as event.MouseMove +/// or event.text will have undefined values. +/// +/// Usage example: +/// \code +/// sf::Event event; +/// while (window.pollEvent(event)) +/// { +/// // Request for closing the window +/// if (event.type == sf::Event::Closed) +/// window.close(); +/// +/// // The escape key was pressed +/// if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)) +/// window.close(); +/// +/// // The window was resized +/// if (event.type == sf::Event::Resized) +/// doSomethingWithTheNewSize(event.size.width, event.size.height); +/// +/// // etc ... +/// } +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Export.hpp b/include/SFML/Window/Export.hpp new file mode 100644 index 0000000..e09f995 --- /dev/null +++ b/include/SFML/Window/Export.hpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_WINDOW_EXPORT_HPP +#define SFML_WINDOW_EXPORT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_WINDOW_EXPORTS) + + #define SFML_WINDOW_API SFML_API_EXPORT + +#else + + #define SFML_WINDOW_API SFML_API_IMPORT + +#endif + + +#endif // SFML_WINDOW_EXPORT_HPP diff --git a/include/SFML/Window/GlResource.hpp b/include/SFML/Window/GlResource.hpp new file mode 100644 index 0000000..627ec30 --- /dev/null +++ b/include/SFML/Window/GlResource.hpp @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GLRESOURCE_HPP +#define SFML_GLRESOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ + +class Context; + +//////////////////////////////////////////////////////////// +/// \brief Base class for classes that require an OpenGL context +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API GlResource +{ +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + GlResource(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~GlResource(); + + //////////////////////////////////////////////////////////// + /// \brief Empty function for ABI compatibility, use acquireTransientContext instead + /// + //////////////////////////////////////////////////////////// + static void ensureGlContext(); + + //////////////////////////////////////////////////////////// + /// \brief RAII helper class to temporarily lock an available context for use + /// + //////////////////////////////////////////////////////////// + class SFML_WINDOW_API TransientContextLock : NonCopyable + { + public: + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TransientContextLock(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~TransientContextLock(); + + private: + Context* m_context; ///< Temporary context, in case we needed to create one + }; +}; + +} // namespace sf + + +#endif // SFML_GLRESOURCE_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::GlResource +/// \ingroup window +/// +/// This class is for internal use only, it must be the base +/// of every class that requires a valid OpenGL context in +/// order to work. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Joystick.hpp b/include/SFML/Window/Joystick.hpp new file mode 100644 index 0000000..463daf0 --- /dev/null +++ b/include/SFML/Window/Joystick.hpp @@ -0,0 +1,227 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_JOYSTICK_HPP +#define SFML_JOYSTICK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Give access to the real-time state of the joysticks +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Joystick +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Constants related to joysticks capabilities + /// + //////////////////////////////////////////////////////////// + enum + { + Count = 8, ///< Maximum number of supported joysticks + ButtonCount = 32, ///< Maximum number of supported buttons + AxisCount = 8 ///< Maximum number of supported axes + }; + + //////////////////////////////////////////////////////////// + /// \brief Axes supported by SFML joysticks + /// + //////////////////////////////////////////////////////////// + enum Axis + { + X, ///< The X axis + Y, ///< The Y axis + Z, ///< The Z axis + R, ///< The R axis + U, ///< The U axis + V, ///< The V axis + PovX, ///< The X axis of the point-of-view hat + PovY ///< The Y axis of the point-of-view hat + }; + + //////////////////////////////////////////////////////////// + /// \brief Structure holding a joystick's identification + /// + //////////////////////////////////////////////////////////// + struct SFML_WINDOW_API Identification + { + Identification(); + + String name; ///< Name of the joystick + unsigned int vendorId; ///< Manufacturer identifier + unsigned int productId; ///< Product identifier + }; + + //////////////////////////////////////////////////////////// + /// \brief Check if a joystick is connected + /// + /// \param joystick Index of the joystick to check + /// + /// \return True if the joystick is connected, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isConnected(unsigned int joystick); + + //////////////////////////////////////////////////////////// + /// \brief Return the number of buttons supported by a joystick + /// + /// If the joystick is not connected, this function returns 0. + /// + /// \param joystick Index of the joystick + /// + /// \return Number of buttons supported by the joystick + /// + //////////////////////////////////////////////////////////// + static unsigned int getButtonCount(unsigned int joystick); + + //////////////////////////////////////////////////////////// + /// \brief Check if a joystick supports a given axis + /// + /// If the joystick is not connected, this function returns false. + /// + /// \param joystick Index of the joystick + /// \param axis Axis to check + /// + /// \return True if the joystick supports the axis, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool hasAxis(unsigned int joystick, Axis axis); + + //////////////////////////////////////////////////////////// + /// \brief Check if a joystick button is pressed + /// + /// If the joystick is not connected, this function returns false. + /// + /// \param joystick Index of the joystick + /// \param button Button to check + /// + /// \return True if the button is pressed, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isButtonPressed(unsigned int joystick, unsigned int button); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of a joystick axis + /// + /// If the joystick is not connected, this function returns 0. + /// + /// \param joystick Index of the joystick + /// \param axis Axis to check + /// + /// \return Current position of the axis, in range [-100 .. 100] + /// + //////////////////////////////////////////////////////////// + static float getAxisPosition(unsigned int joystick, Axis axis); + + //////////////////////////////////////////////////////////// + /// \brief Get the joystick information + /// + /// \param joystick Index of the joystick + /// + /// \return Structure containing joystick information. + /// + //////////////////////////////////////////////////////////// + static Identification getIdentification(unsigned int joystick); + + //////////////////////////////////////////////////////////// + /// \brief Update the states of all joysticks + /// + /// This function is used internally by SFML, so you normally + /// don't have to call it explicitly. However, you may need to + /// call it if you have no window yet (or no window at all): + /// in this case the joystick states are not updated automatically. + /// + //////////////////////////////////////////////////////////// + static void update(); +}; + +} // namespace sf + + +#endif // SFML_JOYSTICK_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Joystick +/// \ingroup window +/// +/// sf::Joystick provides an interface to the state of the +/// joysticks. It only contains static functions, so it's not +/// meant to be instantiated. Instead, each joystick is identified +/// by an index that is passed to the functions of this class. +/// +/// This class allows users to query the state of joysticks at any +/// time and directly, without having to deal with a window and +/// its events. Compared to the JoystickMoved, JoystickButtonPressed +/// and JoystickButtonReleased events, sf::Joystick can retrieve the +/// state of axes and buttons of joysticks at any time +/// (you don't need to store and update a boolean on your side +/// in order to know if a button is pressed or released), and you +/// always get the real state of joysticks, even if they are +/// moved, pressed or released when your window is out of focus +/// and no event is triggered. +/// +/// SFML supports: +/// \li 8 joysticks (sf::Joystick::Count) +/// \li 32 buttons per joystick (sf::Joystick::ButtonCount) +/// \li 8 axes per joystick (sf::Joystick::AxisCount) +/// +/// Unlike the keyboard or mouse, the state of joysticks is sometimes +/// not directly available (depending on the OS), therefore an update() +/// function must be called in order to update the current state of +/// joysticks. When you have a window with event handling, this is done +/// automatically, you don't need to call anything. But if you have no +/// window, or if you want to check joysticks state before creating one, +/// you must call sf::Joystick::update explicitly. +/// +/// Usage example: +/// \code +/// // Is joystick #0 connected? +/// bool connected = sf::Joystick::isConnected(0); +/// +/// // How many buttons does joystick #0 support? +/// unsigned int buttons = sf::Joystick::getButtonCount(0); +/// +/// // Does joystick #0 define a X axis? +/// bool hasX = sf::Joystick::hasAxis(0, sf::Joystick::X); +/// +/// // Is button #2 pressed on joystick #0? +/// bool pressed = sf::Joystick::isButtonPressed(0, 2); +/// +/// // What's the current position of the Y axis on joystick #0? +/// float position = sf::Joystick::getAxisPosition(0, sf::Joystick::Y); +/// \endcode +/// +/// \see sf::Keyboard, sf::Mouse +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Keyboard.hpp b/include/SFML/Window/Keyboard.hpp new file mode 100644 index 0000000..2adad91 --- /dev/null +++ b/include/SFML/Window/Keyboard.hpp @@ -0,0 +1,224 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_KEYBOARD_HPP +#define SFML_KEYBOARD_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Give access to the real-time state of the keyboard +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Keyboard +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Key codes + /// + //////////////////////////////////////////////////////////// + enum Key + { + Unknown = -1, ///< Unhandled key + A = 0, ///< The A key + B, ///< The B key + C, ///< The C key + D, ///< The D key + E, ///< The E key + F, ///< The F key + G, ///< The G key + H, ///< The H key + I, ///< The I key + J, ///< The J key + K, ///< The K key + L, ///< The L key + M, ///< The M key + N, ///< The N key + O, ///< The O key + P, ///< The P key + Q, ///< The Q key + R, ///< The R key + S, ///< The S key + T, ///< The T key + U, ///< The U key + V, ///< The V key + W, ///< The W key + X, ///< The X key + Y, ///< The Y key + Z, ///< The Z key + Num0, ///< The 0 key + Num1, ///< The 1 key + Num2, ///< The 2 key + Num3, ///< The 3 key + Num4, ///< The 4 key + Num5, ///< The 5 key + Num6, ///< The 6 key + Num7, ///< The 7 key + Num8, ///< The 8 key + Num9, ///< The 9 key + Escape, ///< The Escape key + LControl, ///< The left Control key + LShift, ///< The left Shift key + LAlt, ///< The left Alt key + LSystem, ///< The left OS specific key: window (Windows and Linux), apple (MacOS X), ... + RControl, ///< The right Control key + RShift, ///< The right Shift key + RAlt, ///< The right Alt key + RSystem, ///< The right OS specific key: window (Windows and Linux), apple (MacOS X), ... + Menu, ///< The Menu key + LBracket, ///< The [ key + RBracket, ///< The ] key + SemiColon, ///< The ; key + Comma, ///< The , key + Period, ///< The . key + Quote, ///< The ' key + Slash, ///< The / key + BackSlash, ///< The \ key + Tilde, ///< The ~ key + Equal, ///< The = key + Dash, ///< The - key + Space, ///< The Space key + Return, ///< The Return key + BackSpace, ///< The Backspace key + Tab, ///< The Tabulation key + PageUp, ///< The Page up key + PageDown, ///< The Page down key + End, ///< The End key + Home, ///< The Home key + Insert, ///< The Insert key + Delete, ///< The Delete key + Add, ///< The + key + Subtract, ///< The - key + Multiply, ///< The * key + Divide, ///< The / key + Left, ///< Left arrow + Right, ///< Right arrow + Up, ///< Up arrow + Down, ///< Down arrow + Numpad0, ///< The numpad 0 key + Numpad1, ///< The numpad 1 key + Numpad2, ///< The numpad 2 key + Numpad3, ///< The numpad 3 key + Numpad4, ///< The numpad 4 key + Numpad5, ///< The numpad 5 key + Numpad6, ///< The numpad 6 key + Numpad7, ///< The numpad 7 key + Numpad8, ///< The numpad 8 key + Numpad9, ///< The numpad 9 key + F1, ///< The F1 key + F2, ///< The F2 key + F3, ///< The F3 key + F4, ///< The F4 key + F5, ///< The F5 key + F6, ///< The F6 key + F7, ///< The F7 key + F8, ///< The F8 key + F9, ///< The F9 key + F10, ///< The F10 key + F11, ///< The F11 key + F12, ///< The F12 key + F13, ///< The F13 key + F14, ///< The F14 key + F15, ///< The F15 key + Pause, ///< The Pause key + + KeyCount ///< Keep last -- the total number of keyboard keys + }; + + //////////////////////////////////////////////////////////// + /// \brief Check if a key is pressed + /// + /// \param key Key to check + /// + /// \return True if the key is pressed, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isKeyPressed(Key key); + + //////////////////////////////////////////////////////////// + /// \brief Show or hide the virtual keyboard + /// + /// Warning: the virtual keyboard is not supported on all + /// systems. It will typically be implemented on mobile OSes + /// (Android, iOS) but not on desktop OSes (Windows, Linux, ...). + /// + /// If the virtual keyboard is not available, this function does + /// nothing. + /// + /// \param visible True to show, false to hide + /// + //////////////////////////////////////////////////////////// + static void setVirtualKeyboardVisible(bool visible); +}; + +} // namespace sf + + +#endif // SFML_KEYBOARD_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Keyboard +/// \ingroup window +/// +/// sf::Keyboard provides an interface to the state of the +/// keyboard. It only contains static functions (a single +/// keyboard is assumed), so it's not meant to be instantiated. +/// +/// This class allows users to query the keyboard state at any +/// time and directly, without having to deal with a window and +/// its events. Compared to the KeyPressed and KeyReleased events, +/// sf::Keyboard can retrieve the state of a key at any time +/// (you don't need to store and update a boolean on your side +/// in order to know if a key is pressed or released), and you +/// always get the real state of the keyboard, even if keys are +/// pressed or released when your window is out of focus and no +/// event is triggered. +/// +/// Usage example: +/// \code +/// if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) +/// { +/// // move left... +/// } +/// else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) +/// { +/// // move right... +/// } +/// else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) +/// { +/// // quit... +/// } +/// \endcode +/// +/// \see sf::Joystick, sf::Mouse, sf::Touch +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Mouse.hpp b/include/SFML/Window/Mouse.hpp new file mode 100644 index 0000000..c83d6fa --- /dev/null +++ b/include/SFML/Window/Mouse.hpp @@ -0,0 +1,177 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_MOUSE_HPP +#define SFML_MOUSE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Window; + +//////////////////////////////////////////////////////////// +/// \brief Give access to the real-time state of the mouse +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Mouse +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Mouse buttons + /// + //////////////////////////////////////////////////////////// + enum Button + { + Left, ///< The left mouse button + Right, ///< The right mouse button + Middle, ///< The middle (wheel) mouse button + XButton1, ///< The first extra mouse button + XButton2, ///< The second extra mouse button + + ButtonCount ///< Keep last -- the total number of mouse buttons + }; + + //////////////////////////////////////////////////////////// + /// \brief Mouse wheels + /// + //////////////////////////////////////////////////////////// + enum Wheel + { + VerticalWheel, ///< The vertical mouse wheel + HorizontalWheel ///< The horizontal mouse wheel + }; + + //////////////////////////////////////////////////////////// + /// \brief Check if a mouse button is pressed + /// + /// \param button Button to check + /// + /// \return True if the button is pressed, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isButtonPressed(Button button); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of the mouse in desktop coordinates + /// + /// This function returns the global position of the mouse + /// cursor on the desktop. + /// + /// \return Current position of the mouse + /// + //////////////////////////////////////////////////////////// + static Vector2i getPosition(); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of the mouse in window coordinates + /// + /// This function returns the current position of the mouse + /// cursor, relative to the given window. + /// + /// \param relativeTo Reference window + /// + /// \return Current position of the mouse + /// + //////////////////////////////////////////////////////////// + static Vector2i getPosition(const Window& relativeTo); + + //////////////////////////////////////////////////////////// + /// \brief Set the current position of the mouse in desktop coordinates + /// + /// This function sets the global position of the mouse + /// cursor on the desktop. + /// + /// \param position New position of the mouse + /// + //////////////////////////////////////////////////////////// + static void setPosition(const Vector2i& position); + + //////////////////////////////////////////////////////////// + /// \brief Set the current position of the mouse in window coordinates + /// + /// This function sets the current position of the mouse + /// cursor, relative to the given window. + /// + /// \param position New position of the mouse + /// \param relativeTo Reference window + /// + //////////////////////////////////////////////////////////// + static void setPosition(const Vector2i& position, const Window& relativeTo); +}; + +} // namespace sf + + +#endif // SFML_MOUSE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Mouse +/// \ingroup window +/// +/// sf::Mouse provides an interface to the state of the +/// mouse. It only contains static functions (a single +/// mouse is assumed), so it's not meant to be instantiated. +/// +/// This class allows users to query the mouse state at any +/// time and directly, without having to deal with a window and +/// its events. Compared to the MouseMoved, MouseButtonPressed +/// and MouseButtonReleased events, sf::Mouse can retrieve the +/// state of the cursor and the buttons at any time +/// (you don't need to store and update a boolean on your side +/// in order to know if a button is pressed or released), and you +/// always get the real state of the mouse, even if it is +/// moved, pressed or released when your window is out of focus +/// and no event is triggered. +/// +/// The setPosition and getPosition functions can be used to change +/// or retrieve the current position of the mouse pointer. There are +/// two versions: one that operates in global coordinates (relative +/// to the desktop) and one that operates in window coordinates +/// (relative to a specific window). +/// +/// Usage example: +/// \code +/// if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) +/// { +/// // left click... +/// } +/// +/// // get global mouse position +/// sf::Vector2i position = sf::Mouse::getPosition(); +/// +/// // set mouse position relative to a window +/// sf::Mouse::setPosition(sf::Vector2i(100, 200), window); +/// \endcode +/// +/// \see sf::Joystick, sf::Keyboard, sf::Touch +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Sensor.hpp b/include/SFML/Window/Sensor.hpp new file mode 100644 index 0000000..1fd23b3 --- /dev/null +++ b/include/SFML/Window/Sensor.hpp @@ -0,0 +1,150 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SENSOR_HPP +#define SFML_SENSOR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Give access to the real-time state of the sensors +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Sensor +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Sensor type + /// + //////////////////////////////////////////////////////////// + enum Type + { + Accelerometer, ///< Measures the raw acceleration (m/s^2) + Gyroscope, ///< Measures the raw rotation rates (degrees/s) + Magnetometer, ///< Measures the ambient magnetic field (micro-teslas) + Gravity, ///< Measures the direction and intensity of gravity, independent of device acceleration (m/s^2) + UserAcceleration, ///< Measures the direction and intensity of device acceleration, independent of the gravity (m/s^2) + Orientation, ///< Measures the absolute 3D orientation (degrees) + + Count ///< Keep last -- the total number of sensor types + }; + + //////////////////////////////////////////////////////////// + /// \brief Check if a sensor is available on the underlying platform + /// + /// \param sensor Sensor to check + /// + /// \return True if the sensor is available, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isAvailable(Type sensor); + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable a sensor + /// + /// All sensors are disabled by default, to avoid consuming too + /// much battery power. Once a sensor is enabled, it starts + /// sending events of the corresponding type. + /// + /// This function does nothing if the sensor is unavailable. + /// + /// \param sensor Sensor to enable + /// \param enabled True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + static void setEnabled(Type sensor, bool enabled); + + //////////////////////////////////////////////////////////// + /// \brief Get the current sensor value + /// + /// \param sensor Sensor to read + /// + /// \return The current sensor value + /// + //////////////////////////////////////////////////////////// + static Vector3f getValue(Type sensor); +}; + +} // namespace sf + + +#endif // SFML_SENSOR_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Sensor +/// \ingroup window +/// +/// sf::Sensor provides an interface to the state of the +/// various sensors that a device provides. It only contains static +/// functions, so it's not meant to be instantiated. +/// +/// This class allows users to query the sensors values at any +/// time and directly, without having to deal with a window and +/// its events. Compared to the SensorChanged event, sf::Sensor +/// can retrieve the state of a sensor at any time (you don't need to +/// store and update its current value on your side). +/// +/// Depending on the OS and hardware of the device (phone, tablet, ...), +/// some sensor types may not be available. You should always check +/// the availability of a sensor before trying to read it, with the +/// sf::Sensor::isAvailable function. +/// +/// You may wonder why some sensor types look so similar, for example +/// Accelerometer and Gravity / UserAcceleration. The first one +/// is the raw measurement of the acceleration, and takes into account +/// both the earth gravity and the user movement. The others are +/// more precise: they provide these components separately, which is +/// usually more useful. In fact they are not direct sensors, they +/// are computed internally based on the raw acceleration and other sensors. +/// This is exactly the same for Gyroscope vs Orientation. +/// +/// Because sensors consume a non-negligible amount of current, they are +/// all disabled by default. You must call sf::Sensor::setEnabled for each +/// sensor in which you are interested. +/// +/// Usage example: +/// \code +/// if (sf::Sensor::isAvailable(sf::Sensor::Gravity)) +/// { +/// // gravity sensor is available +/// } +/// +/// // enable the gravity sensor +/// sf::Sensor::setEnabled(sf::Sensor::Gravity, true); +/// +/// // get the current value of gravity +/// sf::Vector3f gravity = sf::Sensor::getValue(sf::Sensor::Gravity); +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Touch.hpp b/include/SFML/Window/Touch.hpp new file mode 100644 index 0000000..933523e --- /dev/null +++ b/include/SFML/Window/Touch.hpp @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TOUCH_HPP +#define SFML_TOUCH_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Window; + +//////////////////////////////////////////////////////////// +/// \brief Give access to the real-time state of the touches +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Touch +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if a touch event is currently down + /// + /// \param finger Finger index + /// + /// \return True if \a finger is currently touching the screen, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isDown(unsigned int finger); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of a touch in desktop coordinates + /// + /// This function returns the current touch position + /// in global (desktop) coordinates. + /// + /// \param finger Finger index + /// + /// \return Current position of \a finger, or undefined if it's not down + /// + //////////////////////////////////////////////////////////// + static Vector2i getPosition(unsigned int finger); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of a touch in window coordinates + /// + /// This function returns the current touch position + /// relative to the given window. + /// + /// \param finger Finger index + /// \param relativeTo Reference window + /// + /// \return Current position of \a finger, or undefined if it's not down + /// + //////////////////////////////////////////////////////////// + static Vector2i getPosition(unsigned int finger, const Window& relativeTo); +}; + +} // namespace sf + + +#endif // SFML_TOUCH_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Touch +/// \ingroup window +/// +/// sf::Touch provides an interface to the state of the +/// touches. It only contains static functions, so it's not +/// meant to be instantiated. +/// +/// This class allows users to query the touches state at any +/// time and directly, without having to deal with a window and +/// its events. Compared to the TouchBegan, TouchMoved +/// and TouchEnded events, sf::Touch can retrieve the +/// state of the touches at any time (you don't need to store and +/// update a boolean on your side in order to know if a touch is down), +/// and you always get the real state of the touches, even if they +/// happen when your window is out of focus and no event is triggered. +/// +/// The getPosition function can be used to retrieve the current +/// position of a touch. There are two versions: one that operates +/// in global coordinates (relative to the desktop) and one that +/// operates in window coordinates (relative to a specific window). +/// +/// Touches are identified by an index (the "finger"), so that in +/// multi-touch events, individual touches can be tracked correctly. +/// As long as a finger touches the screen, it will keep the same index +/// even if other fingers start or stop touching the screen in the +/// meantime. As a consequence, active touch indices may not always be +/// sequential (i.e. touch number 0 may be released while touch number 1 +/// is still down). +/// +/// Usage example: +/// \code +/// if (sf::Touch::isDown(0)) +/// { +/// // touch 0 is down +/// } +/// +/// // get global position of touch 1 +/// sf::Vector2i globalPos = sf::Touch::getPosition(1); +/// +/// // get position of touch 1 relative to a window +/// sf::Vector2i relativePos = sf::Touch::getPosition(1, window); +/// \endcode +/// +/// \see sf::Joystick, sf::Keyboard, sf::Mouse +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/VideoMode.hpp b/include/SFML/Window/VideoMode.hpp new file mode 100644 index 0000000..31c3a20 --- /dev/null +++ b/include/SFML/Window/VideoMode.hpp @@ -0,0 +1,228 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VIDEOMODE_HPP +#define SFML_VIDEOMODE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief VideoMode defines a video mode (width, height, bpp) +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API VideoMode +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructors initializes all members to 0. + /// + //////////////////////////////////////////////////////////// + VideoMode(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the video mode with its attributes + /// + /// \param modeWidth Width in pixels + /// \param modeHeight Height in pixels + /// \param modeBitsPerPixel Pixel depths in bits per pixel + /// + //////////////////////////////////////////////////////////// + VideoMode(unsigned int modeWidth, unsigned int modeHeight, unsigned int modeBitsPerPixel = 32); + + //////////////////////////////////////////////////////////// + /// \brief Get the current desktop video mode + /// + /// \return Current desktop video mode + /// + //////////////////////////////////////////////////////////// + static VideoMode getDesktopMode(); + + //////////////////////////////////////////////////////////// + /// \brief Retrieve all the video modes supported in fullscreen mode + /// + /// When creating a fullscreen window, the video mode is restricted + /// to be compatible with what the graphics driver and monitor + /// support. This function returns the complete list of all video + /// modes that can be used in fullscreen mode. + /// The returned array is sorted from best to worst, so that + /// the first element will always give the best mode (higher + /// width, height and bits-per-pixel). + /// + /// \return Array containing all the supported fullscreen modes + /// + //////////////////////////////////////////////////////////// + static const std::vector& getFullscreenModes(); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the video mode is valid + /// + /// The validity of video modes is only relevant when using + /// fullscreen windows; otherwise any video mode can be used + /// with no restriction. + /// + /// \return True if the video mode is valid for fullscreen mode + /// + //////////////////////////////////////////////////////////// + bool isValid() const; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int width; ///< Video mode width, in pixels + unsigned int height; ///< Video mode height, in pixels + unsigned int bitsPerPixel; ///< Video mode pixel depth, in bits per pixels +}; + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of == operator to compare two video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if modes are equal +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator ==(const VideoMode& left, const VideoMode& right); + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of != operator to compare two video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if modes are different +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator !=(const VideoMode& left, const VideoMode& right); + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of < operator to compare video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if \a left is lesser than \a right +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator <(const VideoMode& left, const VideoMode& right); + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of > operator to compare video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if \a left is greater than \a right +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator >(const VideoMode& left, const VideoMode& right); + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of <= operator to compare video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if \a left is lesser or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator <=(const VideoMode& left, const VideoMode& right); + +//////////////////////////////////////////////////////////// +/// \relates VideoMode +/// \brief Overload of >= operator to compare video modes +/// +/// \param left Left operand (a video mode) +/// \param right Right operand (a video mode) +/// +/// \return True if \a left is greater or equal than \a right +/// +//////////////////////////////////////////////////////////// +SFML_WINDOW_API bool operator >=(const VideoMode& left, const VideoMode& right); + +} // namespace sf + + +#endif // SFML_VIDEOMODE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::VideoMode +/// \ingroup window +/// +/// A video mode is defined by a width and a height (in pixels) +/// and a depth (in bits per pixel). Video modes are used to +/// setup windows (sf::Window) at creation time. +/// +/// The main usage of video modes is for fullscreen mode: +/// indeed you must use one of the valid video modes +/// allowed by the OS (which are defined by what the monitor +/// and the graphics card support), otherwise your window +/// creation will just fail. +/// +/// sf::VideoMode provides a static function for retrieving +/// the list of all the video modes supported by the system: +/// getFullscreenModes(). +/// +/// A custom video mode can also be checked directly for +/// fullscreen compatibility with its isValid() function. +/// +/// Additionally, sf::VideoMode provides a static function +/// to get the mode currently used by the desktop: getDesktopMode(). +/// This allows to build windows with the same size or pixel +/// depth as the current resolution. +/// +/// Usage example: +/// \code +/// // Display the list of all the video modes available for fullscreen +/// std::vector modes = sf::VideoMode::getFullscreenModes(); +/// for (std::size_t i = 0; i < modes.size(); ++i) +/// { +/// sf::VideoMode mode = modes[i]; +/// std::cout << "Mode #" << i << ": " +/// << mode.width << "x" << mode.height << " - " +/// << mode.bitsPerPixel << " bpp" << std::endl; +/// } +/// +/// // Create a window with the same pixel depth as the desktop +/// sf::VideoMode desktop = sf::VideoMode::getDesktopMode(); +/// window.create(sf::VideoMode(1024, 768, desktop.bitsPerPixel), "SFML window"); +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Window.hpp b/include/SFML/Window/Window.hpp new file mode 100644 index 0000000..83cb879 --- /dev/null +++ b/include/SFML/Window/Window.hpp @@ -0,0 +1,594 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_WINDOW_HPP +#define SFML_WINDOW_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +namespace priv +{ + class GlContext; + class WindowImpl; +} + +class Event; + +//////////////////////////////////////////////////////////// +/// \brief Window that serves as a target for OpenGL rendering +/// +//////////////////////////////////////////////////////////// +class SFML_WINDOW_API Window : GlResource, NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor doesn't actually create the window, + /// use the other constructors or call create() to do so. + /// + //////////////////////////////////////////////////////////// + Window(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a new window + /// + /// This constructor creates the window with the size and pixel + /// depth defined in \a mode. An optional style can be passed to + /// customize the look and behavior of the window (borders, + /// title bar, resizable, closable, ...). If \a style contains + /// Style::Fullscreen, then \a mode must be a valid video mode. + /// + /// The fourth parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. + /// + /// \param mode Video mode to use (defines the width, height and depth of the rendering area of the window) + /// \param title Title of the window + /// \param style %Window style, a bitwise OR combination of sf::Style enumerators + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + Window(VideoMode mode, const String& title, Uint32 style = Style::Default, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Construct the window from an existing control + /// + /// Use this constructor if you want to create an OpenGL + /// rendering area into an already existing control. + /// + /// The second parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. + /// + /// \param handle Platform-specific handle of the control + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + explicit Window(WindowHandle handle, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Closes the window and frees all the resources attached to it. + /// + //////////////////////////////////////////////////////////// + virtual ~Window(); + + //////////////////////////////////////////////////////////// + /// \brief Create (or recreate) the window + /// + /// If the window was already created, it closes it first. + /// If \a style contains Style::Fullscreen, then \a mode + /// must be a valid video mode. + /// + /// The fourth parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. + /// + /// \param mode Video mode to use (defines the width, height and depth of the rendering area of the window) + /// \param title Title of the window + /// \param style %Window style, a bitwise OR combination of sf::Style enumerators + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + void create(VideoMode mode, const String& title, Uint32 style = Style::Default, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Create (or recreate) the window from an existing control + /// + /// Use this function if you want to create an OpenGL + /// rendering area into an already existing control. + /// If the window was already created, it closes it first. + /// + /// The second parameter is an optional structure specifying + /// advanced OpenGL context settings such as antialiasing, + /// depth-buffer bits, etc. + /// + /// \param handle Platform-specific handle of the control + /// \param settings Additional settings for the underlying OpenGL context + /// + //////////////////////////////////////////////////////////// + void create(WindowHandle handle, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Close the window and destroy all the attached resources + /// + /// After calling this function, the sf::Window instance remains + /// valid and you can call create() to recreate the window. + /// All other functions such as pollEvent() or display() will + /// still work (i.e. you don't have to test isOpen() every time), + /// and will have no effect on closed windows. + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the window is open + /// + /// This function returns whether or not the window exists. + /// Note that a hidden window (setVisible(false)) is open + /// (therefore this function would return true). + /// + /// \return True if the window is open, false if it has been closed + /// + //////////////////////////////////////////////////////////// + bool isOpen() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the settings of the OpenGL context of the window + /// + /// Note that these settings may be different from what was + /// passed to the constructor or the create() function, + /// if one or more settings were not supported. In this case, + /// SFML chose the closest match. + /// + /// \return Structure containing the OpenGL context settings + /// + //////////////////////////////////////////////////////////// + const ContextSettings& getSettings() const; + + //////////////////////////////////////////////////////////// + /// \brief Pop the event on top of the event queue, if any, and return it + /// + /// This function is not blocking: if there's no pending event then + /// it will return false and leave \a event unmodified. + /// Note that more than one event may be present in the event queue, + /// thus you should always call this function in a loop + /// to make sure that you process every pending event. + /// \code + /// sf::Event event; + /// while (window.pollEvent(event)) + /// { + /// // process event... + /// } + /// \endcode + /// + /// \param event Event to be returned + /// + /// \return True if an event was returned, or false if the event queue was empty + /// + /// \see waitEvent + /// + //////////////////////////////////////////////////////////// + bool pollEvent(Event& event); + + //////////////////////////////////////////////////////////// + /// \brief Wait for an event and return it + /// + /// This function is blocking: if there's no pending event then + /// it will wait until an event is received. + /// After this function returns (and no error occurred), + /// the \a event object is always valid and filled properly. + /// This function is typically used when you have a thread that + /// is dedicated to events handling: you want to make this thread + /// sleep as long as no new event is received. + /// \code + /// sf::Event event; + /// if (window.waitEvent(event)) + /// { + /// // process event... + /// } + /// \endcode + /// + /// \param event Event to be returned + /// + /// \return False if any error occurred + /// + /// \see pollEvent + /// + //////////////////////////////////////////////////////////// + bool waitEvent(Event& event); + + //////////////////////////////////////////////////////////// + /// \brief Get the position of the window + /// + /// \return Position of the window, in pixels + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + Vector2i getPosition() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the position of the window on screen + /// + /// This function only works for top-level windows + /// (i.e. it will be ignored for windows created from + /// the handle of a child window/control). + /// + /// \param position New position, in pixels + /// + /// \see getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(const Vector2i& position); + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the rendering region of the window + /// + /// The size doesn't include the titlebar and borders + /// of the window. + /// + /// \return Size in pixels + /// + /// \see setSize + /// + //////////////////////////////////////////////////////////// + Vector2u getSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the size of the rendering region of the window + /// + /// \param size New size, in pixels + /// + /// \see getSize + /// + //////////////////////////////////////////////////////////// + void setSize(const Vector2u& size); + + //////////////////////////////////////////////////////////// + /// \brief Change the title of the window + /// + /// \param title New title + /// + /// \see setIcon + /// + //////////////////////////////////////////////////////////// + void setTitle(const String& title); + + //////////////////////////////////////////////////////////// + /// \brief Change the window's icon + /// + /// \a pixels must be an array of \a width x \a height pixels + /// in 32-bits RGBA format. + /// + /// The OS default icon is used by default. + /// + /// \param width Icon's width, in pixels + /// \param height Icon's height, in pixels + /// \param pixels Pointer to the array of pixels in memory. The + /// pixels are copied, so you need not keep the + /// source alive after calling this function. + /// + /// \see setTitle + /// + //////////////////////////////////////////////////////////// + void setIcon(unsigned int width, unsigned int height, const Uint8* pixels); + + //////////////////////////////////////////////////////////// + /// \brief Show or hide the window + /// + /// The window is shown by default. + /// + /// \param visible True to show the window, false to hide it + /// + //////////////////////////////////////////////////////////// + void setVisible(bool visible); + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable vertical synchronization + /// + /// Activating vertical synchronization will limit the number + /// of frames displayed to the refresh rate of the monitor. + /// This can avoid some visual artifacts, and limit the framerate + /// to a good value (but not constant across different computers). + /// + /// Vertical synchronization is disabled by default. + /// + /// \param enabled True to enable v-sync, false to deactivate it + /// + //////////////////////////////////////////////////////////// + void setVerticalSyncEnabled(bool enabled); + + //////////////////////////////////////////////////////////// + /// \brief Show or hide the mouse cursor + /// + /// The mouse cursor is visible by default. + /// + /// \param visible True to show the mouse cursor, false to hide it + /// + //////////////////////////////////////////////////////////// + void setMouseCursorVisible(bool visible); + + //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor + /// + /// If set, grabs the mouse cursor inside this window's client + /// area so it may no longer be moved outside its bounds. + /// Note that grabbing is only active while the window has + /// focus. + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// + /// \brief Enable or disable automatic key-repeat + /// + /// If key repeat is enabled, you will receive repeated + /// KeyPressed events while keeping a key pressed. If it is disabled, + /// you will only get a single event when the key is pressed. + /// + /// Key repeat is enabled by default. + /// + /// \param enabled True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + void setKeyRepeatEnabled(bool enabled); + + //////////////////////////////////////////////////////////// + /// \brief Limit the framerate to a maximum fixed frequency + /// + /// If a limit is set, the window will use a small delay after + /// each call to display() to ensure that the current frame + /// lasted long enough to match the framerate limit. + /// SFML will try to match the given limit as much as it can, + /// but since it internally uses sf::sleep, whose precision + /// depends on the underlying OS, the results may be a little + /// unprecise as well (for example, you can get 65 FPS when + /// requesting 60). + /// + /// \param limit Framerate limit, in frames per seconds (use 0 to disable limit) + /// + //////////////////////////////////////////////////////////// + void setFramerateLimit(unsigned int limit); + + //////////////////////////////////////////////////////////// + /// \brief Change the joystick threshold + /// + /// The joystick threshold is the value below which + /// no JoystickMoved event will be generated. + /// + /// The threshold value is 0.1 by default. + /// + /// \param threshold New threshold, in the range [0, 100] + /// + //////////////////////////////////////////////////////////// + void setJoystickThreshold(float threshold); + + //////////////////////////////////////////////////////////// + /// \brief Activate or deactivate the window as the current target + /// for OpenGL rendering + /// + /// A window is active only on the current thread, if you want to + /// make it active on another thread you have to deactivate it + /// on the previous thread first if it was active. + /// Only one window can be active on a thread at a time, thus + /// the window previously active (if any) automatically gets deactivated. + /// This is not to be confused with requestFocus(). + /// + /// \param active True to activate, false to deactivate + /// + /// \return True if operation was successful, false otherwise + /// + //////////////////////////////////////////////////////////// + bool setActive(bool active = true) const; + + //////////////////////////////////////////////////////////// + /// \brief Request the current window to be made the active + /// foreground window + /// + /// At any given time, only one window may have the input focus + /// to receive input events such as keystrokes or mouse events. + /// If a window requests focus, it only hints to the operating + /// system, that it would like to be focused. The operating system + /// is free to deny the request. + /// This is not to be confused with setActive(). + /// + /// \see hasFocus + /// + //////////////////////////////////////////////////////////// + void requestFocus(); + + //////////////////////////////////////////////////////////// + /// \brief Check whether the window has the input focus + /// + /// At any given time, only one window may have the input focus + /// to receive input events such as keystrokes or most mouse + /// events. + /// + /// \return True if window has focus, false otherwise + /// \see requestFocus + /// + //////////////////////////////////////////////////////////// + bool hasFocus() const; + + //////////////////////////////////////////////////////////// + /// \brief Display on screen what has been rendered to the window so far + /// + /// This function is typically called after all OpenGL rendering + /// has been done for the current frame, in order to show + /// it on screen. + /// + //////////////////////////////////////////////////////////// + void display(); + + //////////////////////////////////////////////////////////// + /// \brief Get the OS-specific handle of the window + /// + /// The type of the returned handle is sf::WindowHandle, + /// which is a typedef to the handle type defined by the OS. + /// You shouldn't need to use this function, unless you have + /// very specific stuff to implement that SFML doesn't support, + /// or implement a temporary workaround until a bug is fixed. + /// + /// \return System handle of the window + /// + //////////////////////////////////////////////////////////// + WindowHandle getSystemHandle() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Function called after the window has been created + /// + /// This function is called so that derived classes can + /// perform their own specific initialization as soon as + /// the window is created. + /// + //////////////////////////////////////////////////////////// + virtual void onCreate(); + + //////////////////////////////////////////////////////////// + /// \brief Function called after the window has been resized + /// + /// This function is called so that derived classes can + /// perform custom actions when the size of the window changes. + /// + //////////////////////////////////////////////////////////// + virtual void onResize(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Processes an event before it is sent to the user + /// + /// This function is called every time an event is received + /// from the internal window (through pollEvent or waitEvent). + /// It filters out unwanted events, and performs whatever internal + /// stuff the window needs before the event is returned to the + /// user. + /// + /// \param event Event to filter + /// + //////////////////////////////////////////////////////////// + bool filterEvent(const Event& event); + + //////////////////////////////////////////////////////////// + /// \brief Perform some common internal initializations + /// + //////////////////////////////////////////////////////////// + void initialize(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + priv::WindowImpl* m_impl; ///< Platform-specific implementation of the window + priv::GlContext* m_context; ///< Platform-specific implementation of the OpenGL context + Clock m_clock; ///< Clock for measuring the elapsed time between frames + Time m_frameTimeLimit; ///< Current framerate limit + Vector2u m_size; ///< Current size of the window +}; + +} // namespace sf + + +#endif // SFML_WINDOW_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Window +/// \ingroup window +/// +/// sf::Window is the main class of the Window module. It defines +/// an OS window that is able to receive an OpenGL rendering. +/// +/// A sf::Window can create its own new window, or be embedded into +/// an already existing control using the create(handle) function. +/// This can be useful for embedding an OpenGL rendering area into +/// a view which is part of a bigger GUI with existing windows, +/// controls, etc. It can also serve as embedding an OpenGL rendering +/// area into a window created by another (probably richer) GUI library +/// like Qt or wxWidgets. +/// +/// The sf::Window class provides a simple interface for manipulating +/// the window: move, resize, show/hide, control mouse cursor, etc. +/// It also provides event handling through its pollEvent() and waitEvent() +/// functions. +/// +/// Note that OpenGL experts can pass their own parameters (antialiasing +/// level, bits for the depth and stencil buffers, etc.) to the +/// OpenGL context attached to the window, with the sf::ContextSettings +/// structure which is passed as an optional argument when creating the +/// window. +/// +/// Usage example: +/// \code +/// // Declare and create a new window +/// sf::Window window(sf::VideoMode(800, 600), "SFML window"); +/// +/// // Limit the framerate to 60 frames per second (this step is optional) +/// window.setFramerateLimit(60); +/// +/// // The main loop - ends as soon as the window is closed +/// while (window.isOpen()) +/// { +/// // Event processing +/// sf::Event event; +/// while (window.pollEvent(event)) +/// { +/// // Request for closing the window +/// if (event.type == sf::Event::Closed) +/// window.close(); +/// } +/// +/// // Activate the window for OpenGL rendering +/// window.setActive(); +/// +/// // OpenGL drawing commands go here... +/// +/// // End the current frame and display its contents on screen +/// window.display(); +/// } +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/WindowHandle.hpp b/include/SFML/Window/WindowHandle.hpp new file mode 100644 index 0000000..c8b0149 --- /dev/null +++ b/include/SFML/Window/WindowHandle.hpp @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_WINDOWHANDLE_HPP +#define SFML_WINDOWHANDLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + +// Windows' HWND is a typedef on struct HWND__* +#if defined(SFML_SYSTEM_WINDOWS) + struct HWND__; +#endif + +namespace sf +{ +#if defined(SFML_SYSTEM_WINDOWS) + + // Window handle is HWND (HWND__*) on Windows + typedef HWND__* WindowHandle; + +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) + + // Window handle is Window (unsigned long) on Unix - X11 + typedef unsigned long WindowHandle; + +#elif defined(SFML_SYSTEM_MACOS) + + // Window handle is NSWindow or NSView (void*) on Mac OS X - Cocoa + typedef void* WindowHandle; + +#elif defined(SFML_SYSTEM_IOS) + + // Window handle is UIWindow (void*) on iOS - UIKit + typedef void* WindowHandle; + +#elif defined(SFML_SYSTEM_ANDROID) + + // Window handle is ANativeWindow* (void*) on Android + typedef void* WindowHandle; + +#elif defined(SFML_DOXYGEN) + + // Define typedef symbol so that Doxygen can attach some documentation to it + typedef "platform–specific" WindowHandle; + +#endif + +} // namespace sf + + +#endif // SFML_WINDOWHANDLE_HPP + +//////////////////////////////////////////////////////////// +/// \typedef sf::WindowHandle +/// \ingroup window +/// +/// Define a low-level window handle type, specific to +/// each platform. +/// +/// Platform | Type +/// ----------------|------------------------------------------------------------ +/// Windows | \p HWND +/// Linux/FreeBSD | \p %Window +/// Mac OS X | either \p NSWindow* or \p NSView*, disguised as \p void* +/// iOS | \p UIWindow* +/// Android | \p ANativeWindow* +/// +/// \par Mac OS X Specification +/// +/// On Mac OS X, a sf::Window can be created either from an +/// existing \p NSWindow* or an \p NSView*. When the window +/// is created from a window, SFML will use its content view +/// as the OpenGL area. sf::Window::getSystemHandle() will +/// return the handle that was used to create the window, +/// which is a \p NSWindow* by default. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/WindowStyle.hpp b/include/SFML/Window/WindowStyle.hpp new file mode 100644 index 0000000..3b182a9 --- /dev/null +++ b/include/SFML/Window/WindowStyle.hpp @@ -0,0 +1,53 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_WINDOWSTYLE_HPP +#define SFML_WINDOWSTYLE_HPP + + +namespace sf +{ +namespace Style +{ + //////////////////////////////////////////////////////////// + /// \ingroup window + /// \brief Enumeration of the window styles + /// + //////////////////////////////////////////////////////////// + enum + { + None = 0, ///< No border / title bar (this flag and all others are mutually exclusive) + Titlebar = 1 << 0, ///< Title bar + fixed border + Resize = 1 << 1, ///< Title bar + resizable border + maximize button + Close = 1 << 2, ///< Title bar + close button + Fullscreen = 1 << 3, ///< Fullscreen mode (this flag and all others are mutually exclusive) + + Default = Titlebar | Resize | Close ///< Default window style + }; +} + +} // namespace sf + + +#endif // SFML_WINDOWSTYLE_HPP diff --git a/lib/libGameMenu.a b/lib/libGameMenu.a index 4209e3f5bb0dca0e2536c6206dc1527205c52829..d4b51b6fdddedacb32b2982c99c9473b06be77fb 100644 GIT binary patch literal 389190 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�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

YoRG{Gx4dVR&S(PffV;4dA&ZTlu}<(bih|1L4nn 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 z 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 NURC53)-R5G{{y4bTh;&o From 595bdcce8c3052409d43c1fefdb273a5d6a77b00 Mon Sep 17 00:00:00 2001 From: ParadoxZero Date: Tue, 20 Dec 2016 06:12:15 +0530 Subject: [PATCH 03/10] Style is now working. Passing sf::Fonts by reference. added example. --- .../GameMenu_sample/GameMenu_sample.vcxproj | 132 ++++++++++++++++++ .../GameMenu_sample.vcxproj.filters | 25 ++++ Examples/GameMenu_sample/sansation.ttf | Bin 0 -> 28912 bytes .../GameMenu_sample/tests/sample_menu.cpp | 29 ++++ Examples/Most_simple_menu.cpp | 31 ---- GameMenu.sln | 16 ++- GameMenu.vcxproj | 7 + include/GameMenu/GameMenu.h | 65 +++++---- src/GameMenu/GameMenu.cpp | 24 ++-- tests/sample_menu.cpp | 29 ---- 10 files changed, 249 insertions(+), 109 deletions(-) create mode 100644 Examples/GameMenu_sample/GameMenu_sample.vcxproj create mode 100644 Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters create mode 100644 Examples/GameMenu_sample/sansation.ttf create mode 100644 Examples/GameMenu_sample/tests/sample_menu.cpp delete mode 100644 Examples/Most_simple_menu.cpp delete mode 100644 tests/sample_menu.cpp diff --git a/Examples/GameMenu_sample/GameMenu_sample.vcxproj b/Examples/GameMenu_sample/GameMenu_sample.vcxproj new file mode 100644 index 0000000..94c3f0c --- /dev/null +++ b/Examples/GameMenu_sample/GameMenu_sample.vcxproj @@ -0,0 +1,132 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {2371809A-CD4A-45DA-9069-51A5AF301BF5} + GameMenu_sample + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + C:\Users\sidhi\libraries\SFML-2.4.1\include;C:\Users\sidhi\Desktop\Projects\GameMenu_sample\include;%(AdditionalIncludeDirectories) + + + C:\Users\sidhi\Desktop\Projects\GameMenu_sample\lib;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) + GameMenu.lib;sfml-window-d.lib;sfml-graphics-d.lib;sfml-system-d.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + C:\Users\sidhi\Desktop\Projects\GameMenu\include;%(AdditionalIncludeDirectories) + + + C:\Users\sidhi\Desktop\Projects\GameMenu\lib\x64\Debug;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) + sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + C:\Users\sidhi\Desktop\Projects\GameMenu\include;%(AdditionalIncludeDirectories) + + + true + true + C:\Users\sidhi\Desktop\Projects\GameMenu\lib\x64\Debug;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) + sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) + + + + + + + + + + \ No newline at end of file diff --git a/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters b/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters new file mode 100644 index 0000000..a704cfc --- /dev/null +++ b/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Examples/GameMenu_sample/sansation.ttf b/Examples/GameMenu_sample/sansation.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d85fbc81d91e22c647a3338a37f24a9d684dcf8a GIT binary patch literal 28912 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 Y(-osHj2F<;P%p3rF{>lYhrW~jFV!_TuK)l5 literal 0 HcmV?d00001 diff --git a/Examples/GameMenu_sample/tests/sample_menu.cpp b/Examples/GameMenu_sample/tests/sample_menu.cpp new file mode 100644 index 0000000..bca4465 --- /dev/null +++ b/Examples/GameMenu_sample/tests/sample_menu.cpp @@ -0,0 +1,29 @@ +#include "GameMenu\GameMenu.h" +#include + +namespace test { + class testAction : public gmenu::Action { + public: + bool start() { + return true; + } + }; +} + +void main() { + sf::RenderWindow w( sf::VideoMode( 500, 500 ), "Test", sf::Style::Close); + std::vector itemList; + std::string text[3] = { "Hello", "World","!!!" }; + gmenu::MenuItem item; + sf::Font font; + font.loadFromFile( "sansation.ttf" ); + gmenu::Style style( font, font ); + for ( int i = 0; i < 3; ++i ) { + item.title = text[i]; + item.action = new test::testAction(); + itemList.push_back( item ); + } + gmenu::Menu menu( w, "Sample Menu", itemList, style ); + menu.createMenu(); +} + diff --git a/Examples/Most_simple_menu.cpp b/Examples/Most_simple_menu.cpp deleted file mode 100644 index 7164781..0000000 --- a/Examples/Most_simple_menu.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "GameMenu\GameMenu.h" -#include - -namespace test { - class testAction : public gmenu::Action { - public: - bool start() { - return true; - } - }; -} - -void main() { - sf::RenderWindow w( sf::VideoMode( 800, 800 ), "Test", sf::Style::Close ); - gmenu::MenuItem item[3]; - std::string text[3] = { "Hello", "World","!!!" }; - sf::Font font; - font.loadFromFile( "sansation.ttf" ); - for ( int i = 0; i < 3; ++i ) { - item[i].title = text[i]; - item[i].action = new test::testAction(); - } - gmenu::Style style; - style.TitleFont = font; - style.ItemFont = font; - style.ItemColor = sf::Color::Blue; - style.Selected = sf::Color::Yellow; - style.ItemFontSize = 30; - gmenu::Menu menu( &w, "Sample Menu", item, 3, style ); - menu.createMenu(); -} diff --git a/GameMenu.sln b/GameMenu.sln index cfbacf0..dd7e38a 100644 --- a/GameMenu.sln +++ b/GameMenu.sln @@ -5,14 +5,14 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameMenu", "GameMenu.vcxproj", "{02870BF4-F128-4D1D-AB7C-6720D328CBDC}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameMenu_sample", "Examples\GameMenu_sample\GameMenu_sample.vcxproj", "{2371809A-CD4A-45DA-9069-51A5AF301BF5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 - Test|x64 = Test|x64 - Test|x86 = Test|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Debug|x64.ActiveCfg = Debug|x64 @@ -23,10 +23,14 @@ Global {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x64.Build.0 = Release|x64 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.ActiveCfg = Release|Win32 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.Build.0 = Release|Win32 - {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x64.ActiveCfg = Test|x64 - {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x64.Build.0 = Test|x64 - {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x86.ActiveCfg = Test|Win32 - {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Test|x86.Build.0 = Test|Win32 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x64.ActiveCfg = Debug|x64 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x64.Build.0 = Debug|x64 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x86.ActiveCfg = Debug|Win32 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x86.Build.0 = Debug|Win32 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x64.ActiveCfg = Release|x64 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x64.Build.0 = Release|x64 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x86.ActiveCfg = Release|Win32 + {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GameMenu.vcxproj b/GameMenu.vcxproj index 9c4cbf3..4d10ad7 100644 --- a/GameMenu.vcxproj +++ b/GameMenu.vcxproj @@ -88,6 +88,13 @@ C:\Users\sidhi\libraries\SFML-2.4.1\include;C:\Users\sidhi\Desktop\Projects\GameMenu\include;$(IncludePath) + $(SolutionDir)lib\$(Platform)\$(Configuration)\ + + + $(SolutionDir)lib\$(Platform)\$(Configuration)\ + + + $(SolutionDir)lib\$(Platform)\$(Configuration)\ diff --git a/include/GameMenu/GameMenu.h b/include/GameMenu/GameMenu.h index 1d94725..19147c3 100644 --- a/include/GameMenu/GameMenu.h +++ b/include/GameMenu/GameMenu.h @@ -32,27 +32,39 @@ namespace gmenu { std::string title; }; + /* BitFlags for Different possible Layouts */ enum Layout { - TitleCentre, - TitleRight, - TitleLeft, - ItemCentre, - ItemRight, - ItemLeft, + TitleCentre = 1<<0, + TitleRight = 1<<1, + TitleLeft = 1<<2, + + ItemCentre = 1<<3, + ItemRight = 1<<4, + ItemLeft = 1<<5, + + TitleFar = 1<<6, + TitleNear = 1<<7, + TitleNormal = 1<<8, + + ItemSpaceCompact = 1<<9, + ItemSpaceNormal = 1<<10, + ItemSpaceFar = 1<<11, }; + /* Defines the style of the menu */ struct Style { - sf::Font TitleFont; - sf::Font ItemFont; + sf::Font &TitleFont; + sf::Font &ItemFont; sf::Color TitleColor; sf::Color ItemColor; sf::Color Selected; unsigned int TitleFontSize; unsigned int ItemFontSize; Layout layout; - Style() { + Style(sf::Font &mf, sf::Font &itmf): + TitleFont(mf),ItemFont(itmf){ TitleColor = sf::Color::Green; ItemColor = sf::Color::Red; Selected = sf::Color::Blue; @@ -63,22 +75,21 @@ namespace gmenu { - - + class Menu { /* Generic Menu - can be instantiated to generate a custom menu as needed over a sf::RenderWindow */ public: /* Only accesible constructor */ - Menu(sf::RenderWindow *window, std::string title, MenuItem* items, int8_t length, Style style) - : Menu(window, title) { - setMenuItems(items, length); - this->style = style; + Menu(sf::RenderWindow &wnd, std::string title, std::vector items, Style &st): + style(st) { + window = &wnd; + setTitle( title ); + setMenuItems( items ); + } - - /* This method is will start the menu and handover the screen control to it. The Event loop will be controlled by this function after the call, and only after Back/exit on the menu will the control be returned. @@ -88,7 +99,7 @@ namespace gmenu { void createMenu(); /* In case menu items needs to be changed */ - void setMenuItems(MenuItem *, int8_t); + void setMenuItems( std::vector ); /* In case the title needs to be changed */ void setTitle(std::string title); @@ -96,14 +107,6 @@ namespace gmenu { private: - Menu( sf::RenderWindow *wnd ) { - window = wnd; - } - - - Menu( sf::RenderWindow *window, std::string title ) : Menu( window ) { - setTitle( title); - } void writeText( std::string string, sf::Font font, unsigned int size, float x, float y, const sf::Color &color); @@ -118,8 +121,8 @@ namespace gmenu { *===================================================*/ struct { - MenuItem *entries; - int8_t size; + std::vector entries; + int size; } menu_items; struct coordinates { @@ -128,8 +131,8 @@ namespace gmenu { } float x; float y; - } *item_location, title_location; - + } title_location; + std::vector item_location; /*==================================================* * Data Members * @@ -137,7 +140,7 @@ namespace gmenu { int currently_selected_item = 0; - Style style; + Style &style; sf::RenderWindow *window; std::string menu_title; diff --git a/src/GameMenu/GameMenu.cpp b/src/GameMenu/GameMenu.cpp index 382475c..5549106 100644 --- a/src/GameMenu/GameMenu.cpp +++ b/src/GameMenu/GameMenu.cpp @@ -17,9 +17,9 @@ namespace gmenu { menu_title = title; } - void Menu::setMenuItems(MenuItem *items, int8_t length) { + void Menu::setMenuItems( std::vector items ) { menu_items.entries = items; - menu_items.size = length; + menu_items.size = items.size(); } @@ -32,17 +32,14 @@ namespace gmenu { bool cont = true; while (window->isOpen() && cont) { - window->clear(); - drawMenu(); + sf::Event event; while (window->pollEvent(event)) { if (event.type == sf::Event::Closed) window->close(); else if (event.type == sf::Event::KeyPressed) { if (event.key.code == sf::Keyboard::Up) { - currently_selected_item = (currently_selected_item - 1); - if (currently_selected_item < 0) - currently_selected_item = menu_items.size - 1; + currently_selected_item = (currently_selected_item + menu_items.size - 1) % (menu_items.size); } else if (event.key.code == sf::Keyboard::Down) { currently_selected_item = (currently_selected_item + 1) % (menu_items.size); @@ -52,7 +49,9 @@ namespace gmenu { } } } // while( pollEvent ) - + + window->clear(); + drawMenu(); window->display(); } // while window open } //create menu @@ -91,18 +90,19 @@ namespace gmenu { unsigned int block_height = (int) menu_screen_height / menu_items.size * MenuItemScaleFactor; float x = (float)window->getSize().x / 2; float y = (float)window->getSize().y - 0.75 * menu_screen_height + block_height * 1 / 8; - item_location = new coordinates[menu_items.size]; /* Calculating Menu item locations */ for (int8_t i = 0; i < menu_items.size; ++i) { - item_location[i].x = x; - item_location[i].y = y; + coordinates crd ; + crd.x = x; + crd.y = y; + item_location.push_back( crd ); y += block_height; } } //setMenu() void Menu::drawMenu() { - writeText(menu_title, style.TitleFont, style.TitleFontSize, title_location.x, title_location.y, style.TitleColor); + writeText(menu_title, style.ItemFont, style.TitleFontSize, title_location.x, title_location.y, style.TitleColor); sf::Color color = style.ItemColor; for (int i = 0; i < menu_items.size; ++i) { diff --git a/tests/sample_menu.cpp b/tests/sample_menu.cpp deleted file mode 100644 index ba1e82c..0000000 --- a/tests/sample_menu.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "GameMenu\GameMenu.h" -#include - -namespace test { - class testAction : public gmenu::Action { - public: - bool start() { - return false; - } - }; -} - -void main() { - sf::RenderWindow w( sf::VideoMode( 800, 400 ), "Test", sf::Style::Close); - gmenu::MenuItem item[2]; - std::string text[2] = { "Hello", "World" }; - sf::Font font; - font.loadFromFile( "sansation.ttf" ); - for ( int i = 0; i < 2; ++i ) { - item[i].title = text[i]; - item[i].action = new test::testAction(); - } - gmenu::Style style; - style.TitleFont = font; - style.ItemFont = font; - gmenu::Menu menu( &w, "Sample Menu", item, 2,style ); - menu.createMenu(); -} - From 285b7ea5495ca928d99748e79872821416f45ff4 Mon Sep 17 00:00:00 2001 From: ParadoxZero Date: Tue, 20 Dec 2016 08:00:37 +0530 Subject: [PATCH 04/10] Some weird bug. offset not working properly --- .../GameMenu_sample/tests/sample_menu.cpp | 1 + include/GameMenu/GameMenu.h | 55 +++++++++--------- lib/libGameMenu.a | Bin 389190 -> 568194 bytes src/GameMenu/GameMenu.cpp | 34 ++++++++--- 4 files changed, 55 insertions(+), 35 deletions(-) diff --git a/Examples/GameMenu_sample/tests/sample_menu.cpp b/Examples/GameMenu_sample/tests/sample_menu.cpp index bca4465..813bbd6 100644 --- a/Examples/GameMenu_sample/tests/sample_menu.cpp +++ b/Examples/GameMenu_sample/tests/sample_menu.cpp @@ -18,6 +18,7 @@ void main() { sf::Font font; font.loadFromFile( "sansation.ttf" ); gmenu::Style style( font, font ); + style.layout = gmenu::Layout::TitleCentre; for ( int i = 0; i < 3; ++i ) { item.title = text[i]; item.action = new test::testAction(); diff --git a/include/GameMenu/GameMenu.h b/include/GameMenu/GameMenu.h index 19147c3..bf28ebf 100644 --- a/include/GameMenu/GameMenu.h +++ b/include/GameMenu/GameMenu.h @@ -35,41 +35,41 @@ namespace gmenu { /* BitFlags for Different possible Layouts */ enum Layout { - TitleCentre = 1<<0, - TitleRight = 1<<1, - TitleLeft = 1<<2, - - ItemCentre = 1<<3, - ItemRight = 1<<4, - ItemLeft = 1<<5, - - TitleFar = 1<<6, - TitleNear = 1<<7, - TitleNormal = 1<<8, + TitleCentre = 1 << 0, + TitleRight = 1 << 1, + TitleLeft = 1 << 2, - ItemSpaceCompact = 1<<9, - ItemSpaceNormal = 1<<10, - ItemSpaceFar = 1<<11, + ItemCentre = 1 << 3, + ItemRight = 1 << 4, + ItemLeft = 1 << 5, + Default = TitleCentre | ItemCentre + }; /* Defines the style of the menu */ struct Style { sf::Font &TitleFont; sf::Font &ItemFont; - sf::Color TitleColor; - sf::Color ItemColor; - sf::Color Selected; - unsigned int TitleFontSize; - unsigned int ItemFontSize; - Layout layout; + + sf::Color TitleColor = sf::Color::Green;; + sf::Color ItemColor = sf::Color::Red ; + sf::Color Selected = sf::Color::Blue; + + unsigned int TitleFontSize = 50; + unsigned int ItemFontSize = 20; + + float MenuTitleScaleFactor = 0.125; + float MenuItemScaleFactor = 0.25; + + struct { + unsigned int top, left; + } Padding; + + int layout = Layout::Default; Style(sf::Font &mf, sf::Font &itmf): - TitleFont(mf),ItemFont(itmf){ - TitleColor = sf::Color::Green; - ItemColor = sf::Color::Red; - Selected = sf::Color::Blue; - ItemFontSize = 20; - TitleFontSize = 50; + TitleFont( mf ), ItemFont( itmf ), Padding {10,0} + { } }; @@ -146,8 +146,7 @@ namespace gmenu { std::string menu_title; // TODO: create an interface to set these - float MenuTitleScaleFactor = 0.125; - float MenuItemScaleFactor = 0.25; + }; // Menu diff --git a/lib/libGameMenu.a b/lib/libGameMenu.a index d4b51b6fdddedacb32b2982c99c9473b06be77fb..6c328206d07608af67e5b8b36f52c2fa9fb1dcd4 100644 GIT binary patch literal 568194 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 W7|O3D?@hjrd^-7h@{Qyh$p0U=b5gtj literal 389190 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 - +#include namespace gmenu { @@ -72,31 +72,50 @@ namespace gmenu { text.setCharacterSize(size); sf::FloatRect textRect = text.getLocalBounds(); text.setOrigin(textRect.width / 2.0f,0); + if ( x - textRect.width / 2.0f < 0 ) { + //std::cout << x << " " << textRect.width / 2.0f; + x = textRect.width / 2 + style.Padding.left; + } text.setPosition(sf::Vector2f(x,y)); window->draw(text); } //writeText(...) void Menu::setMenu() { + std::cout << "screen size:" << window->getSize().x << " " << window->getSize().y << std::endl; + /* Setting title of menu */ { /* Small scope just to be able to freely use the variable names */ - float x = (float) window->getSize().x / 2, y = 0; - title_location.x = x; + int offset_coefficient = 0.5; + if ( style.layout & Layout::TitleCentre == Layout::TitleCentre ) offset_coefficient = 0.5; + else if ( style.layout & Layout::TitleLeft == Layout::TitleLeft ) offset_coefficient = 0.25; + else if ( style.layout & Layout::TitleRight == Layout::TitleRight ) offset_coefficient = 0.75; + float x = (float) window->getSize().x * offset_coefficient, y = style.Padding.top; + title_location.x = (x + style.Padding.left); title_location.y = y; + std::cout << "title_location:" << title_location.x << " "<getSize().y * (1 - MenuTitleScaleFactor); - unsigned int block_height = (int) menu_screen_height / menu_items.size * MenuItemScaleFactor; - float x = (float)window->getSize().x / 2; - float y = (float)window->getSize().y - 0.75 * menu_screen_height + block_height * 1 / 8; + unsigned int menu_screen_height =(int) window->getSize().y * (1 - style.MenuTitleScaleFactor); + unsigned int block_height = (int) menu_screen_height / menu_items.size * style.MenuItemScaleFactor; + + float offset_coefficient = 0.5; + if ( style.layout & Layout::ItemCentre == Layout::ItemCentre ) offset_coefficient = 0.5; + else if ( style.layout & Layout::ItemLeft == Layout::ItemLeft ) offset_coefficient = 0.25; + else if ( style.layout & Layout::ItemRight == Layout::ItemRight) offset_coefficient = 0.75; + + float x = (float)window->getSize().x * offset_coefficient + style.Padding.left; + float y = ((float)window->getSize().y) - 0.75 * menu_screen_height + block_height * 1 / 8; /* Calculating Menu item locations */ for (int8_t i = 0; i < menu_items.size; ++i) { coordinates crd ; crd.x = x; crd.y = y; item_location.push_back( crd ); + std::cout << "menu location:" << x << " " << y < Date: Thu, 22 Dec 2016 05:25:46 +0530 Subject: [PATCH 05/10] Access voilation error. No idea why --- .../GameMenu_sample/GameMenu_sample.vcxproj | 16 ++---- .../GameMenu_sample.vcxproj.filters | 3 -- GameMenu.sln | 18 +++---- include/GameMenu/GameMenu.h | 32 +++++------- lib/libGameMenu.a | Bin 568194 -> 575482 bytes src/GameMenu/GameMenu.cpp | 46 +++++++++--------- 6 files changed, 47 insertions(+), 68 deletions(-) diff --git a/Examples/GameMenu_sample/GameMenu_sample.vcxproj b/Examples/GameMenu_sample/GameMenu_sample.vcxproj index 94c3f0c..3da71f3 100644 --- a/Examples/GameMenu_sample/GameMenu_sample.vcxproj +++ b/Examples/GameMenu_sample/GameMenu_sample.vcxproj @@ -19,7 +19,7 @@ - {2371809A-CD4A-45DA-9069-51A5AF301BF5} + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED} GameMenu_sample 8.1 @@ -74,12 +74,7 @@ Level3 Disabled true - C:\Users\sidhi\libraries\SFML-2.4.1\include;C:\Users\sidhi\Desktop\Projects\GameMenu_sample\include;%(AdditionalIncludeDirectories) - - C:\Users\sidhi\Desktop\Projects\GameMenu_sample\lib;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) - GameMenu.lib;sfml-window-d.lib;sfml-graphics-d.lib;sfml-system-d.lib;%(AdditionalDependencies) - @@ -89,8 +84,8 @@ C:\Users\sidhi\Desktop\Projects\GameMenu\include;%(AdditionalIncludeDirectories) - C:\Users\sidhi\Desktop\Projects\GameMenu\lib\x64\Debug;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) - sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) + C:\Users\sidhi\libraries\SFML-2.4.1\lib;C:\Users\sidhi\Desktop\Projects\GameMenu\x64\Debug;%(AdditionalLibraryDirectories) + sfml-window-d.lib;sfml-graphics-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) @@ -118,13 +113,12 @@ true true - C:\Users\sidhi\Desktop\Projects\GameMenu\lib\x64\Debug;C:\Users\sidhi\libraries\SFML-2.4.1\lib;%(AdditionalLibraryDirectories) - sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) + C:\Users\sidhi\libraries\SFML-2.4.1\lib;C:\Users\sidhi\Desktop\Projects\GameMenu\x64\Debug;%(AdditionalLibraryDirectories) + sfml-window-d.lib;sfml-graphics-d.lib;sfml-system-d.lib;GameMenu.lib;%(AdditionalDependencies) - diff --git a/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters b/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters index a704cfc..0e9352d 100644 --- a/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters +++ b/Examples/GameMenu_sample/GameMenu_sample.vcxproj.filters @@ -18,8 +18,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/GameMenu.sln b/GameMenu.sln index dd7e38a..dd0444d 100644 --- a/GameMenu.sln +++ b/GameMenu.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameMenu", "GameMenu.vcxproj", "{02870BF4-F128-4D1D-AB7C-6720D328CBDC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameMenu_sample", "Examples\GameMenu_sample\GameMenu_sample.vcxproj", "{2371809A-CD4A-45DA-9069-51A5AF301BF5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameMenu_sample", "Examples\GameMenu_sample\GameMenu_sample.vcxproj", "{A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,14 +23,14 @@ Global {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x64.Build.0 = Release|x64 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.ActiveCfg = Release|Win32 {02870BF4-F128-4D1D-AB7C-6720D328CBDC}.Release|x86.Build.0 = Release|Win32 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x64.ActiveCfg = Debug|x64 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x64.Build.0 = Debug|x64 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x86.ActiveCfg = Debug|Win32 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Debug|x86.Build.0 = Debug|Win32 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x64.ActiveCfg = Release|x64 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x64.Build.0 = Release|x64 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x86.ActiveCfg = Release|Win32 - {2371809A-CD4A-45DA-9069-51A5AF301BF5}.Release|x86.Build.0 = Release|Win32 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Debug|x64.ActiveCfg = Debug|x64 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Debug|x64.Build.0 = Debug|x64 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Debug|x86.ActiveCfg = Debug|Win32 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Debug|x86.Build.0 = Debug|Win32 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Release|x64.ActiveCfg = Release|x64 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Release|x64.Build.0 = Release|x64 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Release|x86.ActiveCfg = Release|Win32 + {A28CCAFC-BA0D-4833-8D9B-3D2F18B69FED}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/include/GameMenu/GameMenu.h b/include/GameMenu/GameMenu.h index bf28ebf..b36180a 100644 --- a/include/GameMenu/GameMenu.h +++ b/include/GameMenu/GameMenu.h @@ -81,13 +81,11 @@ namespace gmenu { public: - /* Only accesible constructor */ + /* Only available constructor */ Menu(sf::RenderWindow &wnd, std::string title, std::vector items, Style &st): - style(st) { - window = &wnd; - setTitle( title ); - setMenuItems( items ); - + style( st ), window (wnd) { + menuTitle = title; + menuItems = items; } /* This method is will start the menu and handover the screen control to it. @@ -120,17 +118,11 @@ namespace gmenu { * Internal structuers * *===================================================*/ - struct { - std::vector entries; - int size; - } menu_items; + std::vector menuItems; struct coordinates { - coordinates() { - x = y = 0.f; - } - float x; - float y; + float x = 0; + float y = 0; } title_location; std::vector item_location; @@ -142,13 +134,11 @@ namespace gmenu { Style &style; - sf::RenderWindow *window; - std::string menu_title; - - // TODO: create an interface to set these - + sf::RenderWindow &window; + std::string menuTitle; }; // Menu -} // namespace sui +} // namespace gmenu + #endif \ No newline at end of file diff --git a/lib/libGameMenu.a b/lib/libGameMenu.a index 6c328206d07608af67e5b8b36f52c2fa9fb1dcd4..918b7d0248fb39e00d46b4c9b4fa50a4127714ad 100644 GIT binary patch literal 575482 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�!2kHvM_fgAEY!1v?$9>@1ae2?e* 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