summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig18
-rw-r--r--.gitattributes13
-rw-r--r--.github/ISSUE_TEMPLATE.md54
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md51
-rw-r--r--CMakeLists.txt512
-rw-r--r--CONTRIBUTING.md7
-rw-r--r--changelog.md702
-rw-r--r--cmake/Config.cmake118
-rw-r--r--cmake/Macros.cmake346
-rw-r--r--cmake/Modules/FindEGL.cmake14
-rw-r--r--cmake/Modules/FindFLAC.cmake18
-rw-r--r--cmake/Modules/FindFreetype.cmake158
-rw-r--r--cmake/Modules/FindGLES.cmake14
-rw-r--r--cmake/Modules/FindUDev.cmake53
-rw-r--r--cmake/Modules/FindVorbis.cmake29
-rw-r--r--cmake/SFMLConfig.cmake.in148
-rw-r--r--cmake/SFMLConfigDependencies.cmake.in86
-rw-r--r--cmake/toolchains/android.toolchain.cmake1666
-rw-r--r--cmake/toolchains/iOS.toolchain.cmake188
-rw-r--r--debian/changelog (renamed from changelog)0
-rw-r--r--debian/control (renamed from control)0
-rw-r--r--debian/copyright (renamed from copyright)0
-rw-r--r--debian/gbp.conf (renamed from gbp.conf)0
-rw-r--r--debian/libsfml-audio2.5.install (renamed from libsfml-audio2.5.install)0
-rw-r--r--debian/libsfml-dev.install (renamed from libsfml-dev.install)0
-rw-r--r--debian/libsfml-doc.README.Debian (renamed from libsfml-doc.README.Debian)0
-rw-r--r--debian/libsfml-doc.doc-base (renamed from libsfml-doc.doc-base)0
-rw-r--r--debian/libsfml-doc.docs (renamed from libsfml-doc.docs)0
-rw-r--r--debian/libsfml-doc.examples (renamed from libsfml-doc.examples)0
-rw-r--r--debian/libsfml-graphics2.5.install (renamed from libsfml-graphics2.5.install)0
-rw-r--r--debian/libsfml-network2.5.install (renamed from libsfml-network2.5.install)0
-rw-r--r--debian/libsfml-system2.5.install (renamed from libsfml-system2.5.install)0
-rw-r--r--debian/libsfml-system2.5.lintian-overrides (renamed from libsfml-system2.5.lintian-overrides)0
-rw-r--r--debian/libsfml-window2.5.install (renamed from libsfml-window2.5.install)0
-rw-r--r--debian/missing-sources/sfml-final-clean.svg (renamed from missing-sources/sfml-final-clean.svg)0
-rw-r--r--debian/patches/01_remove-googleapi-css.patch (renamed from patches/01_remove-googleapi-css.patch)0
-rw-r--r--debian/patches/02_build-doc-once.patch (renamed from patches/02_build-doc-once.patch)0
-rw-r--r--debian/patches/06_pkgconfig-libs-private.patch (renamed from patches/06_pkgconfig-libs-private.patch)0
-rw-r--r--debian/patches/series (renamed from patches/series)0
-rwxr-xr-xdebian/rules (renamed from rules)0
-rw-r--r--debian/source/format (renamed from source/format)0
-rw-r--r--debian/tests/CMakeLists.txt (renamed from tests/CMakeLists.txt)0
-rw-r--r--debian/tests/build (renamed from tests/build)0
-rw-r--r--debian/tests/cmake (renamed from tests/cmake)0
-rw-r--r--debian/tests/control (renamed from tests/control)0
-rw-r--r--debian/tests/sfml_test.cpp (renamed from tests/sfml_test.cpp)0
-rw-r--r--debian/watch (renamed from watch)0
-rw-r--r--doc/CMakeLists.txt62
-rw-r--r--doc/doxyfile.in2470
-rw-r--r--doc/doxygen.css1450
-rw-r--r--doc/footer.html10
-rw-r--r--doc/header.html.in18
-rw-r--r--doc/mainpage.hpp71
-rw-r--r--examples/CMakeLists.txt38
-rw-r--r--examples/X11/CMakeLists.txt10
-rw-r--r--examples/X11/X11.cpp217
-rw-r--r--examples/android/.gitignore8
-rw-r--r--examples/android/app/app.iml123
-rw-r--r--examples/android/app/build.gradle39
-rw-r--r--examples/android/app/proguard-rules.pro21
-rw-r--r--examples/android/app/src/main/AndroidManifest.xml34
-rw-r--r--examples/android/app/src/main/assets/image.pngbin0 -> 8849 bytes
-rw-r--r--examples/android/app/src/main/assets/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/android/app/src/main/jni/Android.mk20
-rw-r--r--examples/android/app/src/main/jni/Application.mk8
-rw-r--r--examples/android/app/src/main/jni/main.cpp176
-rw-r--r--examples/android/app/src/main/res/drawable-hdpi/sfml_logo.pngbin0 -> 4339 bytes
-rw-r--r--examples/android/app/src/main/res/drawable-ldpi/sfml_logo.pngbin0 -> 2246 bytes
-rw-r--r--examples/android/app/src/main/res/drawable-mdpi/sfml_logo.pngbin0 -> 2949 bytes
-rw-r--r--examples/android/app/src/main/res/drawable-xhdpi/sfml_logo.pngbin0 -> 5717 bytes
-rw-r--r--examples/android/app/src/main/res/drawable-xxhdpi/sfml_logo.pngbin0 -> 8482 bytes
-rw-r--r--examples/android/app/src/main/res/values/strings.xml4
-rw-r--r--examples/android/build.gradle23
-rw-r--r--examples/android/gradle.properties17
-rw-r--r--examples/android/settings.gradle1
-rw-r--r--examples/cocoa/CMakeLists.txt61
-rw-r--r--examples/cocoa/CocoaAppDelegate.h71
-rw-r--r--examples/cocoa/CocoaAppDelegate.mm236
-rw-r--r--examples/cocoa/MainMenu.xib4180
-rw-r--r--examples/cocoa/NSString+stdstring.h39
-rw-r--r--examples/cocoa/NSString+stdstring.mm73
-rw-r--r--examples/cocoa/main.m31
-rw-r--r--examples/cocoa/readme.txt28
-rw-r--r--examples/cocoa/resources/Cocoa-Info.plist36
-rw-r--r--examples/cocoa/resources/Credits.rtf7
-rw-r--r--examples/cocoa/resources/blue.pngbin0 -> 114 bytes
-rw-r--r--examples/cocoa/resources/green.pngbin0 -> 112 bytes
-rw-r--r--examples/cocoa/resources/icon.icnsbin0 -> 38947 bytes
-rw-r--r--examples/cocoa/resources/logo.pngbin0 -> 30801 bytes
-rw-r--r--examples/cocoa/resources/red.pngbin0 -> 113 bytes
-rw-r--r--examples/cocoa/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/ftp/CMakeLists.txt10
-rw-r--r--examples/ftp/Ftp.cpp206
-rw-r--r--examples/iOS/CMakeLists.txt25
-rw-r--r--examples/iOS/main.cpp65
-rw-r--r--examples/iOS/resources/image.pngbin0 -> 8849 bytes
-rw-r--r--examples/iOS/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/island/CMakeLists.txt11
-rw-r--r--examples/island/Island.cpp590
-rw-r--r--examples/island/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/island/resources/terrain.frag11
-rw-r--r--examples/island/resources/terrain.vert8
-rw-r--r--examples/island/stb_perlin.h316
-rw-r--r--examples/joystick/CMakeLists.txt11
-rw-r--r--examples/joystick/Joystick.cpp238
-rw-r--r--examples/joystick/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/opengl/CMakeLists.txt11
-rw-r--r--examples/opengl/OpenGL.cpp258
-rw-r--r--examples/opengl/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/pong/CMakeLists.txt11
-rw-r--r--examples/pong/Pong.cpp242
-rw-r--r--examples/pong/resources/ball.wavbin0 -> 15442 bytes
-rw-r--r--examples/pong/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/shader/CMakeLists.txt13
-rw-r--r--examples/shader/Effect.hpp88
-rw-r--r--examples/shader/Shader.cpp460
-rw-r--r--examples/shader/resources/billboard.frag11
-rw-r--r--examples/shader/resources/billboard.geom56
-rw-r--r--examples/shader/resources/billboard.vert5
-rw-r--r--examples/shader/resources/blink.frag9
-rw-r--r--examples/shader/resources/blur.frag20
-rw-r--r--examples/shader/resources/devices.pngbin0 -> 51410 bytes
-rw-r--r--examples/shader/resources/edge.frag32
-rw-r--r--examples/shader/resources/logo.pngbin0 -> 8849 bytes
-rw-r--r--examples/shader/resources/pixelate.frag9
-rw-r--r--examples/shader/resources/sansation.ttfbin0 -> 28912 bytes
-rw-r--r--examples/shader/resources/sfml.pngbin0 -> 25973 bytes
-rw-r--r--examples/shader/resources/storm.vert19
-rw-r--r--examples/shader/resources/text-background.pngbin0 -> 745 bytes
-rw-r--r--examples/shader/resources/wave.vert15
-rw-r--r--examples/sockets/CMakeLists.txt12
-rw-r--r--examples/sockets/Sockets.cpp59
-rw-r--r--examples/sockets/TCP.cpp81
-rw-r--r--examples/sockets/UDP.cpp72
-rw-r--r--examples/sound/CMakeLists.txt11
-rw-r--r--examples/sound/Sound.cpp101
-rw-r--r--examples/sound/resources/ding.flacbin0 -> 61764 bytes
-rw-r--r--examples/sound_capture/CMakeLists.txt10
-rw-r--r--examples/sound_capture/SoundCapture.cpp94
-rw-r--r--examples/voip/CMakeLists.txt12
-rw-r--r--examples/voip/Client.cpp141
-rw-r--r--examples/voip/Server.cpp200
-rw-r--r--examples/voip/VoIP.cpp50
-rw-r--r--examples/win32/CMakeLists.txt11
-rw-r--r--examples/win32/Win32.cpp132
-rw-r--r--examples/window/CMakeLists.txt10
-rw-r--r--examples/window/Window.cpp146
-rw-r--r--extlibs/Android.mk13
-rw-r--r--extlibs/headers/stb_image/stb_image.h7187
-rw-r--r--extlibs/headers/stb_image/stb_image_write.h1458
-rw-r--r--include/SFML/Audio.hpp56
-rw-r--r--include/SFML/Audio/AlResource.hpp70
-rw-r--r--include/SFML/Audio/Export.hpp48
-rw-r--r--include/SFML/Audio/InputSoundFile.hpp263
-rw-r--r--include/SFML/Audio/Listener.hpp234
-rw-r--r--include/SFML/Audio/Music.hpp337
-rw-r--r--include/SFML/Audio/OutputSoundFile.hpp133
-rw-r--r--include/SFML/Audio/Sound.hpp264
-rw-r--r--include/SFML/Audio/SoundBuffer.hpp352
-rw-r--r--include/SFML/Audio/SoundBufferRecorder.hpp144
-rw-r--r--include/SFML/Audio/SoundFileFactory.hpp197
-rw-r--r--include/SFML/Audio/SoundFileFactory.inl100
-rw-r--r--include/SFML/Audio/SoundFileReader.hpp165
-rw-r--r--include/SFML/Audio/SoundFileWriter.hpp125
-rw-r--r--include/SFML/Audio/SoundRecorder.hpp408
-rw-r--r--include/SFML/Audio/SoundSource.hpp332
-rw-r--r--include/SFML/Audio/SoundStream.hpp405
-rw-r--r--include/SFML/Config.hpp236
-rw-r--r--include/SFML/GpuPreference.hpp74
-rw-r--r--include/SFML/Graphics.hpp68
-rw-r--r--include/SFML/Graphics/BlendMode.hpp215
-rw-r--r--include/SFML/Graphics/CircleShape.hpp154
-rw-r--r--include/SFML/Graphics/Color.hpp275
-rw-r--r--include/SFML/Graphics/ConvexShape.hpp153
-rw-r--r--include/SFML/Graphics/Drawable.hpp126
-rw-r--r--include/SFML/Graphics/Export.hpp48
-rw-r--r--include/SFML/Graphics/Font.hpp439
-rw-r--r--include/SFML/Graphics/Glsl.hpp227
-rw-r--r--include/SFML/Graphics/Glsl.inl155
-rw-r--r--include/SFML/Graphics/Glyph.hpp79
-rw-r--r--include/SFML/Graphics/Image.hpp324
-rw-r--r--include/SFML/Graphics/PrimitiveType.hpp58
-rw-r--r--include/SFML/Graphics/Rect.hpp254
-rw-r--r--include/SFML/Graphics/Rect.inl159
-rw-r--r--include/SFML/Graphics/RectangleShape.hpp132
-rw-r--r--include/SFML/Graphics/RenderStates.hpp174
-rw-r--r--include/SFML/Graphics/RenderTarget.hpp510
-rw-r--r--include/SFML/Graphics/RenderTexture.hpp314
-rw-r--r--include/SFML/Graphics/RenderWindow.hpp284
-rw-r--r--include/SFML/Graphics/Shader.hpp875
-rw-r--r--include/SFML/Graphics/Shape.hpp355
-rw-r--r--include/SFML/Graphics/Sprite.hpp279
-rw-r--r--include/SFML/Graphics/Text.hpp513
-rw-r--r--include/SFML/Graphics/Texture.hpp733
-rw-r--r--include/SFML/Graphics/Transform.hpp479
-rw-r--r--include/SFML/Graphics/Transformable.hpp429
-rw-r--r--include/SFML/Graphics/Vertex.hpp148
-rw-r--r--include/SFML/Graphics/VertexArray.hpp223
-rw-r--r--include/SFML/Graphics/VertexBuffer.hpp408
-rw-r--r--include/SFML/Graphics/View.hpp343
-rw-r--r--include/SFML/Main.hpp43
-rw-r--r--include/SFML/Network.hpp53
-rw-r--r--include/SFML/Network/Export.hpp48
-rw-r--r--include/SFML/Network/Ftp.hpp616
-rw-r--r--include/SFML/Network/Http.hpp482
-rw-r--r--include/SFML/Network/IpAddress.hpp328
-rw-r--r--include/SFML/Network/Packet.hpp532
-rw-r--r--include/SFML/Network/Socket.hpp219
-rw-r--r--include/SFML/Network/SocketHandle.hpp57
-rw-r--r--include/SFML/Network/SocketSelector.hpp263
-rw-r--r--include/SFML/Network/TcpListener.hpp166
-rw-r--r--include/SFML/Network/TcpSocket.hpp316
-rw-r--r--include/SFML/Network/UdpSocket.hpp291
-rw-r--r--include/SFML/OpenGL.hpp78
-rw-r--r--include/SFML/System.hpp60
-rw-r--r--include/SFML/System/Clock.hpp117
-rw-r--r--include/SFML/System/Err.hpp80
-rw-r--r--include/SFML/System/Export.hpp48
-rw-r--r--include/SFML/System/FileInputStream.hpp169
-rw-r--r--include/SFML/System/InputStream.hpp152
-rw-r--r--include/SFML/System/Lock.hpp139
-rw-r--r--include/SFML/System/MemoryInputStream.hpp148
-rw-r--r--include/SFML/System/Mutex.hpp148
-rw-r--r--include/SFML/System/NativeActivity.hpp62
-rw-r--r--include/SFML/System/NonCopyable.hpp129
-rw-r--r--include/SFML/System/Sleep.hpp52
-rw-r--r--include/SFML/System/String.hpp669
-rw-r--r--include/SFML/System/String.inl53
-rw-r--r--include/SFML/System/Thread.hpp282
-rw-r--r--include/SFML/System/Thread.inl90
-rw-r--r--include/SFML/System/ThreadLocal.hpp103
-rw-r--r--include/SFML/System/ThreadLocalPtr.hpp158
-rw-r--r--include/SFML/System/ThreadLocalPtr.inl77
-rw-r--r--include/SFML/System/Time.hpp488
-rw-r--r--include/SFML/System/Utf.hpp763
-rw-r--r--include/SFML/System/Utf.inl752
-rw-r--r--include/SFML/System/Vector2.hpp301
-rw-r--r--include/SFML/System/Vector2.inl161
-rw-r--r--include/SFML/System/Vector3.hpp302
-rw-r--r--include/SFML/System/Vector3.inl168
-rw-r--r--include/SFML/Window.hpp58
-rw-r--r--include/SFML/Window/Clipboard.hpp119
-rw-r--r--include/SFML/Window/Context.hpp195
-rw-r--r--include/SFML/Window/ContextSettings.hpp149
-rw-r--r--include/SFML/Window/Cursor.hpp222
-rw-r--r--include/SFML/Window/Event.hpp284
-rw-r--r--include/SFML/Window/Export.hpp48
-rw-r--r--include/SFML/Window/GlResource.hpp109
-rw-r--r--include/SFML/Window/Joystick.hpp227
-rw-r--r--include/SFML/Window/Keyboard.hpp232
-rw-r--r--include/SFML/Window/Mouse.hpp177
-rw-r--r--include/SFML/Window/Sensor.hpp150
-rw-r--r--include/SFML/Window/Touch.hpp137
-rw-r--r--include/SFML/Window/VideoMode.hpp228
-rw-r--r--include/SFML/Window/Window.hpp622
-rw-r--r--include/SFML/Window/WindowHandle.hpp101
-rw-r--r--include/SFML/Window/WindowStyle.hpp53
-rw-r--r--license.md20
-rw-r--r--readme.md39
-rw-r--r--src/SFML/Android.mk183
-rw-r--r--src/SFML/Audio/ALCheck.cpp99
-rw-r--r--src/SFML/Audio/ALCheck.hpp72
-rw-r--r--src/SFML/Audio/AlResource.cpp78
-rw-r--r--src/SFML/Audio/AudioDevice.cpp228
-rw-r--r--src/SFML/Audio/AudioDevice.hpp192
-rw-r--r--src/SFML/Audio/CMakeLists.txt90
-rw-r--r--src/SFML/Audio/InputSoundFile.cpp278
-rw-r--r--src/SFML/Audio/Listener.cpp110
-rw-r--r--src/SFML/Audio/Music.cpp271
-rw-r--r--src/SFML/Audio/OutputSoundFile.cpp88
-rw-r--r--src/SFML/Audio/Sound.cpp198
-rw-r--r--src/SFML/Audio/SoundBuffer.cpp291
-rw-r--r--src/SFML/Audio/SoundBufferRecorder.cpp76
-rw-r--r--src/SFML/Audio/SoundFileFactory.cpp154
-rw-r--r--src/SFML/Audio/SoundFileReaderFlac.cpp340
-rw-r--r--src/SFML/Audio/SoundFileReaderFlac.hpp144
-rw-r--r--src/SFML/Audio/SoundFileReaderOgg.cpp179
-rw-r--r--src/SFML/Audio/SoundFileReaderOgg.hpp128
-rw-r--r--src/SFML/Audio/SoundFileReaderWav.cpp357
-rw-r--r--src/SFML/Audio/SoundFileReaderWav.hpp126
-rw-r--r--src/SFML/Audio/SoundFileWriterFlac.cpp133
-rw-r--r--src/SFML/Audio/SoundFileWriterFlac.hpp114
-rw-r--r--src/SFML/Audio/SoundFileWriterOgg.cpp216
-rw-r--r--src/SFML/Audio/SoundFileWriterOgg.hpp122
-rw-r--r--src/SFML/Audio/SoundFileWriterWav.cpp201
-rw-r--r--src/SFML/Audio/SoundFileWriterWav.hpp123
-rw-r--r--src/SFML/Audio/SoundRecorder.cpp330
-rw-r--r--src/SFML/Audio/SoundSource.cpp209
-rw-r--r--src/SFML/Audio/SoundStream.cpp495
-rw-r--r--src/SFML/CMakeLists.txt76
-rw-r--r--src/SFML/Graphics/BlendMode.cpp103
-rw-r--r--src/SFML/Graphics/CMakeLists.txt147
-rw-r--r--src/SFML/Graphics/CircleShape.cpp84
-rw-r--r--src/SFML/Graphics/Color.cpp155
-rw-r--r--src/SFML/Graphics/ConvexShape.cpp69
-rw-r--r--src/SFML/Graphics/Font.cpp817
-rw-r--r--src/SFML/Graphics/GLCheck.cpp114
-rw-r--r--src/SFML/Graphics/GLCheck.hpp70
-rw-r--r--src/SFML/Graphics/GLExtensions.cpp93
-rw-r--r--src/SFML/Graphics/GLExtensions.hpp333
-rw-r--r--src/SFML/Graphics/GLExtensions.txt23
-rw-r--r--src/SFML/Graphics/GLLoader.cpp1019
-rw-r--r--src/SFML/Graphics/GLLoader.hpp1706
-rw-r--r--src/SFML/Graphics/Glsl.cpp86
-rw-r--r--src/SFML/Graphics/Image.cpp340
-rw-r--r--src/SFML/Graphics/ImageLoader.cpp277
-rw-r--r--src/SFML/Graphics/ImageLoader.hpp128
-rw-r--r--src/SFML/Graphics/RectangleShape.cpp76
-rw-r--r--src/SFML/Graphics/RenderStates.cpp102
-rw-r--r--src/SFML/Graphics/RenderTarget.cpp769
-rw-r--r--src/SFML/Graphics/RenderTexture.cpp186
-rw-r--r--src/SFML/Graphics/RenderTextureImpl.cpp43
-rw-r--r--src/SFML/Graphics/RenderTextureImpl.hpp92
-rw-r--r--src/SFML/Graphics/RenderTextureImplDefault.cpp101
-rw-r--r--src/SFML/Graphics/RenderTextureImplDefault.hpp115
-rw-r--r--src/SFML/Graphics/RenderTextureImplFBO.cpp605
-rw-r--r--src/SFML/Graphics/RenderTextureImplFBO.hpp145
-rw-r--r--src/SFML/Graphics/RenderWindow.cpp123
-rw-r--r--src/SFML/Graphics/Shader.cpp1334
-rw-r--r--src/SFML/Graphics/Shape.cpp313
-rw-r--r--src/SFML/Graphics/Sprite.cpp174
-rw-r--r--src/SFML/Graphics/Text.cpp567
-rw-r--r--src/SFML/Graphics/Texture.cpp870
-rw-r--r--src/SFML/Graphics/TextureSaver.cpp50
-rw-r--r--src/SFML/Graphics/TextureSaver.hpp75
-rw-r--r--src/SFML/Graphics/Transform.cpp291
-rw-r--r--src/SFML/Graphics/Transformable.cpp219
-rw-r--r--src/SFML/Graphics/Vertex.cpp77
-rw-r--r--src/SFML/Graphics/VertexArray.cpp150
-rw-r--r--src/SFML/Graphics/VertexBuffer.cpp363
-rw-r--r--src/SFML/Graphics/View.cpp240
-rw-r--r--src/SFML/Main/CMakeLists.txt31
-rw-r--r--src/SFML/Main/MainAndroid.cpp567
-rw-r--r--src/SFML/Main/MainWin32.cpp53
-rw-r--r--src/SFML/Main/MainiOS.mm63
-rw-r--r--src/SFML/Main/SFMLActivity.cpp207
-rw-r--r--src/SFML/Network/CMakeLists.txt55
-rw-r--r--src/SFML/Network/Ftp.cpp653
-rw-r--r--src/SFML/Network/Http.cpp415
-rw-r--r--src/SFML/Network/IpAddress.cpp271
-rw-r--r--src/SFML/Network/Packet.cpp596
-rw-r--r--src/SFML/Network/Socket.cpp151
-rw-r--r--src/SFML/Network/SocketImpl.hpp39
-rw-r--r--src/SFML/Network/SocketSelector.cpp205
-rw-r--r--src/SFML/Network/TcpListener.cpp131
-rw-r--r--src/SFML/Network/TcpSocket.cpp416
-rw-r--r--src/SFML/Network/UdpSocket.cpp200
-rw-r--r--src/SFML/Network/Unix/SocketImpl.cpp112
-rw-r--r--src/SFML/Network/Unix/SocketImpl.hpp109
-rw-r--r--src/SFML/Network/Win32/SocketImpl.cpp112
-rw-r--r--src/SFML/Network/Win32/SocketImpl.hpp112
-rw-r--r--src/SFML/System/Android/Activity.cpp69
-rw-r--r--src/SFML/System/Android/Activity.hpp101
-rw-r--r--src/SFML/System/Android/NativeActivity.cpp39
-rw-r--r--src/SFML/System/Android/ResourceStream.cpp116
-rw-r--r--src/SFML/System/Android/ResourceStream.hpp113
-rw-r--r--src/SFML/System/CMakeLists.txt102
-rw-r--r--src/SFML/System/Clock.cpp63
-rw-r--r--src/SFML/System/Err.cpp110
-rw-r--r--src/SFML/System/FileInputStream.cpp146
-rw-r--r--src/SFML/System/Lock.cpp48
-rw-r--r--src/SFML/System/MemoryInputStream.cpp101
-rw-r--r--src/SFML/System/Mutex.cpp66
-rw-r--r--src/SFML/System/Sleep.cpp46
-rw-r--r--src/SFML/System/String.cpp400
-rw-r--r--src/SFML/System/Thread.cpp86
-rw-r--r--src/SFML/System/ThreadLocal.cpp67
-rw-r--r--src/SFML/System/Time.cpp260
-rw-r--r--src/SFML/System/Unix/ClockImpl.cpp64
-rw-r--r--src/SFML/System/Unix/ClockImpl.hpp61
-rw-r--r--src/SFML/System/Unix/MutexImpl.cpp69
-rw-r--r--src/SFML/System/Unix/MutexImpl.hpp83
-rw-r--r--src/SFML/System/Unix/SleepImpl.cpp59
-rw-r--r--src/SFML/System/Unix/SleepImpl.hpp52
-rw-r--r--src/SFML/System/Unix/ThreadImpl.cpp94
-rw-r--r--src/SFML/System/Unix/ThreadImpl.hpp93
-rw-r--r--src/SFML/System/Unix/ThreadLocalImpl.cpp65
-rw-r--r--src/SFML/System/Unix/ThreadLocalImpl.hpp87
-rw-r--r--src/SFML/System/Win32/ClockImpl.cpp88
-rw-r--r--src/SFML/System/Win32/ClockImpl.hpp61
-rw-r--r--src/SFML/System/Win32/MutexImpl.cpp64
-rw-r--r--src/SFML/System/Win32/MutexImpl.hpp83
-rw-r--r--src/SFML/System/Win32/SleepImpl.cpp55
-rw-r--r--src/SFML/System/Win32/SleepImpl.hpp52
-rw-r--r--src/SFML/System/Win32/ThreadImpl.cpp93
-rw-r--r--src/SFML/System/Win32/ThreadImpl.hpp109
-rw-r--r--src/SFML/System/Win32/ThreadLocalImpl.cpp64
-rw-r--r--src/SFML/System/Win32/ThreadLocalImpl.hpp87
-rw-r--r--src/SFML/Window/Android/ClipboardImpl.cpp52
-rw-r--r--src/SFML/Window/Android/ClipboardImpl.hpp76
-rw-r--r--src/SFML/Window/Android/CursorImpl.cpp68
-rw-r--r--src/SFML/Window/Android/CursorImpl.hpp88
-rw-r--r--src/SFML/Window/Android/InputImpl.cpp213
-rw-r--r--src/SFML/Window/Android/InputImpl.hpp168
-rw-r--r--src/SFML/Window/Android/JoystickImpl.cpp97
-rw-r--r--src/SFML/Window/Android/JoystickImpl.hpp117
-rw-r--r--src/SFML/Window/Android/SensorImpl.cpp214
-rw-r--r--src/SFML/Window/Android/SensorImpl.hpp137
-rw-r--r--src/SFML/Window/Android/VideoModeImpl.cpp63
-rw-r--r--src/SFML/Window/Android/WindowImplAndroid.cpp727
-rw-r--r--src/SFML/Window/Android/WindowImplAndroid.hpp249
-rw-r--r--src/SFML/Window/CMakeLists.txt288
-rw-r--r--src/SFML/Window/Clipboard.cpp48
-rw-r--r--src/SFML/Window/ClipboardImpl.hpp45
-rw-r--r--src/SFML/Window/Context.cpp111
-rw-r--r--src/SFML/Window/Cursor.cpp73
-rw-r--r--src/SFML/Window/CursorImpl.hpp56
-rw-r--r--src/SFML/Window/EGLCheck.cpp161
-rw-r--r--src/SFML/Window/EGLCheck.hpp68
-rw-r--r--src/SFML/Window/EglContext.cpp341
-rw-r--r--src/SFML/Window/EglContext.hpp190
-rw-r--r--src/SFML/Window/FreeBSD/JoystickImpl.cpp346
-rw-r--r--src/SFML/Window/FreeBSD/JoystickImpl.hpp129
-rw-r--r--src/SFML/Window/GlContext.cpp824
-rw-r--r--src/SFML/Window/GlContext.hpp305
-rw-r--r--src/SFML/Window/GlResource.cpp68
-rw-r--r--src/SFML/Window/InputImpl.hpp46
-rw-r--r--src/SFML/Window/Joystick.cpp92
-rw-r--r--src/SFML/Window/JoystickImpl.hpp112
-rw-r--r--src/SFML/Window/JoystickManager.cpp123
-rw-r--r--src/SFML/Window/JoystickManager.hpp129
-rw-r--r--src/SFML/Window/Keyboard.cpp47
-rw-r--r--src/SFML/Window/Mouse.cpp69
-rw-r--r--src/SFML/Window/OSX/AutoreleasePoolWrapper.h37
-rw-r--r--src/SFML/Window/OSX/AutoreleasePoolWrapper.mm105
-rw-r--r--src/SFML/Window/OSX/ClipboardImpl.hpp78
-rw-r--r--src/SFML/Window/OSX/ClipboardImpl.mm68
-rw-r--r--src/SFML/Window/OSX/CursorImpl.hpp109
-rw-r--r--src/SFML/Window/OSX/CursorImpl.mm129
-rw-r--r--src/SFML/Window/OSX/HIDInputManager.hpp236
-rw-r--r--src/SFML/Window/OSX/HIDInputManager.mm870
-rw-r--r--src/SFML/Window/OSX/HIDJoystickManager.cpp152
-rw-r--r--src/SFML/Window/OSX/HIDJoystickManager.hpp129
-rw-r--r--src/SFML/Window/OSX/InputImpl.hpp169
-rw-r--r--src/SFML/Window/OSX/InputImpl.mm237
-rw-r--r--src/SFML/Window/OSX/JoystickImpl.cpp524
-rw-r--r--src/SFML/Window/OSX/JoystickImpl.hpp139
-rw-r--r--src/SFML/Window/OSX/NSImage+raw.h52
-rw-r--r--src/SFML/Window/OSX/NSImage+raw.mm68
-rw-r--r--src/SFML/Window/OSX/SFApplication.h63
-rw-r--r--src/SFML/Window/OSX/SFApplication.m266
-rw-r--r--src/SFML/Window/OSX/SFApplicationDelegate.h53
-rw-r--r--src/SFML/Window/OSX/SFApplicationDelegate.m54
-rw-r--r--src/SFML/Window/OSX/SFContext.hpp173
-rw-r--r--src/SFML/Window/OSX/SFContext.mm310
-rw-r--r--src/SFML/Window/OSX/SFKeyboardModifiersHelper.h70
-rw-r--r--src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm240
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView+keyboard.mm220
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h68
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView+mouse.mm421
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h109
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView.h200
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView.mm352
-rw-r--r--src/SFML/Window/OSX/SFSilentResponder.h42
-rw-r--r--src/SFML/Window/OSX/SFSilentResponder.m40
-rw-r--r--src/SFML/Window/OSX/SFViewController.h58
-rw-r--r--src/SFML/Window/OSX/SFViewController.mm279
-rw-r--r--src/SFML/Window/OSX/SFWindow.h107
-rw-r--r--src/SFML/Window/OSX/SFWindow.m112
-rw-r--r--src/SFML/Window/OSX/SFWindowController.h88
-rw-r--r--src/SFML/Window/OSX/SFWindowController.mm629
-rw-r--r--src/SFML/Window/OSX/Scaling.h103
-rw-r--r--src/SFML/Window/OSX/SensorImpl.cpp88
-rw-r--r--src/SFML/Window/OSX/SensorImpl.hpp101
-rw-r--r--src/SFML/Window/OSX/VideoModeImpl.cpp99
-rw-r--r--src/SFML/Window/OSX/WindowImplCocoa.hpp377
-rw-r--r--src/SFML/Window/OSX/WindowImplCocoa.mm530
-rw-r--r--src/SFML/Window/OSX/WindowImplDelegateProtocol.h234
-rw-r--r--src/SFML/Window/OSX/cg_sf_conversion.hpp72
-rw-r--r--src/SFML/Window/OSX/cg_sf_conversion.mm97
-rw-r--r--src/SFML/Window/OSX/cpp_objc_conversion.h44
-rw-r--r--src/SFML/Window/OSX/cpp_objc_conversion.mm58
-rw-r--r--src/SFML/Window/OpenBSD/JoystickImpl.cpp97
-rw-r--r--src/SFML/Window/OpenBSD/JoystickImpl.hpp117
-rw-r--r--src/SFML/Window/Sensor.cpp53
-rw-r--r--src/SFML/Window/SensorImpl.hpp57
-rw-r--r--src/SFML/Window/SensorManager.cpp129
-rw-r--r--src/SFML/Window/SensorManager.hpp138
-rw-r--r--src/SFML/Window/Touch.cpp54
-rw-r--r--src/SFML/Window/Unix/ClipboardImpl.cpp384
-rw-r--r--src/SFML/Window/Unix/ClipboardImpl.hpp155
-rw-r--r--src/SFML/Window/Unix/CursorImpl.cpp156
-rw-r--r--src/SFML/Window/Unix/CursorImpl.hpp103
-rw-r--r--src/SFML/Window/Unix/Display.cpp110
-rw-r--r--src/SFML/Window/Unix/Display.hpp74
-rw-r--r--src/SFML/Window/Unix/GlxContext.cpp780
-rw-r--r--src/SFML/Window/Unix/GlxContext.hpp192
-rw-r--r--src/SFML/Window/Unix/GlxExtensions.cpp218
-rw-r--r--src/SFML/Window/Unix/GlxExtensions.hpp251
-rw-r--r--src/SFML/Window/Unix/GlxExtensions.txt14
-rw-r--r--src/SFML/Window/Unix/InputImpl.cpp329
-rw-r--r--src/SFML/Window/Unix/InputImpl.hpp168
-rw-r--r--src/SFML/Window/Unix/JoystickImpl.cpp708
-rw-r--r--src/SFML/Window/Unix/JoystickImpl.hpp131
-rw-r--r--src/SFML/Window/Unix/SensorImpl.cpp88
-rw-r--r--src/SFML/Window/Unix/SensorImpl.hpp101
-rw-r--r--src/SFML/Window/Unix/VideoModeImpl.cpp190
-rw-r--r--src/SFML/Window/Unix/WindowImplX11.cpp2181
-rw-r--r--src/SFML/Window/Unix/WindowImplX11.hpp330
-rw-r--r--src/SFML/Window/VideoMode.cpp146
-rw-r--r--src/SFML/Window/VideoModeImpl.hpp68
-rw-r--r--src/SFML/Window/Win32/ClipboardImpl.cpp103
-rw-r--r--src/SFML/Window/Win32/ClipboardImpl.hpp76
-rwxr-xr-xsrc/SFML/Window/Win32/CursorImpl.cpp188
-rwxr-xr-xsrc/SFML/Window/Win32/CursorImpl.hpp103
-rw-r--r--src/SFML/Window/Win32/InputImpl.cpp256
-rw-r--r--src/SFML/Window/Win32/InputImpl.hpp168
-rw-r--r--src/SFML/Window/Win32/JoystickImpl.cpp920
-rw-r--r--src/SFML/Window/Win32/JoystickImpl.hpp237
-rw-r--r--src/SFML/Window/Win32/SensorImpl.cpp88
-rw-r--r--src/SFML/Window/Win32/SensorImpl.hpp101
-rw-r--r--src/SFML/Window/Win32/VideoModeImpl.cpp73
-rw-r--r--src/SFML/Window/Win32/WglContext.cpp737
-rw-r--r--src/SFML/Window/Win32/WglContext.hpp193
-rw-r--r--src/SFML/Window/Win32/WglExtensions.cpp223
-rw-r--r--src/SFML/Window/Win32/WglExtensions.hpp236
-rw-r--r--src/SFML/Window/Win32/WglExtensions.txt13
-rwxr-xr-xsrc/SFML/Window/Win32/WindowImplWin32.cpp1166
-rwxr-xr-xsrc/SFML/Window/Win32/WindowImplWin32.hpp293
-rw-r--r--src/SFML/Window/Window.cpp449
-rw-r--r--src/SFML/Window/WindowImpl.cpp266
-rw-r--r--src/SFML/Window/WindowImpl.hpp285
-rw-r--r--src/SFML/Window/iOS/ClipboardImpl.hpp78
-rw-r--r--src/SFML/Window/iOS/ClipboardImpl.mm72
-rw-r--r--src/SFML/Window/iOS/CursorImpl.cpp68
-rw-r--r--src/SFML/Window/iOS/CursorImpl.hpp88
-rw-r--r--src/SFML/Window/iOS/EaglContext.hpp167
-rw-r--r--src/SFML/Window/iOS/EaglContext.mm256
-rw-r--r--src/SFML/Window/iOS/InputImpl.hpp168
-rw-r--r--src/SFML/Window/iOS/InputImpl.mm116
-rw-r--r--src/SFML/Window/iOS/JoystickImpl.hpp114
-rw-r--r--src/SFML/Window/iOS/JoystickImpl.mm97
-rw-r--r--src/SFML/Window/iOS/ObjCType.hpp37
-rw-r--r--src/SFML/Window/iOS/SFAppDelegate.hpp135
-rw-r--r--src/SFML/Window/iOS/SFAppDelegate.mm327
-rw-r--r--src/SFML/Window/iOS/SFMain.hpp35
-rw-r--r--src/SFML/Window/iOS/SFMain.mm61
-rw-r--r--src/SFML/Window/iOS/SFView.hpp59
-rw-r--r--src/SFML/Window/iOS/SFView.mm212
-rw-r--r--src/SFML/Window/iOS/SFViewController.hpp65
-rw-r--r--src/SFML/Window/iOS/SFViewController.mm49
-rw-r--r--src/SFML/Window/iOS/SensorImpl.hpp114
-rw-r--r--src/SFML/Window/iOS/SensorImpl.mm242
-rw-r--r--src/SFML/Window/iOS/VideoModeImpl.mm59
-rw-r--r--src/SFML/Window/iOS/WindowImplUIKit.hpp242
-rw-r--r--src/SFML/Window/iOS/WindowImplUIKit.mm251
-rwxr-xr-xtools/android/clean_all.sh6
-rwxr-xr-xtools/android/compile_arm-v7a.sh12
-rwxr-xr-xtools/android/compile_arm.sh12
-rwxr-xr-xtools/android/compile_libs.sh57
-rwxr-xr-xtools/android/compile_mips.sh12
-rwxr-xr-xtools/android/compile_x86.sh12
-rwxr-xr-xtools/android/create_toolchains.sh46
-rwxr-xr-xtools/android/download_sources.sh49
-rwxr-xr-xtools/android/make_all.sh38
-rw-r--r--tools/android/patches/remove-so-version-suffix.diff13
-rw-r--r--tools/android/readme.txt27
-rw-r--r--tools/pkg-config/sfml-all.pc.in10
-rw-r--r--tools/pkg-config/sfml-audio.pc.in15
-rw-r--r--tools/pkg-config/sfml-graphics.pc.in15
-rw-r--r--tools/pkg-config/sfml-network.pc.in12
-rw-r--r--tools/pkg-config/sfml-system.pc.in11
-rw-r--r--tools/pkg-config/sfml-window.pc.in14
563 files changed, 109763 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..3af2b9d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+# Configuration file for EditorConfig
+# More information is available under http://EditorConfig.org
+
+# Ignore any other files further up in the file system
+root = true
+
+# Configuration for all files
+[*]
+# Enforce Unix style line endings (\n only)
+end_of_line = lf
+# Always end files with a blank line
+insert_final_newline = true
+# Force space characters for indentation
+indent_style = space
+# Always indent by 4 characters
+indent_size = 4
+# Remove whitespace characters at the end of line
+trim_trailing_whitespace = true
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..2f88bea
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+* text=auto eol=lf
+
+extlibs/**/* -text -eol linguist-vendored
+cmake/toolchains/android.toolchain.cmake -text -eol
+
+*.png -text -eol
+*.jpg -text -eol
+*.wav -text -eol
+*.ogg -text -eol
+*.flac -text -eol
+*.tff -text -eol
+*.icns -text -eol
+*.rtf -text -eol
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..0fbd9e4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,54 @@
+Thanks for raising your issue here! 🙂
+
+Before you submit the issue however, we'd like you to consider the follow points.
+
+* We like to use the issue tracker for confirmed issues.
+* If you're stuck with SFML, please use [the forum](https://en.sfml-dev.org/forums/index.php#c3) to get help.
+
+----
+
+## Subject of the issue
+
+Describe your issue here.
+
+## Your environment
+
+* Your OS / distro / window manager used
+* Your version of SFML (2.5.0, git master, etc)
+* Your compiler and compiler version used
+* Special compiler flags used
+
+## Steps to reproduce
+
+Tell us how to reproduce this issue. Please provide a [minimal, complete and verifiable example](https://stackoverflow.com/help/mcve), you can use the follow template as a start:
+
+```cpp
+#include <SFML/Graphics.hpp>
+
+int main()
+{
+ sf::RenderWindow window(sf::VideoMode(1280, 720), "Minimal, complete and verifiable example");
+ window.setFramerateLimit(60);
+
+ while (window.isOpen())
+ {
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ if (event.type == sf::Event::Closed)
+ window.close();
+ }
+
+ window.clear();
+ window.display();
+ }
+}
+```
+
+## Expected behavior
+
+Tell us what should happen
+
+## Actual behavior
+
+Tell us what happens instead
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..92a926d
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,51 @@
+Thanks a lot for making a contribution to SFML! 🙂
+
+Before you create the pull request, we ask you to check the follow boxes. (For small changes not everything needs to ticked, but the more the better!)
+
+* [ ] Has this change been discussed on [the forum](https://en.sfml-dev.org/forums/index.php#c3) or in an issue before?
+* [ ] Does the code follow the SFML [Code Style Guide](https://www.sfml-dev.org/style.php)?
+* [ ] Have you provided some example/test code for your changes?
+* [ ] If you have additional steps which need to be performed list them as tasks!
+
+----
+
+## Description
+
+Please describe your pull request.
+
+This PR is related to the issue #
+
+## Tasks
+
+* [ ] Tested on Linux
+* [ ] Tested on Windows
+* [ ] Tested on macOS
+* [ ] Tested on iOS
+* [ ] Tested on Android
+
+## How to test this PR?
+
+Describe how to best test these changes. Please provide a [minimal, complete and verifiable example](https://stackoverflow.com/help/mcve) if possible, you can use the follow template as a start:
+
+```cpp
+#include <SFML/Graphics.hpp>
+
+int main()
+{
+ sf::RenderWindow window(sf::VideoMode(1280, 720), "Minimal, complete and verifiable example");
+ window.setFramerateLimit(60);
+
+ while (window.isOpen())
+ {
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ if (event.type == sf::Event::Closed)
+ window.close();
+ }
+
+ window.clear();
+ window.display();
+ }
+}
+``` \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..e821a49
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,512 @@
+# CMake's built-in Android support requires 3.7.0
+if(CMAKE_SYSTEM_NAME MATCHES "Android")
+ cmake_minimum_required(VERSION 3.7.2)
+else()
+ cmake_minimum_required(VERSION 3.0.2)
+endif()
+
+# define a macro that helps defining an option
+macro(sfml_set_option var default type docstring)
+ if(NOT DEFINED ${var})
+ set(${var} ${default})
+ endif()
+ set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
+endmacro()
+
+# these options have to be set before CMake detects/configures the toolchain
+
+# determine whether to create a debug or release build
+sfml_set_option(CMAKE_BUILD_TYPE Release STRING "Choose the type of build (Debug or Release)")
+
+# Suppress Cygwin legacy warning
+set(CMAKE_LEGACY_CYGWIN_WIN32 0)
+
+# Suppress Mac OS X RPATH warnings and adopt new related behaviors
+cmake_policy(SET CMP0042 NEW)
+if (NOT CMAKE_VERSION VERSION_LESS 3.9)
+ cmake_policy(SET CMP0068 NEW)
+endif()
+
+# add some default value for some additional macOS variable
+# note that those variables are ignored on other systems
+if(NOT CMAKE_OSX_ARCHITECTURES)
+ set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "macOS architecture to build; 64-bit is expected" FORCE)
+endif()
+if(NOT CMAKE_OSX_SYSROOT)
+ # query the path to the default SDK, will fail on non-macOS, but it's okay.
+ execute_process(COMMAND xcodebuild -sdk macosx -version Path
+ COMMAND head -n 1
+ COMMAND tr -d '\n'
+ OUTPUT_VARIABLE CMAKE_OSX_SYSROOT
+ ERROR_QUIET)
+endif()
+
+# project name
+project(SFML)
+
+# include the configuration file
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake)
+
+# setup version numbers
+set(VERSION_MAJOR 2)
+set(VERSION_MINOR 5)
+set(VERSION_PATCH 1)
+
+# add an option for choosing the build type (shared or static)
+if(NOT (SFML_OS_IOS OR SFML_OS_ANDROID))
+ sfml_set_option(BUILD_SHARED_LIBS TRUE BOOL "TRUE to build SFML as shared libraries, FALSE to build it as static libraries")
+else()
+ if(SFML_OS_IOS)
+ set(BUILD_SHARED_LIBS FALSE)
+ elseif(SFML_OS_ANDROID)
+ set(BUILD_SHARED_LIBS TRUE)
+ endif()
+endif()
+
+# add an option for building the examples
+if(NOT SFML_OS_ANDROID)
+ sfml_set_option(SFML_BUILD_EXAMPLES FALSE BOOL "TRUE to build the SFML examples, FALSE to ignore them")
+else()
+ set(SFML_BUILD_EXAMPLES FALSE)
+endif()
+
+# add options to select which modules to build
+sfml_set_option(SFML_BUILD_WINDOW TRUE BOOL "TRUE to build SFML's Window module. This setting is ignored, if the graphics module is built.")
+sfml_set_option(SFML_BUILD_GRAPHICS TRUE BOOL "TRUE to build SFML's Graphics module.")
+sfml_set_option(SFML_BUILD_AUDIO TRUE BOOL "TRUE to build SFML's Audio module.")
+sfml_set_option(SFML_BUILD_NETWORK TRUE BOOL "TRUE to build SFML's Network module.")
+
+# add an option for building the API documentation
+sfml_set_option(SFML_BUILD_DOC FALSE BOOL "TRUE to generate the API documentation, FALSE to ignore it")
+
+# add an option for choosing the OpenGL implementation
+if(SFML_BUILD_WINDOW)
+ sfml_set_option(SFML_OPENGL_ES ${OPENGL_ES} BOOL "TRUE to use an OpenGL ES implementation, FALSE to use a desktop OpenGL implementation")
+endif()
+
+# Mac OS X specific options
+if(SFML_OS_MACOSX)
+ # add an option to build frameworks instead of dylibs (release only)
+ sfml_set_option(SFML_BUILD_FRAMEWORKS FALSE BOOL "TRUE to build SFML as frameworks libraries (release only), FALSE to build according to BUILD_SHARED_LIBS")
+
+ # add an option to let the user specify a custom directory for external frameworks installation
+ sfml_set_option(SFML_DEPENDENCIES_INSTALL_PREFIX "/Library/Frameworks" PATH "External frameworks (FLAC, Freetype, Vorbis, ...) installation directory")
+
+ # add an option to automatically install Xcode templates
+ sfml_set_option(SFML_INSTALL_XCODE_TEMPLATES FALSE BOOL "TRUE to automatically install the Xcode templates, FALSE to do nothing about it. The templates are compatible with Xcode 4 and 5.")
+else()
+ # add an option to let the user specify a custom directory for external libraries installation
+ sfml_set_option(SFML_DEPENDENCIES_INSTALL_PREFIX "." PATH "External libraries (FLAC, Freetype, Vorbis, ...) installation directory")
+endif()
+
+# Android options
+if(SFML_OS_ANDROID)
+ # make sure there's the android library available
+ if (CMAKE_ANDROID_API LESS 14)
+ message(FATAL_ERROR "Android API level (${CMAKE_ANDROID_API}) must be equal or greater than 14.")
+ endif()
+
+ # CMake doesn't support defining the STL to be used with Nsight Tegra, so warn the user
+ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ message(WARNING "CMake might not properly support setting the STL. Make sure to adjust all generated library projects!")
+ endif()
+
+ # install everything in $NDK/sources/ because this path is appended by the NDK (convenient)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_ANDROID_NDK}/sources/third_party/sfml)
+
+ # we install libs in a subdirectory named after the ABI (lib/mips/*.so)
+ set(LIB_SUFFIX "/${CMAKE_ANDROID_ARCH_ABI}")
+
+ # pass shared STL configuration (if any)
+ if (CMAKE_ANDROID_STL_TYPE MATCHES "_shared")
+ add_definitions("-DSTL_LIBRARY=${CMAKE_ANDROID_STL_TYPE}")
+ # if(NOT CMAKE_ANDROID_STL_TYPE MATCHES "c\\+\\+_shared")
+ # message("Android: Using ${CMAKE_ANDROID_STL_TYPE} as STL. Set CMAKE_ANDROID_STL_TYPE to c++_shared, if there are any issues.")
+ # endif()
+ else()
+ # message(WARNING "Android: You're using a static STL (${CMAKE_ANDROID_STL_TYPE}). Set CMAKE_ANDROID_STL_TYPE to c++_shared, if there are any issues.")
+ endif()
+
+ # let the user switch ABIs
+ set(ANDROID_ABI "armeabi-v7a" CACHE STRING "Look at the NDK docs for currently supported ABIs")
+
+ # this is a workaround to compile sfml-activity without the stl library as a dependency
+ # we save the original compilation command line to restore it later in Macro.cmake
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY_WITH_STL ${CMAKE_CXX_CREATE_SHARED_LIBRARY})
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY_WITHOUT_STL "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# Install directories
+# For miscellaneous files
+if(SFML_OS_WINDOWS OR SFML_OS_IOS)
+ set(DEFAULT_INSTALL_MISC_DIR .)
+elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD)
+ set(DEFAULT_INSTALL_MISC_DIR share/SFML)
+elseif(SFML_OS_MACOSX)
+ set(DEFAULT_INSTALL_MISC_DIR /usr/local/share/SFML)
+elseif(SFML_OS_ANDROID)
+ set(DEFAULT_INSTALL_MISC_DIR ${CMAKE_ANDROID_NDK}/sources/third_party/sfml)
+endif()
+# add an option to let the user specify a custom directory for doc, examples, licence, readme and other miscellaneous files
+sfml_set_option(SFML_MISC_INSTALL_PREFIX "${DEFAULT_INSTALL_MISC_DIR}" PATH "Prefix installation path for miscellaneous files")
+
+
+# force building sfml-window, if sfml-graphics module is built
+if(SFML_BUILD_GRAPHICS AND NOT SFML_BUILD_WINDOW)
+ message(WARNING "You're trying to build SFML's Graphics module without the Window module. Forcing building of the Window module as a dependency.")
+ set(SFML_BUILD_WINDOW TRUE)
+endif()
+
+# allow not using bundled dependencies with a switch
+# (except for stb_image)
+# yes this is horrible, but GLOB_RECURSE sucks
+sfml_set_option(SFML_USE_SYSTEM_DEPS FALSE BOOL "TRUE to use system dependencies, FALSE to use the bundled ones.")
+if(SFML_USE_SYSTEM_DEPS)
+ if(SFML_INSTALL_XCODE_TEMPLATES)
+ message(FATAL_ERROR "XCode templates installation cannot be used with the SFML_USE_SYSTEM_DEPS option (the bundled frameworks are required.)")
+ endif()
+
+ file(GLOB_RECURSE DEP_LIBS "${CMAKE_SOURCE_DIR}/extlibs/libs*/*")
+ file(GLOB_RECURSE DEP_BINS "${CMAKE_SOURCE_DIR}/extlibs/bin*/*")
+ file(GLOB_RECURSE DEP_HEADERS "${CMAKE_SOURCE_DIR}/extlibs/headers/*")
+
+ foreach(DEP_FILE ${DEP_LIBS} ${DEP_BINS} ${DEP_HEADERS})
+ get_filename_component(DEP_DIR ${DEP_FILE} PATH)
+
+ if(NOT DEP_DIR MATCHES "/stb_image(/|$)")
+ set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH} ${DEP_DIR})
+ endif()
+
+ get_filename_component(DEP_PARENT_DIR ${DEP_DIR} PATH)
+ while(NOT DEP_PARENT_DIR STREQUAL "${CMAKE_SOURCE_DIR}/extlibs")
+ if(NOT DEP_DIR MATCHES "/stb_image(/|$)")
+ set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH} ${DEP_PARENT_DIR})
+ endif()
+
+ get_filename_component(DEP_PARENT_DIR ${DEP_PARENT_DIR} PATH)
+ endwhile()
+ endforeach()
+
+ list(REMOVE_DUPLICATES CMAKE_IGNORE_PATH)
+endif()
+
+# Visual C++: remove warnings regarding SL security and algorithms on pointers
+if(SFML_COMPILER_MSVC)
+ # add an option to choose whether PDB debug symbols should be generated (defaults to true when possible)
+ if(CMAKE_VERSION VERSION_LESS 3.1)
+ sfml_set_option(SFML_GENERATE_PDB FALSE BOOL "True to generate PDB debug symbols, FALSE otherwise. Requires CMake 3.1.")
+ if(SFML_GENERATE_PDB)
+ message(FATAL_ERROR "Generation of PDB files (SFML_GENERATE_PDB) requires at least CMake 3.1.0")
+ endif()
+ else()
+ sfml_set_option(SFML_GENERATE_PDB TRUE BOOL "True to generate PDB debug symbols, FALSE otherwise. Requires CMake 3.1.")
+ endif()
+
+ add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
+endif()
+
+# define SFML_OPENGL_ES if needed
+if(SFML_OPENGL_ES)
+ add_definitions(-DSFML_OPENGL_ES)
+ add_definitions(-DGL_GLEXT_PROTOTYPES)
+endif()
+
+# define an option for choosing between static and dynamic C runtime (Windows only)
+if(SFML_OS_WINDOWS)
+ sfml_set_option(SFML_USE_STATIC_STD_LIBS FALSE BOOL "TRUE to statically link to the standard libraries, FALSE to use them as DLLs")
+
+ # the following combination of flags is not valid
+ if (BUILD_SHARED_LIBS AND SFML_USE_STATIC_STD_LIBS)
+ message(FATAL_ERROR "BUILD_SHARED_LIBS and SFML_USE_STATIC_STD_LIBS cannot be used together")
+ endif()
+
+ # for VC++, we can apply it globally by modifying the compiler flags
+ if(SFML_COMPILER_MSVC AND SFML_USE_STATIC_STD_LIBS)
+ foreach(flag
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ if(${flag} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
+ endif()
+ endforeach()
+ endif()
+endif()
+
+# setup Mac OS X stuff
+if(SFML_OS_MACOSX)
+ # SFML_BUILD_FRAMEWORKS needs two things:
+ # first, it's available only for release
+ # (because cmake currently doesn't allow specifying a custom framework name so XXX-d is not possible)
+ # secondly, it works only with BUILD_SHARED_LIBS enabled
+ if(SFML_BUILD_FRAMEWORKS)
+ # requirement #1
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
+ message(FATAL_ERROR "CMAKE_BUILD_TYPE should be \"Release\" when SFML_BUILD_FRAMEWORKS is TRUE")
+ return()
+ endif()
+
+ # requirement #2
+ if(NOT BUILD_SHARED_LIBS)
+ message(FATAL_ERROR "BUILD_SHARED_LIBS should be TRUE when SFML_BUILD_FRAMEWORKS is TRUE")
+ return()
+ endif()
+ endif()
+
+ # only the default architecture (i.e. 64-bit) is supported
+ if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
+ message(FATAL_ERROR "Only 64-bit architecture is supported")
+ endif()
+
+ # configure Xcode templates
+ set(XCODE_TEMPLATES_ARCH "\$(NATIVE_ARCH_ACTUAL)")
+endif()
+
+# enable project folders
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake")
+
+# add the subdirectories
+add_subdirectory(src/SFML)
+if(SFML_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
+if(SFML_BUILD_DOC)
+ add_subdirectory(doc)
+endif()
+
+# on Linux and BSD-like OS, install pkg-config files by default
+set(SFML_INSTALL_PKGCONFIG_DEFAULT FALSE)
+
+if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD)
+ set(SFML_INSTALL_PKGCONFIG_DEFAULT TRUE)
+endif()
+
+sfml_set_option(SFML_INSTALL_PKGCONFIG_FILES ${SFML_INSTALL_PKGCONFIG_DEFAULT} BOOL "TRUE to automatically install pkg-config files so other projects can find SFML")
+
+if(SFML_INSTALL_PKGCONFIG_FILES)
+ sfml_set_option(SFML_PKGCONFIG_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/${SFML_PKGCONFIG_DIR}" PATH "Install directory for SFML's pkg-config .pc files")
+
+ foreach(sfml_module IN ITEMS all system window graphics audio network)
+ CONFIGURE_FILE(
+ "tools/pkg-config/sfml-${sfml_module}.pc.in"
+ "tools/pkg-config/sfml-${sfml_module}.pc"
+ @ONLY)
+ INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/tools/pkg-config/sfml-${sfml_module}.pc"
+ DESTINATION "${SFML_PKGCONFIG_INSTALL_PREFIX}")
+ endforeach()
+endif()
+
+# setup the install rules
+if(NOT SFML_BUILD_FRAMEWORKS)
+ install(DIRECTORY include
+ DESTINATION .
+ COMPONENT devel
+ FILES_MATCHING PATTERN "*.hpp" PATTERN "*.inl")
+
+ if(SFML_GENERATE_PDB)
+ install(DIRECTORY ${PROJECT_BINARY_DIR}/lib
+ DESTINATION .
+ COMPONENT devel
+ FILES_MATCHING PATTERN "*.pdb")
+ endif()
+else()
+ # find only "root" headers
+ file(GLOB SFML_HEADERS RELATIVE ${PROJECT_SOURCE_DIR} "include/SFML/*")
+
+ # in fact we have to fool cmake to copy all the headers in subdirectories
+ # to do that we have to add the "root" headers to the PUBLIC_HEADER
+ # then we can run a post script to copy the remaining headers
+
+ # we need a dummy file in order to compile the framework
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
+ COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp)
+
+ set(SFML_SOURCES ${SFML_HEADERS})
+ list(APPEND SFML_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp)
+
+ # create SFML.framework
+ add_library(SFML ${SFML_SOURCES})
+
+ # set the target flags to use the appropriate C++ standard library
+ sfml_set_stdlib(SFML)
+
+ # edit target properties
+ set_target_properties(SFML PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ MACOSX_FRAMEWORK_IDENTIFIER org.sfml-dev.SFML
+ MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ MACOSX_FRAMEWORK_BUNDLE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ PUBLIC_HEADER "${SFML_HEADERS}")
+
+ # add the non-optional SFML headers
+ add_custom_command(TARGET SFML POST_BUILD COMMAND cp -r
+ ${PROJECT_SOURCE_DIR}/include/SFML/Config.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/OpenGL.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/GpuPreference.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/System.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/Main.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/System
+ $<TARGET_FILE_DIR:SFML>/Headers)
+
+ # add window module headers if enabled
+ if(SFML_BUILD_WINDOW)
+ add_custom_command(TARGET SFML POST_BUILD COMMAND cp -r
+ ${PROJECT_SOURCE_DIR}/include/SFML/Window.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/Window
+ $<TARGET_FILE_DIR:SFML>/Headers)
+ endif()
+
+ # add network module headers if enabled
+ if(SFML_BUILD_NETWORK)
+ add_custom_command(TARGET SFML POST_BUILD COMMAND cp -r
+ ${PROJECT_SOURCE_DIR}/include/SFML/Network.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/Network
+ $<TARGET_FILE_DIR:SFML>/Headers)
+ endif()
+
+ # add graphics module headers if enabled
+ if(SFML_BUILD_GRAPHICS)
+ add_custom_command(TARGET SFML POST_BUILD COMMAND cp -r
+ ${PROJECT_SOURCE_DIR}/include/SFML/Graphics.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/Graphics
+ $<TARGET_FILE_DIR:SFML>/Headers)
+ endif()
+
+ # add audio module headers if enabled
+ if(SFML_BUILD_AUDIO)
+ add_custom_command(TARGET SFML POST_BUILD COMMAND cp -r
+ ${PROJECT_SOURCE_DIR}/include/SFML/Audio.hpp
+ ${PROJECT_SOURCE_DIR}/include/SFML/Audio
+ $<TARGET_FILE_DIR:SFML>/Headers)
+ endif()
+
+ # adapt install directory to allow distributing dylibs/frameworks in user's frameworks/application bundle
+ # NOTE: it's not required to link against SFML.framework
+ set_target_properties(SFML PROPERTIES INSTALL_NAME_DIR "@rpath")
+ if(NOT CMAKE_SKIP_BUILD_RPATH)
+ if (CMAKE_VERSION VERSION_LESS 3.9)
+ set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+ else()
+ set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_NAME_DIR TRUE)
+ endif()
+ endif()
+
+ # install rule
+ install(TARGETS SFML
+ FRAMEWORK DESTINATION "."
+ COMPONENT devel)
+endif()
+
+install(FILES license.md DESTINATION ${SFML_MISC_INSTALL_PREFIX})
+install(FILES readme.md DESTINATION ${SFML_MISC_INSTALL_PREFIX})
+
+# install 3rd-party libraries and tools
+if(SFML_OS_WINDOWS)
+
+ if(NOT SFML_USE_SYSTEM_DEPS)
+ # install the binaries of SFML dependencies
+ if(ARCH_32BITS)
+ install(DIRECTORY extlibs/bin/x86/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/bin)
+ if(SFML_COMPILER_MSVC AND SFML_MSVC_VERSION LESS 14)
+ install(DIRECTORY extlibs/libs-msvc/x86/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ elseif(SFML_COMPILER_MSVC)
+ install(DIRECTORY extlibs/libs-msvc-universal/x86/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ else()
+ install(DIRECTORY extlibs/libs-mingw/x86/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ endif()
+ elseif(ARCH_64BITS)
+ install(DIRECTORY extlibs/bin/x64/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/bin)
+ if(SFML_COMPILER_MSVC AND SFML_MSVC_VERSION LESS 14)
+ install(DIRECTORY extlibs/libs-msvc/x64/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ elseif(SFML_COMPILER_MSVC)
+ install(DIRECTORY extlibs/libs-msvc-universal/x64/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ else()
+ install(DIRECTORY extlibs/libs-mingw/x64/ DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX}/lib)
+ endif()
+ endif()
+ endif()
+
+elseif(SFML_OS_MACOSX)
+ # install extlibs dependencies only when used
+ if(SFML_BUILD_GRAPHICS)
+ if(FREETYPE_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/freetype.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/freetype.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+ endif()
+
+ if(SFML_BUILD_AUDIO)
+ if(FLAC_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/FLAC.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/FLAC.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+
+ if(OGG_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/ogg.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/ogg.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+
+ if(VORBIS_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/vorbis.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/vorbis.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+
+ if(VORBISENC_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/vorbisenc.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/vorbisenc.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+
+ if(VORBISFILE_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/vorbisfile.framework")
+ install(DIRECTORY extlibs/libs-osx/Frameworks/vorbisfile.framework DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+
+ if(OPENAL_LIBRARY STREQUAL "${SFML_SOURCE_DIR}/extlibs/libs-osx/Frameworks/OpenAL.framework")
+ install(DIRECTORY "${OPENAL_LIBRARY}" DESTINATION ${SFML_DEPENDENCIES_INSTALL_PREFIX})
+ endif()
+ endif()
+
+ # install the Xcode templates if requested
+ if(SFML_INSTALL_XCODE_TEMPLATES)
+ # configure the templates plist files
+ foreach(TEMPLATE "SFML Compiler" "SFML App")
+ configure_file(
+ "tools/xcode/templates/SFML/${TEMPLATE}.xctemplate/TemplateInfo.plist.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/tools/xcode/templates/SFML/${TEMPLATE}.xctemplate/TemplateInfo.plist"
+ @ONLY)
+ endforeach()
+ install(DIRECTORY "tools/xcode/templates/SFML" "${CMAKE_CURRENT_BINARY_DIR}/tools/xcode/templates/SFML"
+ DESTINATION /Library/Developer/Xcode/Templates
+ PATTERN "*.in" EXCLUDE
+ PATTERN ".DS_Store" EXCLUDE)
+ endif()
+
+elseif(SFML_OS_IOS)
+
+ # fix CMake install rules broken for iOS (see http://public.kitware.com/Bug/view.php?id=12506)
+ install(DIRECTORY "${CMAKE_BINARY_DIR}/lib/\$ENV{CONFIGURATION}/" DESTINATION lib${LIB_SUFFIX})
+
+ if(NOT SFML_USE_SYSTEM_DEPS)
+ # since the iOS libraries are built as static, we must install the SFML dependencies
+ # too so that the end user can easily link them to its final application
+ if(SFML_BUILD_GRAPHICS)
+ install(FILES extlibs/libs-ios/libfreetype.a DESTINATION lib)
+ endif()
+
+ if(SFML_BUILD_AUDIO)
+ install(FILES extlibs/libs-ios/libflac.a
+ extlibs/libs-ios/libvorbis.a
+ extlibs/libs-ios/libogg.a
+ DESTINATION lib)
+ endif()
+ endif()
+
+elseif(SFML_OS_ANDROID)
+
+ if(NOT SFML_USE_SYSTEM_DEPS)
+ # install extlibs
+ install(DIRECTORY extlibs/libs-android/${CMAKE_ANDROID_ARCH_ABI} DESTINATION extlibs/lib)
+ install(FILES extlibs/Android.mk DESTINATION extlibs)
+ endif()
+
+ # install Android.mk so the NDK knows how to set up SFML
+ install(FILES src/SFML/Android.mk DESTINATION .)
+
+endif()
+
+sfml_export_targets()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..ce2b66c
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,7 @@
+# Contribution Guidelines
+
+You would like to see a feature implemented or a bug fixed in SFML? Great! Contributions to SFML are highly appreciated, be it in the form of general ideas, concrete suggestions or code patches.
+
+[A few guiding rules have been set up on the SFML website](https://www.sfml-dev.org/contribute.php) that you should be aware of before opening an Issue or Pull Request. They will help you focus on the important stuff and prevent you from losing (y)our time with requests that are out of SFML's scope, known issues, and so on.
+
+Those rules cover the general scope defined for this project, a coding style, and a precise procedure to report bugs or suggest new features.
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000..6174a84
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,702 @@
+# Changelog
+
+## SFML 2.5.1
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.5.1
+
+### General
+
+ * Various CMake fixes (#1414, #1416, #1436, #1439, #1467, #1470)
+ * Fixed the installation of pkg-config files (#1466)
+ * Fixed two conversion warnings (#1454)
+ * [Android] Fixes all symbols in sfml-main are hidden (#1457, #1460)
+ * [Android] Fixed some `#define` flag problem (#1458)
+ * [Android] Fix deadlock in main cleanup (#1265)
+ * [iOS] Modernized toolchain file (#1411)
+ * [iOS] Check that `<SFML/Main.hpp>` is used (#1412)
+ * [macOS] Add `-ObjC` flag to fix static linking on macOS (#1485)
+
+### Window
+
+**Bugfixes**
+
+ * [iOS] Use default supported rotations when none are specified (#1417)
+ * [iOS] Fixed autocomplete window overlaps keyboard (#1473, #1482)
+ * [Linux] Fixed dual monitor issue (#1226, #1238)
+ * [Linux] Fixed issue where fullscreen window didn't go over task bars on top and left on in Ubuntu (#1224)
+ * [Linux] Fixed the Unix clipboard implementation causing an abort due to internal data races in Xlib (#1437)
+ * [macOS] Added additional system cursors (#1401, #1413, #1425)
+ * [Windows] Fixed swapped colors for custom cursors (#1464, #1465, #1491)
+
+### Graphics
+
+**Bugfixes**
+
+ * Fixed a bug in which a `sf::RenderTexture` would not be re-activated after being re-created (#1438)
+ * Fixed `sf::RenderTextureImplFBO`'s destructor incorrectly triggering deletion of other `sf::RenderTextureImplFBO`'s active FBOs (#1440)
+ * Fix `sf::RenderWindow::setActive` incorrectly trying to unbind an FBO during deactivation (#1442)
+ * Fixed `sf::RenderTexture::display()` dereferencing a NULL pointer when being called before `sf::RenderTexture::create()` (#1446)
+ * Fixed bug in `sf::Text` when applying an outline color/thickness (#1176)
+ * Squash duplicated `sf::Font` glyphs to single chars (#1461)
+ * Fixed two issues with glyph sub-pixel positioning (#1452)
+ * Reduced context locking & unlocking while creating textures (#1459)
+ * Fixed the error message when the wrong bitmap font size is selected (#1456, #1474, #1492)
+
+### Audio
+
+**Bugfixes**
+
+ * Fixed performance issue with reading WAV files (#1450)
+
+## SFML 2.5.0
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.5.0
+
+### General
+
+ * Replaced FindSFML.cmake with SFMLConfig.cmake (#1335)
+ * Markdown'd and updated readme, changelog, contributing and license files (#1196, #1368, #1317)
+ * Improve packaging support (#1173)
+ * Added Tagfile generation and search (#1327)
+ * Added CMake variables to select the modules to be built (#798, #800)
+ * Do not install extlibs if `SFML_USE_SYSTEM_DEPS` is true (#1236, #1237)
+ * Fixed various type conversion/comparison warnings (#1325)
+ * [Android] Increased minimum API version to 14 (#1362)
+ * [Android] Removed custom toolchain and added support for the newest NDK version and Gradle (#1350, #1393)
+ * [iOS] Updated the binary libs from exlibs/libs-ios (#1207, #1209)
+ * [iOS] Use a CMake toolchain file for iOS build (#1268, #1269)
+ * [iOS] Install extlibs if needed (#1348)
+ * [iOS] Drop 32 bit support (#1374)
+ * [iOS] Force correct iOS architecture for cmake (#1373, #1377)
+ * [iOS] Added iOS example (#1378)
+ * [macOS] Fixed launch of cocoa examples (#1334)
+ * [macOS] Improved application signing process (#1020, #1036, #1194)
+ * [macOS] Improved CMake script (#1215, #1371)
+ * [macOS] Use `-stdlib=libc++` (#1361)
+ * [OpenBSD] Added support for OpenBSD (#1330)
+
+### System
+
+**Bugfixes**
+
+ * Added protected destructor to `sf::NonCopyable` to prevent possible resource leaks (#1125, #1161)
+ * Fixed crash when `sf::Clock` is constructed in a global scope (#1258)
+
+### Window
+
+**Features**
+
+ * Implemented Cursor API (#269, #784, #827)
+ * Implemented Clipboard API (#715, #1204, #1221)
+ * Renamed a few key codes (#1395)
+ * Added joystick example (#1363)
+ * [Windows] Added support for interfacing with joysticks via DirectInput when it is available (#1251, #1326)
+ * [Windows] Fix discrete GPU preference symbols being exported from the wrong place (#1192, #1406)
+
+**Bugfixes**
+
+ * [Android] Return correct key code for delete/backspace (#1309, #1362)
+ * [iOS] Don't need to find vorbisfile or vorbisenc (#1347)
+ * [Linux] Fixed `sf::Window::getPosition()` returning incorrect position because of differences in window managers (#1228, #1266)
+ * [Linux] Fix X11 key repeat handling not filtering out events from other windows (#1223, #1230, #1291)
+ * [Linux] Restore fullscreen of a non-visible window (#1339)
+ * [macOS] Fixed window menu not working (#1091, #1180, #1193)
+ * [macOS] Fixed crash with application messing hardware detection e.g. TeamViewer (#1323)
+ * [macOS] Added support for (some) Hat/POV axis (#1248)
+ * [Windows] Prevent uninitialized read by zeroing memory (#1264)
+ * [Windows] Fixed modifier keys handling (#1357)
+
+### Graphics
+
+**Features**
+
+ * Implemented additional line spacing and letter spacing in `sf::Text` (#928, #1366)
+ * Added `sf::VertexBuffer` class (#1308)
+ * Added GPU local texture copying support, allowing performance optimizations and texture swapping (#1119, #1319, #1320)
+ * Optimize performance by skipping `glTexCoordPointer()` call if not needed (#1015)
+ * Generate shape outline vertices only if necessary (#925, #1356)
+ * Removed dependency to libjpeg, stb_image_write now supports writing JPEG files (#1278, #1279)
+ * Enable comparing `sf::Transform` and optimize resetting OpenGL back to the identity matrix (#1298)
+ * Added missing `setActive()` virtual method to `sf::RenderTarget` (#1157)
+ * Updated stb_image to v2.16 and stb_image_write to v1.07 (#1270)
+ * Added `sf::RenderTexture` stencil and multisampling support (#1274, #1285)
+ * Added example demonstrating `sf::VertexBuffer`, `sf::Shader` and `sf::Thread` usage (#1352)
+ * Optimized `sf::RenderTexture` performance (#1379)
+
+**Bugfixes**
+
+ * Properly free memory in `sf::Font::cleanup()` (#1119)
+ * Fixed memory leak in `sf::Font` (#1216)
+ * Fix OpenGL texture coordinate pointer not being updated correctly under certain conditions (#1297)
+ * Fix for broken text when the font is reloaded (#1345)
+ * Fix memory leak in `sf::Text` (#1233, #1360)
+ * Fixed strict aliasing punning warning when generating the key of a glyph in Font.cpp (#1187, #1396)
+ * Fixed OpenGL version string being parsed incorrectly on some platforms (#1249, #1390)
+ * [macOS] Worked around render target bug (#1132, #1342)
+ * [Windows] Replaced time-based joystick poll with a hardware event handler (#1179, #1195, #1198, #1199, #1421)
+
+### Audio
+
+**Features**
+
+ * Added loop point support to `sf::Music` (#177, #629)
+ * Added support for the extensible PCM wave file format (#1296)
+ * [iOS] Enable audio module (#1338)
+
+**Bugfixes**
+
+ * Fixed inconsistent seek behavior in `sf::SoundStream` (#1118)
+ * Fixed stack overflow in `sf::SoundStream::fillAndPushBuffer()` (#1154)
+ * Fixed seeking quirks in the FLAC reader (#966, #1162)
+ * Allow polymorphism with `sf::SoundSource` (#1185)
+ * Fixed WAV file writer writing wrong header values (#1280, #1281)
+ * Small bugfix to argument of `alcCaptureOpenDevice()` (#1304, #1305)
+ * [iOS] Find OpenAL correctly (#1263, #1376)
+ * [Windows] Updated OpenAL Soft to 1.18.1 fixing crashes (#1247, #1260)
+
+### Network
+
+**Features**
+
+ * Add append/overwrite parameter to Ftp::upload (#1072, #1399)
+
+**Bugfixes**
+
+ * Fixed wrong condition for building network support (#1253)
+ * Changed TCP listen backlog from 0 to SOMAXCONN (#1369, #1407)
+ * Fixed socket reuse not conforming to documentation (#1346, #1408)
+
+## SFML 2.4.2
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.4.2
+
+### System
+
+**Bugfixes**
+
+ * [Windows] Removed thread affinity changes in sf::Clock (#1107)
+
+### Window
+
+**Bugfixes**
+
+ * Fixed bug where TransientContextLock would hang (#1165, #1172)
+ * [Linux] Fixed GLX extensions being loaded too late (#1183)
+ * [Linux] Fix wrong types passed to XChangeProperty (#1168, #1171)
+ * [Windows] Make context disabling via wglMakeCurrent more tolerant of broken drivers (#1186)
+
+### Graphics
+
+**Bugfixes**
+
+ * Optimized sf::Image::create and made it more exception safe (#1166)
+
+## SFML 2.4.1
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.4.1
+
+### General
+
+ * [kFreeBSD] Define SFML_OS_FREEBSD when compiling for kFreeBSD (#1129)
+ * [Windows] Added some simple messaging when trying to build under Cygwin (#1153)
+
+### Window
+
+**Bugfixes**
+
+ * Fixed stack overflow on GlContext creation with multiple threads (#989, #1002)
+ * Adjusted mouse cursor grab documentation (#1133)
+ * [iOS] Fixed orientation change not rescaling window size properly (#1049, #1050)
+ * [Linux] Fixed fullscreen issue (#921, #1138)
+ * [Linux] Switched from XCB back to Xlib for windowing (#1138)
+ * [Linux] Fixed window icon not showing up on some distros (#1087, #1088)
+ * [Linux] Fixed an issue where GNOME flags window unresponsive (#1089, #1138)
+ * [Linux] Fixed leak of XVisualInfo objects during GlxContext creation (#1135)
+ * [Linux] Fixed possible hang when setting visibility if external window sources (#1136)
+ * [macOS] Fixed inconsistency between doc and impl on macOS for the grab feature (#1133, #1148, #1150)
+ * [Windows] Fixed context memory leaks (#1143, #1002)
+
+### Graphics
+
+**Bugfixes**
+
+ * Adjusted uniform error message (#1131)
+ * Clarify documentation on Rect::contains function bounds (#1151)
+
+### Network
+
+**Bugfixes**
+
+ * Fixed a typo in comment for void unbind() (#1121)
+
+## SFML 2.4.0
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.4.0
+
+### General
+
+ * Added deprecation macro (#969)
+ * Fixed issues reported by Coverity Scan static analysis (#1064)
+ * Fixed some initialization issues reported by Cppcheck (#1008)
+ * Changed comment chars in FindSFML.cmake to # (#1090)
+ * Fixed some typos (#1098, #993, #1099, #956, #963, #979)
+ * Updated/fixed string comparisons in Config.cmake (#1102)
+ * Added the missing -s postfix for the RelWithDebInfo config (#1014)
+ * [Android] Fixed current Android compilation issues (#1116, #1111, #1079)
+ * [macOS] Update Xcode template material (#976, #968)
+ * [Windows] Added support for VS 2015 (#972)
+ * [Windows] Create and install PDB debug symbols alongside binaries (#1037)
+
+### Deprecated API
+
+ * sf::RenderWindow::capture(): Use a sf::Texture and its sf::Texture::update(const Window&) function and copy its contents into an sf::Image instead.
+ * sf::Shader::setParameter(): Use setUniform() instead.
+ * sf::Text::getColor(): There is now fill and outline colors instead of a single global color. Use getFillColor() or getOutlineColor() instead.
+ * sf::Text::setColor(): There is now fill and outline colors instead of a single global color. Use setFillColor() or setOutlineColor() instead.
+ * sf::LinesStrip: Use LineStrip instead.
+ * sf::TrianglesFan: Use TriangleFan instead.
+ * sf::TrianglesStrip: Use TriangleStrip instead.
+
+### System
+
+**Features**
+
+ * [Android] Added sf::getNativeActivity() (#1005, #680)
+
+**Bugfixes**
+
+ * Added missing <iterator> include in String.hpp (#1069, #1068)
+ * Fixed encoding of UTF-16 (#997)
+ * [Android] Fixed crash when trying to load a non-existing font file (#1058)
+
+### Window
+
+**Features**
+
+ * Added ability to grab cursor (#614, #394, #1107)
+ * Added Multi-GPU preference (#869, #867)
+ * Added support for sRGB capable framebuffers (#981, #175)
+ * [Linux, Windows] Improved OpenGL context creation (#884)
+ * [Linux, Windows] Added support for pbuffers on Windows and Unix (#885, #434)
+
+**Bugfixes**
+
+ * Updated platform-specific handle documentation (#961)
+ * [Android] Accept touch events from "multiple" devices (#954, #953)
+ * [Android] Copy the selected EGL context's settings to SFML (#1039)
+ * [Linux] Fixed modifiers causing sf::Keyboard::Unknown being returned (#1022, #1012)
+ * [macOS] Improved memory management on macOS (#962, #790)
+ * [macOS] Fixed crash when resizing a window to a zero-height/width size (#986, #984)
+ * [macOS] Use the mouse button constant instead of 0 to avoid a compiler error on macOS (#1035)
+ * [macOS] macOS improvement: warnings + bugfix + refactoring, the lot! (#1042)
+
+### Graphics
+
+**Features**
+
+ * Added support for outlined text (#840)
+ * Add support for geometry shaders (#886, #428)
+ * Feature/blend mode reverse subtract (#945, #944)
+ * Implemented support for mipmap generation (#973, #498, #123)
+ * Added new API to set shader uniforms (#983, #538)
+ * Rewrite RenderWindow::capture (#1001)
+
+**Bugfixes**
+
+ * Exporting some Glsl utility functions due to linking issues (#1044, #1046)
+ * Fixed missing initialisation of Font::m_stroker (#1059)
+ * Changed primitive types to be grammatically correct (#1095, #939)
+
+### Audio
+
+**Features**
+
+ * Implemented stereo audio recording (#1010)
+
+**Bugfixes**
+
+ * Added an assignment operator to SoundSource (#864)
+ * [macOS] Updates OpenAL-soft for macOS to version 1.17.2 (#1057, #900, #1000)
+ * Fixed a bug where vorbis can't handle large buffers (#1067)
+ * Added support for 24-bit .wav files (#958, #955)
+ * Fixed threading issue in sf::SoundRecorder (#1011)
+ * Made WAV file reader no longer assume that data chunk goes till end of file to prevent reading trailing metadata as samples (#1018)
+ * Fixed seeking in multi channel FLAC files (#1041, #1040)
+
+### Network
+
+**Features**
+
+ * Added optional argument on which address to bind (socket). (#850, #678)
+
+**Bugfixes**
+
+ * Fixed FTP directory listing blocking forever (#1086, #1025)
+
+## SFML 2.3.2
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.3.2
+
+### General
+
+ * Fixed an issue where FindSFML.cmake couldn't find older versions of SFML (#903)
+ * Robust alCheck and glCheck macros (#917)
+ * Fixed FindSFML.cmake to use the uppercase FLAC name (#923)
+ * Added a CONTRIBUTING file so GitHub shows a message when creating a new issue (#932)
+
+### Window
+
+**Bugfixes**
+
+ * [Linux] Fixed an issue where the keypad's key weren't being detected (#910)
+ * [Linux] Revert to Xlib event handling (#934)
+ * [Linux] Fixed `XK_*` inconsistency in InpuImpl.cpp (#947)
+ * [Linux] Fix `_NET_WM_PING` messages not being replied to properly (#947)
+
+### Graphics
+
+**Bugfixes**
+
+ * Fixed clear bug on RenderTextures (#915)
+ * Fixed image file extension detection (#929, #930, #931)
+ * Secure function against random data return (#935, #942)
+
+## SFML 2.3.1
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.3.1
+
+### Window
+
+**Bugfixes**
+
+ * [Android] Make sure a window still exists before trying to access its dimensions (#854)
+ * [Android] Added Android API level checks (#856)
+ * [Android] Updated the JNI/event handling code (#906)
+ * [Linux] Resized events are only spawned when the window size actually changes (#878, #893)
+ * [Linux] Whitelisted X SHAPE events (#879, #883)
+ * [Linux] Remap Unix keyboard when user changes layout (#895, #897)
+ * [Linux] Fix undefined behavior in ewmhSupported() (#892, #901)
+
+### Graphics
+
+**Bugfixes**
+
+ * Added support for GL_EXT_texture_edge_clamp for systems that don't expose GL_SGIS_texture_edge_clamp (#880, #882)
+
+### Audio
+
+**Bugfixes**
+
+ * [Android] Fixed audio files not loading (and possibly crashing) (#855, #887)
+
+## SFML 2.3
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.3
+
+### General
+
+ * Examples only link against sfml-main in release mode (#610, #766)
+ * Replaced unsigned int with std::size_t for array indices and sizes (#739)
+ * Fixed some issues with the Doxygen documentation (#750)
+ * Added support for EditorConfig (#751)
+ * Hide success message for CMake in quiet mode (#753)
+ * Improved documentation for statuses with sf::Ftp (#763)
+ * Moved stb_image into the extlibs directory (#795)
+ * Changed the SOVERSION to major.minor (#812)
+ * Fixed warnings about switch-statements (#863)
+ * Added missing includes in the general headers (#851)
+ * [Android] Updated toolchain file and dependencies (#791)
+ * [Linux] Fixed missing pthread dependency (#794)
+ * [macOS] Relaxed CMake installation rules regarding framework dependencies (#767)
+
+### Deprecated API
+
+ * sf::Event::MouseWheelEvent: This event is deprecated and potentially inaccurate. Use MouseWheelScrollEvent instead.
+
+### Window
+
+**Features**
+
+ * Added new events for handling high-precision scrolling (#95, #810, #837)
+ * Switched from Xlib to XCB (#200, #319, #694, #780, #813, #825)
+ * Added support for OpenGL 3 core context creation (#654, #779)
+
+**Bugfixes**
+
+ * Fixed glXSwapIntervalSGI being broken for some driver implementations (#727, #779)
+ * Fixed simultaneous context operations causing crashes on some AMD hardware (#778, #779)
+ * Fixed joystick identification (#809, #811)
+ * [iOS] Fixed various issues including stencil bits, device orientation and retina support (#748)
+ * [iOS] Fixed inconsistency between sf::Touch::getPosition and touch events (#875)
+ * [Linux] Fixed Alt+F4 not getting triggered in window mode (#274)
+ * [Linux] Fixed Unix joystick stuff (#838)
+ * [macOS] Fixed typo in JoystickImpl.cpp to prevent a crash (#762, #765)
+ * [macOS] Fixed an issue in InputImpl::getSFOpenGLViewFromSFMLWindow (#782, #792)
+
+### Graphics
+
+**Features**
+
+ * Replaced GLEW with loader generated by glLoadGen (#779)
+ * Added a new constructor to sf::Color that takes an sf::Uint32 (#722)
+ * Updated stb_image to v2.02 (#777)
+ * Updated FreeType to v2.5.5 (#799, #804)
+ * Added checks for software OpenGL (#870)
+
+**Bugfixes**
+
+ * Fixed GL_ARB_compatibility not being detected (#859)
+ * Fixed pixel format selection (#862)
+ * Bumped back the OpenGL version requirement to 1.1 (#858)
+
+### Audio
+
+**Features**
+
+ * Dropped libsndfile and started using Vorbis, FLAC and OGG directly (#604, #757)
+ * Added a FLAC file to the sound example (#815)
+
+**Bugfixes**
+
+ * Fixed access violation error in the destructor of sf::AudioDevice (#30, #602)
+ * [macOS] Fixed threading issue with sf::SoundStream and OpenAL (#541, #831)
+
+### Network
+
+**Bugfixes**
+
+ * Fixed sf::TcpSocket not handling partial sends properly (#749, #796)
+
+## SFML 2.2
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.2
+
+### General
+
+ * Support for iOS and Android platform (#410, #440)
+ * Various documentation corrections (#438, #496, #497, #714)
+ * Fixed support for compilers on Debian FreeBSD (#380, #578)
+ * Added support for Visual Studio 2013 and proper support for the TDM builds (#482)
+ * Fixed CMake problems related to FindSFML and cached variables (#637, #684)
+ * Switched and enforced LF line endings (#708, #712)
+ * Updated OpenAL to version 1.15.1 (d077210)
+ * Made compiler and OS variable names much clearer in CMake files (9b0ed30)
+ * Re-enabled RPATH feature (e157e7a)
+ * Slight adjustments to the examples (#737)
+ * [FreeBSD] Various configuration fixes (#577, #578)
+ * [Linux] Updated FindSFML.cmake to add UDev to SFML's dependencies (#728, #729, #734, #736)
+ * [macOS] Fixed incorrect symlink in freetype.framework (#519)
+ * [macOS] CMake module for correct dependencies (#548)
+ * [macOS] Fixed SFML target for Xcode (#595, #596)
+ * [macOS] Updated implementation, mainly reverting to non-ARC (#601)
+ * [macOS] Fixed memory leaks and dead store (#615)
+ * [macOS] Improved event handling and performance (#617)
+ * [macOS] Reduced memory usage (#672, #698)
+ * [macOS] macOS 10.10 support (#691, #699)
+ * [macOS] Improve flexibility of dependencies' locations (#713)
+ * [Windows] Removed the hack that copied external libraries into SFML static libraries (dbf01a7)
+
+### System
+
+**Features**
+
+ * Added substring and replace functions to sf::String (#21, #355)
+ * Added toUtfX to sf::String (#501)
+ * Added fromUtfX functions to set the internal data to a string by converting from another string in a fixed encoding (#196)
+ * Added modulo operator for sf::Time (#429, #430)
+ * Added division operator for sf::Time (#453)
+
+**Bugfixes**
+
+ * Ensured a high resolution for sf::sleep (#439, #475)
+ * [Windows] Fixed stack unalignment by two internal functions (#412)
+
+### Window
+
+**Features**
+
+ * Added window methods to request and to check focus (#518, #525, #613, #723, #735)
+ * Provide name, manufacturer ID and product ID via sf::Joystick (#152, #528)
+ * [FreeBSD] Joystick support (#477)
+ * [macOS] Improved integration with menus and dock actions (#11)
+ * [macOS] Support for OpenGL 3.2 (#84)
+ * [macOS] Improved fullscreen support (#343)
+ * [macOS] Added support for retina displays (#353, #388)
+ * [Windows] Removed support for Windows 9x (#469)
+ * [Windows] Fixed typo in Windows keyboard implementation (#516)
+
+**Bugfixes**
+
+ * sf::Window::create() now also resets framerate limit (#371)
+ * Fixed OpenGL context leak (#635, #705)
+ * Fixed various joystick problems (memory leak, accelerometer detected, code refactoring) (#660, #686, #742, #743)
+ * Optimized sf::Window::waitEvent a bit, no sleep if events are available at first try (ff555d6)
+ * [Linux] Output error message when XOpenDisplay() fails (#508, #616)
+ * [Linux] Resize window with setSize when sf::Style::Resize is set (#466)
+ * [Linux] Fixed broken key repeat on window recreation (#564, #567)
+ * [macOS] Fixed KeyReleased not being fired in fullscreen mode (#465)
+ * [macOS] Fixed an issue where disconnecting the keyboard would cause a crash (#467)
+ * [macOS] Fixed unexpected resizing behavior (#468)
+ * [macOS] Improved resizing windows (#474)
+ * [macOS] Fixed memory leak with sf::Window::create() (#484)
+ * [macOS] Fixed menu shortcuts in fullscreen on macOS (#527)
+ * [macOS] Improved cursor hiding (#703)
+ * [macOS] Fixed right click not detected with trackpads (#716, #730)
+ * [Windows] Fixed joystick POV values (ef1d29b)
+ * [Windows] Fixed Unicode inconsistency (#635)
+ * [Windows] Fixed Alt+F4 and mouse clicks issues (#437, #457)
+ * [Windows] Send MouseButtonReleased event when the mouse is outside of the window (#455, #457)
+ * [Windows] Fixed sf::Joystick wrong registry usage (#701, #702, #706)
+
+### Graphics
+
+**Features**
+
+ * Provide more information about the loaded font in sf::Font (#164)
+ * Implemented a more flexible blending system (#298)
+ * Added strikethrough text style (#243, #362, #682)
+ * Slight optimization for sf::Text::setString (#413)
+ * Added subtraction operator for sf::Color (#114, #145)
+ * Optimized sf::Image::flipVertically/flipHorizontally (#555)
+ * Changed sf::Font measurements from int to float to allow better underline drawing (#693)
+
+**Bugfixes**
+
+ * Improved text quality for small and pixelated fonts (#228)
+ * Yet another fix for Intel GPUs with sf::RenderTexture (#418)
+ * Removed VTab since it causes issues and doesn't have a use nowadays (#442, #445, #460, #588)
+ * Fixed broken BDF and PCF font formats (#448)
+ * Fixed compilation issue with newer versions of GCC for sf::Rect (#458)
+ * Fixed resetGLStates() not explicitly setting the default polygon mode (#480)
+ * Fixed division-by-zero in sf::RectangleShape (#499)
+ * Fixed potential memory leak in sf::Font (#509)
+ * Updated glext and removed glxext (#511, #583)
+ * Make sure texture unit 0 is active when resetting sf::RenderTarget states (#523, #591)
+ * Fixed texture rect computation in fonts (#669)
+ * Improved rendering of underlined text (#593)
+ * Avoided repeated output of error messages (#566)
+ * Fixed text rendered with vertical offset on ascent and font size mismatch (#576)
+ * Fixed rounding problem for viewports (#598)
+ * Fixed sf::Shader::isAvailable() possibly breaking context management (#211, #603, #608, #603)
+ * Fixed sf::Texture::getMaximumSize() possibly breaking context management (#666)
+ * Fixed various sf::Text rendering issues (#692, #699)
+ * The texture matrix is now reset in sf::Texture::bind(NULL) (7c4b058)
+ * [Windows] Fixed DPI scaling causing strange window behavior (#679, #681, #688)
+
+### Audio
+
+**Features**
+
+ * Added support for selecting the audio capture device (#220, #470)
+ * Make sf::SoundRecorder processing frequency configurable (#333)
+ * Added up vector to sf::Listener (#545)
+
+**Bugfixes**
+
+ * Prevented sf::SoundStream::setPlayingOffset() from restarting playing even when paused (#203, #592)
+ * Fixed sf::SoundBuffer contents not being able to be updated when still attached to sounds (#354, 367, #390, #589)
+ * Catch audio format error and prevent division by zero (#529)
+ * Fixed sf::SoundBuffer returning wrong duration for sounds containing more than ~4.3 million samples (2ff58ed)
+ * Optimized sf::Listener with a cache (d97e524)
+
+### Network
+
+**Features**
+
+ * Added support for PUT and DELETE in sf::Http (#257, #312, #607)
+ * Added support for chunked HTTP transfers (#296, #337)
+ * Added support for 64-bit integers in sf::Packet (#710)
+ * Made sf::Ftp::sendCommand() public (2c5cab5)
+
+**Bugfixes**
+
+ * Checked socket descriptor limit (#153, #628, #683)
+ * Fixed sf::TcpSocket::connect()'s switching from blocking to non-blocking mode on immediate connection success (#221)
+ * Fixed FTP download and upload file sizes being limited by available RAM (#565, #590)
+ * Fixed C++11 compiler warnings for sf::Uint8 (#731, #732)
+
+## SFML 2.1
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.1
+
+### General
+
+ * Updated the Window and OpenGL examples (got rid of GLU and immediate mode)
+
+### Window
+
+**Features**
+
+ * Now using inotify on Linux to avoid constantly polling joystick connections (#96)
+ * Add keypad return, equal and period keys support for macOS
+ * Improved mouse events on macOS regarding fullscreen mode
+ * Improved mouse events on macOS (#213, #277)
+ * Improved reactivity of setMousePosition on macOS (#290)
+ * Added support for right control key on macOS
+ * Improved TextEntered for macOS (#377)
+ * Improved the performances of Window::getSize() (the size is now cached)
+ * Added the WM_CLASS property to SFML windows on Linux
+ * Fake resize events are no longer sent when the window is moved, on Linux
+ * Pressing ALT or F10 on Windows no longer steals the focus
+
+**Bugfixes**
+
+ * Fixed MouseMove event sometimes not generated when holding left button on Windows (#225)
+ * Fixed ContextSettings ignored when creating a 3.x/4.x OpenGL context on Linux (#258)
+ * Fixed ContextSettings ignored on Linux when creating a window (#35)
+ * Fixed windows bigger than the desktop not appearing on Windows (#215)
+ * Fixed KeyRelease events sometimes not reported on Linux (#404)
+ * Fixed mouse moved event on macOS when dragging the cursor (#277)
+ * Fixed KeyRelease event with CMD key pressed (#381)
+ * Fixed taskbar bugs on Windows (#328, #69)
+ * Fixed Window::getPosition() on Linux (#346)
+ * Unicode characters outside the BMP (> 0xFFFF) are now correctly handled on Windows (#366)
+
+### Graphics
+
+**Features**
+
+ * Checking errors in RenderTarget::pushGLStates() to avoid generating false error messages when user leaves unchecked OpenGL errors (#340)
+ * Optimized Shader::setParameter functions, by using a cache internally (#316, #358)
+
+**Bugfixes**
+
+ * Fixed bounding rect of sf::Text ignoring whitespaces (#216)
+ * Solved graphics resources not updated or corrupted when loaded in a thread (#411)
+ * Fixed white pixel showing on first character of sf::Text (#414)
+ * sf::Rect::contains and sf::Rect::intersects now handle rectangles with negative dimensions correctly (#219)
+ * Fixed Shape::setTextureRect not working when called before setTexture
+
+### Audio
+
+**Features**
+
+ * loadFromStream functions now explicitly reset the stream (seek(0)) before starting to read (#349)
+
+**Bugfixes**
+
+ * Added a workaround for a bug in the macOS implementation of OpenAL (unsupported channel count no properly detected) (#201)
+ * Fixed SoundBuffer::loadFromStream reading past the end of the stream (#214)
+
+### Network
+
+**Features**
+
+ * Replaced the deprecated gethostbyname with getaddrinfo (#47)
+ * Minor improvements to sf::Packet operators (now using strlen and wcslen instead of explicit loops) (#118)
+
+**Bugfixes**
+
+ * Fixed non-blocking connection with a sf::TcpSocket on Windows
+ * Fixed TCP packet data corruption in non-blocking mode (#402, #119)
+ * On Unix systems, a socket disconnection no longer stops the program with signal SIGPIPE (#72)
+
+## SFML 2.0
+
+Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.0
+
+No changelog available. *Everything changed.*
+
+## Older Releases
+
+See the website for changelogs of older releases: https://www.sfml-dev.org/changelog.php
diff --git a/cmake/Config.cmake b/cmake/Config.cmake
new file mode 100644
index 0000000..0a28660
--- /dev/null
+++ b/cmake/Config.cmake
@@ -0,0 +1,118 @@
+# detect the OS
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+ set(SFML_OS_WINDOWS 1)
+
+ # don't use the OpenGL ES implementation on Windows
+ set(OPENGL_ES 0)
+
+ # detect the architecture (note: this test won't work for cross-compilation)
+ include(CheckTypeSize)
+ check_type_size(void* SIZEOF_VOID_PTR)
+ if(${SIZEOF_VOID_PTR} STREQUAL "4")
+ set(ARCH_32BITS 1)
+ elseif(${SIZEOF_VOID_PTR} STREQUAL "8")
+ set(ARCH_64BITS 1)
+ else()
+ message(FATAL_ERROR "Unsupported architecture")
+ return()
+ endif()
+elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ set(SFML_OS_UNIX 1)
+ if(ANDROID)
+ set(SFML_OS_ANDROID 1)
+ # use the OpenGL ES implementation on Android
+ set(OPENGL_ES 1)
+ else()
+ set(SFML_OS_LINUX 1)
+ # don't use the OpenGL ES implementation on Linux
+ set(OPENGL_ES 0)
+ endif()
+elseif(CMAKE_SYSTEM_NAME MATCHES "^k?FreeBSD$")
+ set(SFML_OS_FREEBSD 1)
+ # don't use the OpenGL ES implementation on FreeBSD
+ set(OPENGL_ES 0)
+elseif(CMAKE_SYSTEM_NAME MATCHES "^OpenBSD$")
+ set(SFML_OS_OPENBSD 1)
+ # don't use the OpenGL ES implementation on OpenBSD
+ set(OPENGL_ES 0)
+elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+ if(IOS)
+ set(SFML_OS_IOS 1)
+
+ # use the OpenGL ES implementation on iOS
+ set(OPENGL_ES 1)
+ else()
+ set(SFML_OS_MACOSX 1)
+
+ # don't use the OpenGL ES implementation on Mac OS X
+ set(OPENGL_ES 0)
+
+ # detect OS X version. (use '/usr/bin/sw_vers -productVersion' to extract V from '10.V.x'.)
+ EXEC_PROGRAM(/usr/bin/sw_vers ARGS -productVersion OUTPUT_VARIABLE MACOSX_VERSION_RAW)
+ STRING(REGEX REPLACE "10\\.([0-9]+).*" "\\1" MACOSX_VERSION "${MACOSX_VERSION_RAW}")
+ if(${MACOSX_VERSION} LESS 7)
+ message(FATAL_ERROR "Unsupported version of OS X: ${MACOSX_VERSION_RAW}")
+ return()
+ endif()
+ endif()
+elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ set(SFML_OS_ANDROID 1)
+
+ # use the OpenGL ES implementation on Android
+ set(OPENGL_ES 1)
+# comparing CMAKE_SYSTEM_NAME with "CYGWIN" generates a false warning depending on the CMake version
+# let's avoid it so the actual error is more visible
+elseif(${CYGWIN})
+ message(FATAL_ERROR "Unfortunately SFML doesn't support Cygwin's 'hybrid' status between both Windows and Linux derivatives.\nIf you insist on using the GCC, please use a standalone build of MinGW without the Cygwin environment instead.")
+else()
+ message(FATAL_ERROR "Unsupported operating system or environment")
+ return()
+endif()
+
+# set pkgconfig install directory
+# this could be e.g. macports on mac or msys2 on windows etc.
+set(SFML_PKGCONFIG_DIR "/lib${LIB_SUFFIX}/pkgconfig")
+
+if(SFML_OS_FREEBSD OR SFML_OS_OPENBSD)
+ set(SFML_PKGCONFIG_DIR "/libdata/pkgconfig")
+endif()
+
+# detect the compiler and its version
+# Note: on some platforms (OS X), CMAKE_COMPILER_IS_GNUCXX is true
+# even when CLANG is used, therefore the Clang test is done first
+if(CMAKE_CXX_COMPILER MATCHES "clang[+][+]" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ # CMAKE_CXX_COMPILER_ID is an internal CMake variable subject to change,
+ # but there is no other way to detect CLang at the moment
+ set(SFML_COMPILER_CLANG 1)
+ execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "--version" OUTPUT_VARIABLE CLANG_VERSION_OUTPUT)
+ string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" SFML_CLANG_VERSION "${CLANG_VERSION_OUTPUT}")
+elseif(CMAKE_COMPILER_IS_GNUCXX)
+ set(SFML_COMPILER_GCC 1)
+ execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-dumpversion" OUTPUT_VARIABLE GCC_VERSION_OUTPUT)
+ string(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" SFML_GCC_VERSION "${GCC_VERSION_OUTPUT}")
+ execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "--version" OUTPUT_VARIABLE GCC_COMPILER_VERSION)
+ string(REGEX MATCHALL ".*(tdm[64]*-[1-9]).*" SFML_COMPILER_GCC_TDM "${GCC_COMPILER_VERSION}")
+ execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-dumpmachine" OUTPUT_VARIABLE GCC_MACHINE)
+ string(STRIP "${GCC_MACHINE}" GCC_MACHINE)
+ if(GCC_MACHINE MATCHES ".*w64.*")
+ set(SFML_COMPILER_GCC_W64 1)
+ endif()
+elseif(MSVC)
+ set(SFML_COMPILER_MSVC 1)
+ if(MSVC_VERSION EQUAL 1400)
+ set(SFML_MSVC_VERSION 8)
+ elseif(MSVC_VERSION EQUAL 1500)
+ set(SFML_MSVC_VERSION 9)
+ elseif(MSVC_VERSION EQUAL 1600)
+ set(SFML_MSVC_VERSION 10)
+ elseif(MSVC_VERSION EQUAL 1700)
+ set(SFML_MSVC_VERSION 11)
+ elseif(MSVC_VERSION EQUAL 1800)
+ set(SFML_MSVC_VERSION 12)
+ elseif(MSVC_VERSION EQUAL 1900)
+ set(SFML_MSVC_VERSION 14)
+ endif()
+else()
+ message(FATAL_ERROR "Unsupported compiler")
+ return()
+endif()
diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake
new file mode 100644
index 0000000..ecb37c8
--- /dev/null
+++ b/cmake/Macros.cmake
@@ -0,0 +1,346 @@
+include(CMakeParseArguments)
+
+# This little macro lets you set any Xcode specific property
+macro (sfml_set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
+ set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
+endmacro ()
+
+# set the appropriate standard library on each platform for the given target
+# example: sfml_set_stdlib(sfml-system)
+function(sfml_set_stdlib target)
+ # for gcc >= 4.0 on Windows, apply the SFML_USE_STATIC_STD_LIBS option if it is enabled
+ if(SFML_OS_WINDOWS AND SFML_COMPILER_GCC AND NOT SFML_GCC_VERSION VERSION_LESS "4")
+ if(SFML_USE_STATIC_STD_LIBS AND NOT SFML_COMPILER_GCC_TDM)
+ target_link_libraries(${target} PRIVATE "-static-libgcc" "-static-libstdc++")
+ elseif(NOT SFML_USE_STATIC_STD_LIBS AND SFML_COMPILER_GCC_TDM)
+ target_link_libraries(${target} PRIVATE "-shared-libgcc" "-shared-libstdc++")
+ endif()
+ endif()
+
+ if (SFML_OS_MACOSX)
+ if (${CMAKE_GENERATOR} MATCHES "Xcode")
+ sfml_set_xcode_property(${target} CLANG_CXX_LIBRARY "libc++")
+ else()
+ target_compile_options(${target} PRIVATE "-stdlib=libc++")
+ target_link_libraries(${target} PRIVATE "-stdlib=libc++")
+ endif()
+ endif()
+endfunction()
+
+# add a new target which is a SFML library
+# example: sfml_add_library(sfml-graphics
+# SOURCES sprite.cpp image.cpp ...
+# [STATIC]) # Always create a static library and ignore BUILD_SHARED_LIBS
+macro(sfml_add_library target)
+
+ # parse the arguments
+ cmake_parse_arguments(THIS "STATIC" "" "SOURCES" ${ARGN})
+ if (NOT "${THIS_UNPARSED_ARGUMENTS}" STREQUAL "")
+ message(FATAL_ERROR "Extra unparsed arguments when calling sfml_add_library: ${THIS_UNPARSED_ARGUMENTS}")
+ endif()
+
+ # create the target
+ if (THIS_STATIC)
+ add_library(${target} STATIC ${THIS_SOURCES})
+ else()
+ add_library(${target} ${THIS_SOURCES})
+ endif()
+
+ # define the export symbol of the module
+ string(REPLACE "-" "_" NAME_UPPER "${target}")
+ string(TOUPPER "${NAME_UPPER}" NAME_UPPER)
+ set_target_properties(${target} PROPERTIES DEFINE_SYMBOL ${NAME_UPPER}_EXPORTS)
+
+ # adjust the output file prefix/suffix to match our conventions
+ if(BUILD_SHARED_LIBS AND NOT THIS_STATIC)
+ if(SFML_OS_WINDOWS)
+ # include the major version number in Windows shared library names (but not import library names)
+ set_target_properties(${target} PROPERTIES DEBUG_POSTFIX -d)
+ set_target_properties(${target} PROPERTIES SUFFIX "-${VERSION_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else()
+ set_target_properties(${target} PROPERTIES DEBUG_POSTFIX -d)
+ endif()
+ if (SFML_OS_WINDOWS AND SFML_COMPILER_GCC)
+ # on Windows/gcc get rid of "lib" prefix for shared libraries,
+ # and transform the ".dll.a" suffix into ".a" for import libraries
+ set_target_properties(${target} PROPERTIES PREFIX "")
+ set_target_properties(${target} PROPERTIES IMPORT_SUFFIX ".a")
+ endif()
+ else()
+ set_target_properties(${target} PROPERTIES DEBUG_POSTFIX -s-d)
+ set_target_properties(${target} PROPERTIES RELEASE_POSTFIX -s)
+ set_target_properties(${target} PROPERTIES MINSIZEREL_POSTFIX -s)
+ set_target_properties(${target} PROPERTIES RELWITHDEBINFO_POSTFIX -s)
+ endif()
+
+ # set the version and soversion of the target (for compatible systems -- mostly Linuxes)
+ # except for Android which strips soversion suffixes
+ if(NOT SFML_OS_ANDROID)
+ set_target_properties(${target} PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR})
+ set_target_properties(${target} PROPERTIES VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
+ endif()
+
+ # set the target's folder (for IDEs that support it, e.g. Visual Studio)
+ set_target_properties(${target} PROPERTIES FOLDER "SFML")
+
+ # set the target flags to use the appropriate C++ standard library
+ sfml_set_stdlib(${target})
+
+ # For Visual Studio on Windows, export debug symbols (PDB files) to lib directory
+ if(SFML_GENERATE_PDB)
+ # PDB files are only generated in Debug and RelWithDebInfo configurations, find out which one
+ if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+ set(SFML_PDB_POSTFIX "-d")
+ else()
+ set(SFML_PDB_POSTFIX "")
+ endif()
+
+ if(BUILD_SHARED_LIBS AND NOT THIS_STATIC)
+ # DLLs export debug symbols in the linker PDB (the compiler PDB is an intermediate file)
+ set_target_properties(${target} PROPERTIES
+ PDB_NAME "${target}${SFML_PDB_POSTFIX}"
+ PDB_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
+ else()
+ # Static libraries have no linker PDBs, thus the compiler PDBs are relevant
+ set_target_properties(${target} PROPERTIES
+ COMPILE_PDB_NAME "${target}-s${SFML_PDB_POSTFIX}"
+ COMPILE_PDB_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
+ endif()
+ endif()
+
+ # if using gcc >= 4.0 or clang >= 3.0 on a non-Windows platform, we must hide public symbols by default
+ # (exported ones are explicitly marked)
+ if(NOT SFML_OS_WINDOWS AND ((SFML_COMPILER_GCC AND NOT SFML_GCC_VERSION VERSION_LESS "4") OR (SFML_COMPILER_CLANG AND NOT SFML_CLANG_VERSION VERSION_LESS "3")))
+ set_target_properties(${target} PROPERTIES COMPILE_FLAGS -fvisibility=hidden)
+ endif()
+
+ # build frameworks or dylibs
+ if(SFML_OS_MACOSX AND BUILD_SHARED_LIBS AND NOT THIS_STATIC)
+ if(SFML_BUILD_FRAMEWORKS)
+ # adapt target to build frameworks instead of dylibs
+ set_target_properties(${target} PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ MACOSX_FRAMEWORK_IDENTIFIER org.sfml-dev.${target}
+ MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ MACOSX_FRAMEWORK_BUNDLE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
+ endif()
+
+ # adapt install directory to allow distributing dylibs/frameworks in user's frameworks/application bundle
+ # but only if cmake rpath options aren't set
+ if(NOT CMAKE_SKIP_RPATH AND NOT CMAKE_SKIP_INSTALL_RPATH AND NOT CMAKE_INSTALL_RPATH AND NOT CMAKE_INSTALL_RPATH_USE_LINK_PATH AND NOT CMAKE_INSTALL_NAME_DIR)
+ set_target_properties(${target} PROPERTIES INSTALL_NAME_DIR "@rpath")
+ if(NOT CMAKE_SKIP_BUILD_RPATH)
+ if (CMAKE_VERSION VERSION_LESS 3.9)
+ set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+ else()
+ set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_NAME_DIR TRUE)
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # enable automatic reference counting on iOS
+ if (SFML_OS_IOS)
+ set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES)
+ endif()
+
+ # sfml-activity library is our bootstrap activity and must not depend on stlport_shared
+ # (otherwise Android will fail to load it)
+ if (SFML_OS_ANDROID)
+ if (${target} MATCHES "sfml-activity")
+ set_target_properties(${target} PROPERTIES COMPILE_FLAGS -fpermissive)
+ set_target_properties(${target} PROPERTIES LINK_FLAGS "-landroid -llog")
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY ${CMAKE_CXX_CREATE_SHARED_LIBRARY_WITHOUT_STL})
+ else()
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY ${CMAKE_CXX_CREATE_SHARED_LIBRARY_WITH_STL})
+ endif()
+ endif()
+
+ # add the install rule
+ install(TARGETS ${target} EXPORT SFMLConfigExport
+ RUNTIME DESTINATION bin COMPONENT bin
+ LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT bin
+ ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT devel
+ FRAMEWORK DESTINATION "." COMPONENT bin)
+
+ # add <project>/include as public include directory
+ target_include_directories(${target}
+ PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
+ PRIVATE ${PROJECT_SOURCE_DIR}/src)
+
+ if (SFML_BUILD_FRAMEWORKS)
+ target_include_directories(${target} INTERFACE $<INSTALL_INTERFACE:SFML.framework>)
+ else()
+ target_include_directories(${target} INTERFACE $<INSTALL_INTERFACE:include>)
+ endif()
+
+ # define SFML_STATIC if the build type is not set to 'shared'
+ if(NOT BUILD_SHARED_LIBS)
+ target_compile_definitions(${target} PUBLIC "SFML_STATIC")
+ endif()
+
+endmacro()
+
+# add a new target which is a SFML example
+# example: sfml_add_example(ftp
+# SOURCES ftp.cpp ...
+# BUNDLE_RESOURCES MainMenu.nib ... # Files to be added in target but not installed next to the executable
+# DEPENDS sfml-network
+# RESOURCES_DIR resources) # A directory to install next to the executable and sources
+macro(sfml_add_example target)
+
+ # parse the arguments
+ cmake_parse_arguments(THIS "GUI_APP" "RESOURCES_DIR" "SOURCES;BUNDLE_RESOURCES;DEPENDS" ${ARGN})
+
+ # set a source group for the source files
+ source_group("" FILES ${THIS_SOURCES})
+
+ # check whether resources must be added in target
+ set(target_input ${THIS_SOURCES})
+ if(THIS_BUNDLE_RESOURCES)
+ set(target_input ${target_input} ${THIS_BUNDLE_RESOURCES})
+ endif()
+
+ # create the target
+ if(THIS_GUI_APP AND SFML_OS_WINDOWS AND NOT DEFINED CMAKE_CONFIGURATION_TYPES AND ${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ add_executable(${target} WIN32 ${target_input})
+ target_link_libraries(${target} PRIVATE sfml-main)
+ elseif(THIS_GUI_APP AND SFML_OS_IOS)
+ add_executable(${target} MACOSX_BUNDLE ${target_input})
+ target_link_libraries(${target} PRIVATE sfml-main)
+ else()
+ add_executable(${target} ${target_input})
+ endif()
+
+ # set the debug suffix
+ set_target_properties(${target} PROPERTIES DEBUG_POSTFIX -d)
+
+ # set the target's folder (for IDEs that support it, e.g. Visual Studio)
+ set_target_properties(${target} PROPERTIES FOLDER "Examples")
+
+ # set the target flags to use the appropriate C++ standard library
+ sfml_set_stdlib(${target})
+
+ # set the Visual Studio startup path for debugging
+ set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+ # link the target to its SFML dependencies
+ if(THIS_DEPENDS)
+ target_link_libraries(${target} PRIVATE ${THIS_DEPENDS})
+ endif()
+
+ # add the install rule
+ install(TARGETS ${target}
+ RUNTIME DESTINATION ${SFML_MISC_INSTALL_PREFIX}/examples/${target} COMPONENT examples
+ BUNDLE DESTINATION ${SFML_MISC_INSTALL_PREFIX}/examples/${target} COMPONENT examples)
+
+ # install the example's source code
+ install(FILES ${THIS_SOURCES}
+ DESTINATION ${SFML_MISC_INSTALL_PREFIX}/examples/${target}
+ COMPONENT examples)
+
+ if (THIS_RESOURCES_DIR)
+ # install the example's resources as well
+ get_filename_component(THIS_RESOURCES_DIR "${THIS_RESOURCES_DIR}" ABSOLUTE)
+
+ if(NOT EXISTS "${THIS_RESOURCES_DIR}")
+ message(FATAL_ERROR "Given resources directory to install does not exist: ${THIS_RESOURCES_DIR}")
+ endif()
+ install(DIRECTORY ${THIS_RESOURCES_DIR}
+ DESTINATION ${SFML_MISC_INSTALL_PREFIX}/examples/${target}
+ COMPONENT examples)
+ endif()
+
+endmacro()
+
+
+# Find the requested package and make an INTERFACE library from it
+# Usage: sfml_find_package(wanted_target_name
+# [INCLUDE "OPENGL_INCLUDE_DIR"]
+# [LINK "OPENGL_gl_LIBRARY"])
+function(sfml_find_package)
+ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/")
+ list(GET ARGN 0 target)
+ list(REMOVE_AT ARGN 0)
+
+ if (TARGET ${target})
+ message(FATAL_ERROR "Target '${target}' is already defined")
+ endif()
+
+ cmake_parse_arguments(THIS "" "" "INCLUDE;LINK" ${ARGN})
+ if (THIS_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown arguments when calling sfml_import_library: ${THIS_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if (SFML_OS_IOS)
+ find_host_package(${target} REQUIRED)
+ else()
+ find_package(${target} REQUIRED)
+ endif()
+
+ add_library(${target} INTERFACE)
+
+ if (THIS_INCLUDE)
+ foreach(include_dir IN LISTS "${THIS_INCLUDE}")
+ if (NOT include_dir)
+ message(FATAL_ERROR "No path given for include dir ${THIS_INCLUDE}")
+ endif()
+ target_include_directories(${target} INTERFACE "$<BUILD_INTERFACE:${include_dir}>")
+ endforeach()
+ endif()
+
+ if (THIS_LINK)
+ foreach(link_item IN LISTS ${THIS_LINK})
+ if (NOT link_item)
+ message(FATAL_ERROR "Missing item in ${THIS_LINK}")
+ endif()
+ target_link_libraries(${target} INTERFACE "$<BUILD_INTERFACE:${link_item}>")
+ endforeach()
+ endif()
+ install(TARGETS ${target} EXPORT SFMLConfigExport)
+endfunction()
+
+# Generate a SFMLConfig.cmake file (and associated files) from the targets registered against
+# the EXPORT name "SFMLConfigExport" (EXPORT parameter of install(TARGETS))
+function(sfml_export_targets)
+ # CMAKE_CURRENT_LIST_DIR or CMAKE_CURRENT_SOURCE_DIR not usable for files that are to be included like this one
+ set(CURRENT_DIR "${PROJECT_SOURCE_DIR}/cmake")
+
+ include(CMakePackageConfigHelpers)
+ write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigVersion.cmake"
+ VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
+ COMPATIBILITY SameMajorVersion)
+
+ if (BUILD_SHARED_LIBS)
+ set(config_name "Shared")
+ else()
+ set(config_name "Static")
+ endif()
+ set(targets_config_filename "SFML${config_name}Targets.cmake")
+
+ export(EXPORT SFMLConfigExport
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/${targets_config_filename}")
+
+ if (SFML_BUILD_FRAMEWORKS)
+ set(config_package_location "SFML.framework/Resources/CMake")
+ else()
+ set(config_package_location lib${LIB_SUFFIX}/cmake/SFML)
+ endif()
+ configure_package_config_file("${CURRENT_DIR}/SFMLConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfig.cmake"
+ INSTALL_DESTINATION "${config_package_location}")
+ configure_package_config_file("${CURRENT_DIR}/SFMLConfigDependencies.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigDependencies.cmake"
+ INSTALL_DESTINATION "${config_package_location}")
+
+
+ install(EXPORT SFMLConfigExport
+ FILE ${targets_config_filename}
+ DESTINATION ${config_package_location})
+
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigDependencies.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfigVersion.cmake"
+ DESTINATION ${config_package_location}
+ COMPONENT devel)
+endfunction()
+
diff --git a/cmake/Modules/FindEGL.cmake b/cmake/Modules/FindEGL.cmake
new file mode 100644
index 0000000..cde632a
--- /dev/null
+++ b/cmake/Modules/FindEGL.cmake
@@ -0,0 +1,14 @@
+#
+# Try to find EGL library and include path.
+# Once done this will define
+#
+# EGL_FOUND
+# EGL_INCLUDE_PATH
+# EGL_LIBRARY
+#
+
+find_path(EGL_INCLUDE_DIR EGL/egl.h)
+find_library(EGL_LIBRARY NAMES EGL)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR)
diff --git a/cmake/Modules/FindFLAC.cmake b/cmake/Modules/FindFLAC.cmake
new file mode 100644
index 0000000..e820cf9
--- /dev/null
+++ b/cmake/Modules/FindFLAC.cmake
@@ -0,0 +1,18 @@
+#
+# Try to find FLAC libraries and include paths.
+# Once done this will define
+#
+# FLAC_FOUND
+# FLAC_INCLUDE_DIR
+# FLAC_LIBRARY
+#
+
+find_path(FLAC_INCLUDE_DIR FLAC/all.h)
+find_path(FLAC_INCLUDE_DIR FLAC/stream_decoder.h)
+
+find_library(FLAC_LIBRARY NAMES FLAC)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FLAC DEFAULT_MSG FLAC_LIBRARY FLAC_INCLUDE_DIR)
+
+mark_as_advanced(FLAC_INCLUDE_DIR FLAC_LIBRARY)
diff --git a/cmake/Modules/FindFreetype.cmake b/cmake/Modules/FindFreetype.cmake
new file mode 100644
index 0000000..6e3f3f7
--- /dev/null
+++ b/cmake/Modules/FindFreetype.cmake
@@ -0,0 +1,158 @@
+#.rst:
+# FindFreetype
+# ------------
+#
+# Locate FreeType library
+#
+# This module defines
+#
+# ::
+#
+# FREETYPE_LIBRARIES, the library to link against
+# FREETYPE_FOUND, if false, do not try to link to FREETYPE
+# FREETYPE_INCLUDE_DIRS, where to find headers.
+# FREETYPE_VERSION_STRING, the version of freetype found (since CMake 2.8.8)
+# This is the concatenation of the paths:
+# FREETYPE_INCLUDE_DIR_ft2build
+# FREETYPE_INCLUDE_DIR_freetype2
+#
+#
+#
+# $FREETYPE_DIR is an environment variable that would correspond to the
+# ./configure --prefix=$FREETYPE_DIR used in building FREETYPE.
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Created by Eric Wing.
+# Modifications by Alexander Neundorf.
+# This file has been renamed to "FindFreetype.cmake" instead of the correct
+# "FindFreeType.cmake" in order to be compatible with the one from KDE4, Alex.
+
+# Ugh, FreeType seems to use some #include trickery which
+# makes this harder than it should be. It looks like they
+# put ft2build.h in a common/easier-to-find location which
+# then contains a #include to a more specific header in a
+# more specific location (#include <freetype/config/ftheader.h>).
+# Then from there, they need to set a bunch of #define's
+# so you can do something like:
+# #include FT_FREETYPE_H
+# Unfortunately, using CMake's mechanisms like include_directories()
+# wants explicit full paths and this trickery doesn't work too well.
+# I'm going to attempt to cut out the middleman and hope
+# everything still works.
+find_path(
+ FREETYPE_INCLUDE_DIR_ft2build
+ ft2build.h
+ HINTS
+ ENV FREETYPE_DIR
+ PATHS
+ /usr/X11R6
+ /usr/local/X11R6
+ /usr/local/X11
+ /usr/freeware
+ ENV GTKMM_BASEPATH
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]
+ PATH_SUFFIXES
+ include/freetype2
+ include
+ freetype2
+)
+
+find_path(
+ FREETYPE_INCLUDE_DIR_freetype2
+ NAMES
+ freetype/config/ftheader.h
+ config/ftheader.h
+ HINTS
+ ENV FREETYPE_DIR
+ PATHS
+ /usr/X11R6
+ /usr/local/X11R6
+ /usr/local/X11
+ /usr/freeware
+ ENV GTKMM_BASEPATH
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]
+ PATH_SUFFIXES
+ include/freetype2
+ include
+ freetype2
+)
+
+find_library(FREETYPE_LIBRARY
+ NAMES
+ freetype
+ libfreetype
+ freetype219
+ HINTS
+ ENV FREETYPE_DIR
+ PATHS
+ /usr/X11R6
+ /usr/local/X11R6
+ /usr/local/X11
+ /usr/freeware
+ ENV GTKMM_BASEPATH
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]
+ PATH_SUFFIXES
+ lib
+)
+
+# set the user variables
+if(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2)
+ set(FREETYPE_INCLUDE_DIRS "${FREETYPE_INCLUDE_DIR_ft2build};${FREETYPE_INCLUDE_DIR_freetype2}")
+ list(REMOVE_DUPLICATES FREETYPE_INCLUDE_DIRS)
+endif()
+set(FREETYPE_LIBRARIES "${FREETYPE_LIBRARY}")
+
+if(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h")
+ set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h")
+elseif(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h")
+ set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h")
+endif()
+
+if(FREETYPE_INCLUDE_DIR_freetype2 AND FREETYPE_H)
+ file(STRINGS "${FREETYPE_H}" freetype_version_str
+ REGEX "^#[\t ]*define[\t ]+FREETYPE_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
+
+ unset(FREETYPE_VERSION_STRING)
+ foreach(VPART MAJOR MINOR PATCH)
+ foreach(VLINE ${freetype_version_str})
+ if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$")
+ set(FREETYPE_VERSION_PART "${CMAKE_MATCH_1}")
+ if(FREETYPE_VERSION_STRING)
+ set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_STRING}.${FREETYPE_VERSION_PART}")
+ else()
+ set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_PART}")
+ endif()
+ unset(FREETYPE_VERSION_PART)
+ endif()
+ endforeach()
+ endforeach()
+endif()
+
+
+# set FREETYPE_FOUND to TRUE if all listed variables are TRUE
+if(FREETYPE_LIBRARY AND FREETYPE_INCLUDE_DIRS AND FREETYPE_VERSION_STRING)
+ set(FREETYPE_FOUND TRUE)
+else()
+ set(FREETYPE_FOUND FALSE)
+endif()
+
+mark_as_advanced(
+ FREETYPE_LIBRARY
+ FREETYPE_INCLUDE_DIR_freetype2
+ FREETYPE_INCLUDE_DIR_ft2build
+)
diff --git a/cmake/Modules/FindGLES.cmake b/cmake/Modules/FindGLES.cmake
new file mode 100644
index 0000000..f34f2cd
--- /dev/null
+++ b/cmake/Modules/FindGLES.cmake
@@ -0,0 +1,14 @@
+#
+# Try to find GLES library and include path.
+# Once done this will define
+#
+# GLES_FOUND
+# GLES_INCLUDE_PATH
+# GLES_LIBRARY
+#
+
+find_path(GLES_INCLUDE_DIR GLES/gl.h)
+find_library(GLES_LIBRARY NAMES GLESv1_CM)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GLES DEFAULT_MSG GLES_LIBRARY GLES_INCLUDE_DIR)
diff --git a/cmake/Modules/FindUDev.cmake b/cmake/Modules/FindUDev.cmake
new file mode 100644
index 0000000..467bd69
--- /dev/null
+++ b/cmake/Modules/FindUDev.cmake
@@ -0,0 +1,53 @@
+# Configure libudev environment
+#
+# UDEV_FOUND - system has a libudev
+# UDEV_INCLUDE_DIR - where to find header files
+# UDEV_LIBRARIES - the libraries to link against udev
+# UDEV_STABLE - it's true when is the version greater or equals to 143 - version when the libudev was stabilized in its API
+#
+# copyright (c) 2011 Petr Vanek <petr@scribus.info>
+# Redistribution and use of this file is allowed according to the terms of the BSD license.
+#
+
+FIND_PATH(
+ UDEV_INCLUDE_DIR
+ libudev.h
+ /usr/include
+ /usr/local/include
+ ${UDEV_PATH_INCLUDES}
+)
+
+FIND_LIBRARY(
+ UDEV_LIBRARIES
+ NAMES udev libudev
+ PATHS ${ADDITIONAL_LIBRARY_PATHS}
+ ${UDEV_PATH_LIB}
+)
+
+IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR)
+ SET(UDEV_FOUND "YES")
+ execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE)
+ # retvale is 0 of the condition is "true" so we need to negate the value...
+ if (UDEV_STABLE)
+ set(UDEV_STABLE 0)
+ else (UDEV_STABLE)
+ set(UDEV_STABLE 1)
+ endif (UDEV_STABLE)
+ message(STATUS "libudev stable: ${UDEV_STABLE}")
+ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR)
+
+IF (UDEV_FOUND)
+ MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}")
+ MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}")
+ELSE (UDEV_FOUND)
+ MESSAGE(STATUS "UDev not found.")
+ MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include")
+ MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}")
+ MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib")
+ MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}")
+ IF (UDev_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find UDev library")
+ ENDIF (UDev_FIND_REQUIRED)
+ENDIF (UDEV_FOUND)
+
+mark_as_advanced(UDEV_INCLUDE_DIR UDEV_LIBRARIES)
diff --git a/cmake/Modules/FindVorbis.cmake b/cmake/Modules/FindVorbis.cmake
new file mode 100644
index 0000000..e285411
--- /dev/null
+++ b/cmake/Modules/FindVorbis.cmake
@@ -0,0 +1,29 @@
+#
+# Try to find Ogg/Vorbis libraries and include paths.
+# Once done this will define
+#
+# VORBIS_FOUND
+# VORBIS_INCLUDE_DIRS
+# VORBIS_LIBRARIES
+#
+
+find_path(OGG_INCLUDE_DIR ogg/ogg.h)
+find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h)
+
+find_library(OGG_LIBRARY NAMES ogg)
+find_library(VORBIS_LIBRARY NAMES vorbis)
+if (NOT SFML_OS_IOS)
+ find_library(VORBISFILE_LIBRARY NAMES vorbisfile)
+ find_library(VORBISENC_LIBRARY NAMES vorbisenc)
+ set(VORBIS_LIBRARIES ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
+else()
+ set(VORBIS_LIBRARIES ${VORBIS_LIBRARY} ${OGG_LIBRARY})
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(VORBIS DEFAULT_MSG VORBIS_LIBRARIES VORBIS_INCLUDE_DIR OGG_INCLUDE_DIR)
+
+set(VORBIS_INCLUDE_DIRS ${OGG_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR})
+
+mark_as_advanced(OGG_INCLUDE_DIR VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY VORBISENC_LIBRARY)
diff --git a/cmake/SFMLConfig.cmake.in b/cmake/SFMLConfig.cmake.in
new file mode 100644
index 0000000..ce81953
--- /dev/null
+++ b/cmake/SFMLConfig.cmake.in
@@ -0,0 +1,148 @@
+# This script provides the SFML libraries as imported targets
+# ------------------------------------
+#
+# Usage
+# -----
+#
+# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main).
+# If none is given, no imported target will be created and you won't be able to link to SFML libraries.
+# example:
+# find_package(SFML COMPONENTS graphics window system) # find the graphics, window and system modules
+#
+# You can enforce a specific version, either MAJOR.MINOR or only MAJOR.
+# If nothing is specified, the version won't be checked (i.e. any version will be accepted).
+# example:
+# find_package(SFML COMPONENTS ...) # no specific version required
+# find_package(SFML 2 COMPONENTS ...) # any 2.x version
+# find_package(SFML 2.4 COMPONENTS ...) # version 2.4 or greater
+#
+# By default, the dynamic libraries of SFML will be found. To find the static ones instead,
+# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).
+# You don't need to deal with SFML's dependencies when linking your targets against SFML libraries,
+# they will all be configured automatically, even if you use SFML static libraries.
+# example:
+# set(SFML_STATIC_LIBRARIES TRUE)
+# find_package(SFML 2 COMPONENTS network system)
+#
+# On macOS by default CMake will search for frameworks. If you want to use static libraries and have installed
+# both SFML frameworks and SFML static libraries, your must set CMAKE_FIND_FRAMEWORK to "NEVER" or "LAST"
+# in addition to setting SFML_STATIC_LIBRARIES to TRUE. Otherwise CMake will check the frameworks bundle config and
+# fail after finding out that it does not provide static libraries. Please refer to CMake documentation for more details.
+#
+# Additionally, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which
+# are available for both release and debug modes.
+#
+# If SFML is not installed in a standard path, you can use the SFML_DIR CMake variable
+# to tell CMake where SFML's config file is located (PREFIX/lib/cmake/SFML for a library-based installation,
+# and PREFIX/SFML.framework/Resources/CMake on macOS for a framework-based installation).
+#
+# Output
+# ------
+#
+# This script defines the following variables:
+# - For each specified module XXX (system, window, graphics, network, audio, main):
+# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found
+# - SFML_FOUND: true if all the required modules are found
+#
+# And the following targets:
+# - For each specified module XXX (system, window, graphics, network, audio, main):
+# - sfml-XXX
+# The SFML targets are the same for both Debug and Release build configurations and will automatically provide
+# correct settings based on your currently active build configuration. The SFML targets name also do not change
+# when using dynamic or static SFML libraries.
+#
+# When linking against a SFML target, you do not need to specify indirect dependencies. For example, linking
+# against sfml-graphics will also automatically link against sfml-window and sfml-system.
+#
+# example:
+# find_package(SFML 2 COMPONENTS graphics audio REQUIRED)
+# add_executable(myapp ...)
+# target_link_libraries(myapp sfml-graphics sfml-audio)
+
+if (NOT SFML_FIND_COMPONENTS)
+ message(FATAL_ERROR "find_package(SFML) called with no component")
+endif()
+
+set(FIND_SFML_PATHS
+ "${CMAKE_CURRENT_LIST_DIR}/../.."
+ ${SFML_ROOT}
+ $ENV{SFML_ROOT}
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw
+ /opt/local
+ /opt/csw
+ /opt)
+
+find_path(SFML_DOC_DIR SFML.tag
+ PATH_SUFFIXES SFML/doc share/SFML/doc
+ PATHS ${FIND_SFML_PATHS})
+
+
+# Update requested components (eg. request window component if graphics component was requested)
+set(FIND_SFML_SYSTEM_DEPENDENCIES "")
+set(FIND_SFML_MAIN_DEPENDENCIES "")
+set(FIND_SFML_AUDIO_DEPENDENCIES system)
+set(FIND_SFML_NETWORK_DEPENDENCIES system)
+set(FIND_SFML_WINDOW_DEPENDENCIES system)
+set(FIND_SFML_GRAPHICS_DEPENDENCIES window system)
+set(FIND_SFML_ADDITIONAL_COMPONENTS "")
+foreach(component ${SFML_FIND_COMPONENTS})
+ string(TOUPPER "${component}" UPPER_COMPONENT)
+ list(APPEND FIND_SFML_ADDITIONAL_COMPONENTS ${FIND_SFML_${UPPER_COMPONENT}_DEPENDENCIES})
+endforeach()
+list(APPEND SFML_FIND_COMPONENTS ${FIND_SFML_ADDITIONAL_COMPONENTS})
+list(REMOVE_DUPLICATES SFML_FIND_COMPONENTS)
+
+# Choose which target definitions must be imported
+if (SFML_STATIC_LIBRARIES)
+ set(SFML_IS_FRAMEWORK_INSTALL "@SFML_BUILD_FRAMEWORKS@")
+ if (SFML_IS_FRAMEWORK_INSTALL)
+ message(WARNING "Static frameworks are not supported by SFML. Clear SFML_DIR cache entry, \
+and either change SFML_STATIC_LIBRARIES or CMAKE_FIND_FRAMEWORK before calling find_package(SFML)")
+ endif()
+ set(config_name "Static")
+else()
+ set(config_name "Shared")
+endif()
+set(targets_config_file "${CMAKE_CURRENT_LIST_DIR}/SFML${config_name}Targets.cmake")
+
+# Generate imported targets for SFML and its dependencies
+if (EXISTS "${targets_config_file}")
+ # Set SFML_FOUND to TRUE by default, may be overwritten by one of the includes below
+ set(SFML_FOUND TRUE)
+ include("${targets_config_file}")
+ include("${CMAKE_CURRENT_LIST_DIR}/SFMLConfigDependencies.cmake")
+
+ if (SFML_FOUND)
+ foreach (component ${SFML_FIND_COMPONENTS})
+ string(TOUPPER "${component}" UPPER_COMPONENT)
+ if (TARGET sfml-${component})
+ set(SFML_${UPPER_COMPONENT}_FOUND TRUE)
+ else()
+ set(FIND_SFML_ERROR "Found SFML but requested component '${component}' is missing in the config defined in ${SFML_DIR}.")
+ set(SFML_${UPPER_COMPONENT}_FOUND FALSE)
+ set(SFML_FOUND FALSE)
+ endif()
+ endforeach()
+ endif()
+else()
+ set(FIND_SFML_ERROR "Requested SFML configuration (${config_name}) was not found")
+ set(SFML_FOUND FALSE)
+endif()
+
+if (NOT SFML_FOUND)
+ if(SFML_FIND_REQUIRED)
+ # fatal error
+ message(FATAL_ERROR "${FIND_SFML_ERROR}")
+ elseif(NOT SFML_FIND_QUIETLY)
+ # error but continue
+ message(STATUS "${FIND_SFML_ERROR}")
+ endif()
+endif()
+
+if (SFML_FOUND AND NOT SFML_FIND_QUIETLY)
+ message(STATUS "Found SFML @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ in ${CMAKE_CURRENT_LIST_DIR}")
+endif()
diff --git a/cmake/SFMLConfigDependencies.cmake.in b/cmake/SFMLConfigDependencies.cmake.in
new file mode 100644
index 0000000..1028110
--- /dev/null
+++ b/cmake/SFMLConfigDependencies.cmake.in
@@ -0,0 +1,86 @@
+
+if (CMAKE_VERSION VERSION_LESS 3.5.2)
+ include(CMakeParseArguments)
+endif()
+
+# in case of static linking, we must also define the list of all the dependencies of SFML libraries
+if(SFML_STATIC_LIBRARIES)
+ # detect the OS
+ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+ set(FIND_SFML_OS_WINDOWS 1)
+ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ set(FIND_SFML_OS_LINUX 1)
+ elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+ set(FIND_SFML_OS_FREEBSD 1)
+ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ if (DEFINED IOS)
+ set(FIND_SFML_OS_IOS 1)
+ else()
+ set(FIND_SFML_OS_MACOSX 1)
+ endif()
+ endif()
+
+ # start with an empty list
+ set(FIND_SFML_DEPENDENCIES_NOTFOUND)
+
+ # macro that searches for a 3rd-party library
+ function(sfml_bind_dependency)
+ cmake_parse_arguments(THIS "" "TARGET;FRIENDLY_NAME" "SEARCH_NAMES" ${ARGN})
+ if (THIS_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown arguments when calling sfml_bind_dependency: ${THIS_UNPARSED_ARGUMENTS}")
+ endif()
+
+ # No lookup in environment variables (PATH on Windows), as they may contain wrong library versions
+ find_library(${THIS_FRIENDLY_NAME}_LIB NAMES ${THIS_SEARCH_NAMES}
+ PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH)
+ mark_as_advanced(${THIS_FRIENDLY_NAME}_LIB)
+ if(${THIS_FRIENDLY_NAME}_LIB)
+ set_property(TARGET ${THIS_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${${THIS_FRIENDLY_NAME}_LIB}")
+ else()
+ set(FIND_SFML_DEPENDENCIES_NOTFOUND "${FIND_SFML_DEPENDENCIES_NOTFOUND} ${THIS_FRIENDLY_NAME}" PARENT_SCOPE)
+ endif()
+ endfunction()
+
+ # sfml-window
+ list(FIND SFML_FIND_COMPONENTS "window" FIND_SFML_WINDOW_COMPONENT_INDEX)
+ if(FIND_SFML_WINDOW_COMPONENT_INDEX GREATER -1)
+ if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD)
+ sfml_bind_dependency(TARGET X11 FRIENDLY_NAME "X11" SEARCH_NAMES "X11")
+ sfml_bind_dependency(TARGET X11 FRIENDLY_NAME "Xrandr" SEARCH_NAMES "Xrandr")
+ endif()
+
+ if(FIND_SFML_OS_LINUX)
+ sfml_bind_dependency(TARGET UDev FRIENDLY_NAME "UDev" SEARCH_NAMES "udev" "libudev")
+ endif()
+
+ if (FIND_SFML_OS_WINDOWS)
+ set_property(TARGET OpenGL APPEND PROPERTY INTERFACE_LINK_LIBRARIES "OpenGL32")
+ elseif(NOT FIND_SFML_OS_IOS)
+ sfml_bind_dependency(TARGET OpenGL FRIENDLY_NAME "OpenGL" SEARCH_NAMES "OpenGL" "GL")
+ endif()
+ endif()
+
+ # sfml-graphics
+ list(FIND SFML_FIND_COMPONENTS "graphics" FIND_SFML_GRAPHICS_COMPONENT_INDEX)
+ if(FIND_SFML_GRAPHICS_COMPONENT_INDEX GREATER -1)
+ sfml_bind_dependency(TARGET Freetype FRIENDLY_NAME "FreeType" SEARCH_NAMES "freetype")
+ endif()
+
+ # sfml-audio
+ list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT_INDEX)
+ if(FIND_SFML_AUDIO_COMPONENT_INDEX GREATER -1)
+ sfml_bind_dependency(TARGET OpenAL FRIENDLY_NAME "OpenAL" SEARCH_NAMES "OpenAL" "openal" "openal32")
+ if (NOT FIND_SFML_OS_IOS)
+ sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisFile" SEARCH_NAMES "vorbisfile")
+ sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisEnc" SEARCH_NAMES "vorbisenc")
+ endif()
+ sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Vorbis" SEARCH_NAMES "vorbis")
+ sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Ogg" SEARCH_NAMES "ogg")
+ sfml_bind_dependency(TARGET FLAC FRIENDLY_NAME "FLAC" SEARCH_NAMES "FLAC")
+ endif()
+
+ if (FIND_SFML_DEPENDENCIES_NOTFOUND)
+ set(FIND_SFML_ERROR "SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})")
+ set(SFML_FOUND FALSE)
+ endif()
+endif()
diff --git a/cmake/toolchains/android.toolchain.cmake b/cmake/toolchains/android.toolchain.cmake
new file mode 100644
index 0000000..ee28e51
--- /dev/null
+++ b/cmake/toolchains/android.toolchain.cmake
@@ -0,0 +1,1666 @@
+# Copyright (c) 2010-2011, Ethan Rublee
+# Copyright (c) 2011-2014, Andrey Kamaev
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# ------------------------------------------------------------------------------
+# Android CMake toolchain file, for use with the Android NDK r5-r10d
+# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended).
+# See home page: https://github.com/taka-no-me/android-cmake
+#
+# Usage Linux:
+# $ export ANDROID_NDK=/absolute/path/to/the/android-ndk
+# $ mkdir build && cd build
+# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
+# $ make -j8
+#
+# Usage Windows:
+# You need native port of make to build your project.
+# Android NDK r7 (and newer) already has make.exe on board.
+# For older NDK you have to install it separately.
+# For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm
+#
+# $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk
+# $ mkdir build && cd build
+# $ cmake.exe -G"MinGW Makefiles"
+# -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake
+# -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" ..
+# $ cmake.exe --build .
+#
+#
+# Options (can be set as cmake parameters: -D<option_name>=<value>):
+# ANDROID_NDK=/opt/android-ndk - path to the NDK root.
+# Can be set as environment variable. Can be set only at first cmake run.
+#
+# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary
+# Interface (ABI). This option nearly matches to the APP_ABI variable
+# used by ndk-build tool from Android NDK.
+#
+# Possible targets are:
+# "armeabi" - ARMv5TE based CPU with software floating point operations
+# "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions
+# this ABI target is used by default
+# "armeabi-v7a with NEON" - same as armeabi-v7a, but
+# sets NEON as floating-point unit
+# "armeabi-v7a with VFPV3" - same as armeabi-v7a, but
+# sets VFPV3 as floating-point unit (has 32 registers instead of 16)
+# "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP
+# "x86" - IA-32 instruction set
+# "mips" - MIPS32 instruction set
+#
+# 64-bit ABIs for NDK r10 and newer:
+# "arm64-v8a" - ARMv8 AArch64 instruction set
+# "x86_64" - Intel64 instruction set (r1)
+# "mips64" - MIPS64 instruction set (r6)
+#
+# ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for.
+# Option is read-only when standalone toolchain is used.
+# Note: building for "android-L" requires explicit configuration.
+#
+# ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler
+# toolchain to be used. The list of possible values depends on the NDK
+# version. For NDK r10c the possible values are:
+#
+# * aarch64-linux-android-4.9
+# * aarch64-linux-android-clang3.4
+# * aarch64-linux-android-clang3.5
+# * arm-linux-androideabi-4.6
+# * arm-linux-androideabi-4.8
+# * arm-linux-androideabi-4.9 (default)
+# * arm-linux-androideabi-clang3.4
+# * arm-linux-androideabi-clang3.5
+# * mips64el-linux-android-4.9
+# * mips64el-linux-android-clang3.4
+# * mips64el-linux-android-clang3.5
+# * mipsel-linux-android-4.6
+# * mipsel-linux-android-4.8
+# * mipsel-linux-android-4.9
+# * mipsel-linux-android-clang3.4
+# * mipsel-linux-android-clang3.5
+# * x86-4.6
+# * x86-4.8
+# * x86-4.9
+# * x86-clang3.4
+# * x86-clang3.5
+# * x86_64-4.9
+# * x86_64-clang3.4
+# * x86_64-clang3.5
+#
+# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions
+# instead of Thumb. Is not available for "armeabi-v6 with VFP"
+# (is forced to be ON) ABI.
+#
+# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker
+# errors even if they are not used.
+#
+# ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared
+# libraries. Automatically turned for NDK r5x and r6x due to GLESv2
+# problems.
+#
+# ANDROID_STL=gnustl_static - specify the runtime to use.
+#
+# Possible values are:
+# none -> Do not configure the runtime.
+# system -> Use the default minimal system C++ runtime library.
+# Implies -fno-rtti -fno-exceptions.
+# Is not available for standalone toolchain.
+# system_re -> Use the default minimal system C++ runtime library.
+# Implies -frtti -fexceptions.
+# Is not available for standalone toolchain.
+# gabi++_static -> Use the GAbi++ runtime as a static library.
+# Implies -frtti -fno-exceptions.
+# Available for NDK r7 and newer.
+# Is not available for standalone toolchain.
+# gabi++_shared -> Use the GAbi++ runtime as a shared library.
+# Implies -frtti -fno-exceptions.
+# Available for NDK r7 and newer.
+# Is not available for standalone toolchain.
+# stlport_static -> Use the STLport runtime as a static library.
+# Implies -fno-rtti -fno-exceptions for NDK before r7.
+# Implies -frtti -fno-exceptions for NDK r7 and newer.
+# Is not available for standalone toolchain.
+# stlport_shared -> Use the STLport runtime as a shared library.
+# Implies -fno-rtti -fno-exceptions for NDK before r7.
+# Implies -frtti -fno-exceptions for NDK r7 and newer.
+# Is not available for standalone toolchain.
+# gnustl_static -> Use the GNU STL as a static library.
+# Implies -frtti -fexceptions.
+# gnustl_shared -> Use the GNU STL as a shared library.
+# Implies -frtti -fno-exceptions.
+# Available for NDK r7b and newer.
+# Silently degrades to gnustl_static if not available.
+# c++_static -> Use libc++ as a static library.
+# c++_shared -> Use libc++ as a shared library.
+#
+# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
+# chosen runtime. If disabled, then the user is responsible for settings
+# these options.
+#
+# What?:
+# android-cmake toolchain searches for NDK/toolchain in the following order:
+# ANDROID_NDK - cmake parameter
+# ANDROID_NDK - environment variable
+# ANDROID_STANDALONE_TOOLCHAIN - cmake parameter
+# ANDROID_STANDALONE_TOOLCHAIN - environment variable
+# ANDROID_NDK - default locations
+# ANDROID_STANDALONE_TOOLCHAIN - default locations
+#
+# Make sure to do the following in your scripts:
+# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" )
+# SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" )
+# The flags will be prepopulated with critical flags, so don't loose them.
+# Also be aware that toolchain also sets configuration-specific compiler
+# flags and linker flags.
+#
+# ANDROID and BUILD_ANDROID will be set to true, you may test any of these
+# variables to make necessary Android-specific configuration changes.
+#
+# Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64
+# will be set true, mutually exclusive. NEON option will be set true
+# if VFP is set to NEON.
+#
+# ------------------------------------------------------------------------------
+
+cmake_minimum_required( VERSION 2.6.3 )
+
+if( DEFINED CMAKE_CROSSCOMPILING )
+ # subsequent toolchain loading is not really needed
+ return()
+endif()
+
+if( CMAKE_TOOLCHAIN_FILE )
+ # touch toolchain variable to suppress "unused variable" warning
+endif()
+
+# inherit settings in recursive loads
+get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE )
+if( _CMAKE_IN_TRY_COMPILE )
+ include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL )
+endif()
+
+# this one is important
+if( CMAKE_VERSION VERSION_GREATER "3.0.99" )
+ set( CMAKE_SYSTEM_NAME Android )
+else()
+ set( CMAKE_SYSTEM_NAME Linux )
+endif()
+
+# this one not so much
+set( CMAKE_SYSTEM_VERSION 1 )
+
+# rpath makes low sense for Android
+set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" )
+set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
+
+# NDK search paths
+set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
+if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS )
+ if( CMAKE_HOST_WIN32 )
+ file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
+ set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" )
+ else()
+ file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
+ set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" )
+ endif()
+endif()
+if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
+ set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
+endif()
+
+# known ABIs
+set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" )
+set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" )
+set( ANDROID_SUPPORTED_ABIS_x86 "x86" )
+set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" )
+set( ANDROID_SUPPORTED_ABIS_mips "mips" )
+set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" )
+
+# API level defaults
+set( ANDROID_DEFAULT_NDK_API_LEVEL 8 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 )
+
+
+macro( __LIST_FILTER listvar regex )
+ if( ${listvar} )
+ foreach( __val ${${listvar}} )
+ if( __val MATCHES "${regex}" )
+ list( REMOVE_ITEM ${listvar} "${__val}" )
+ endif()
+ endforeach()
+ endif()
+endmacro()
+
+macro( __INIT_VARIABLE var_name )
+ set( __test_path 0 )
+ foreach( __var ${ARGN} )
+ if( __var STREQUAL "PATH" )
+ set( __test_path 1 )
+ break()
+ endif()
+ endforeach()
+
+ if( __test_path AND NOT EXISTS "${${var_name}}" )
+ unset( ${var_name} CACHE )
+ endif()
+
+ if( " ${${var_name}}" STREQUAL " " )
+ set( __values 0 )
+ foreach( __var ${ARGN} )
+ if( __var STREQUAL "VALUES" )
+ set( __values 1 )
+ elseif( NOT __var STREQUAL "PATH" )
+ if( __var MATCHES "^ENV_.*$" )
+ string( REPLACE "ENV_" "" __var "${__var}" )
+ set( __value "$ENV{${__var}}" )
+ elseif( DEFINED ${__var} )
+ set( __value "${${__var}}" )
+ elseif( __values )
+ set( __value "${__var}" )
+ else()
+ set( __value "" )
+ endif()
+
+ if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") )
+ set( ${var_name} "${__value}" )
+ break()
+ endif()
+ endif()
+ endforeach()
+ unset( __value )
+ unset( __values )
+ endif()
+
+ if( __test_path )
+ file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
+ endif()
+ unset( __test_path )
+endmacro()
+
+macro( __DETECT_NATIVE_API_LEVEL _var _path )
+ set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
+ file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
+ if( NOT __apiFileContent )
+ message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
+ endif()
+ string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
+ unset( __apiFileContent )
+ unset( __ndkApiLevelRegex )
+endmacro()
+
+macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
+ if( EXISTS "${_root}" )
+ file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
+ __LIST_FILTER( __gccExePath "^[.].*" )
+ list( LENGTH __gccExePath __gccExePathsCount )
+ if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
+ message( WARNING "Could not determine machine name for compiler from ${_root}" )
+ set( ${_var} "" )
+ else()
+ get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
+ string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
+ endif()
+ unset( __gccExePath )
+ unset( __gccExePathsCount )
+ unset( __gccExeName )
+ else()
+ set( ${_var} "" )
+ endif()
+endmacro()
+
+
+# fight against cygwin
+set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools")
+mark_as_advanced( ANDROID_FORBID_SYGWIN )
+if( ANDROID_FORBID_SYGWIN )
+ if( CYGWIN )
+ message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." )
+ endif()
+
+ if( CMAKE_HOST_WIN32 )
+ # remove cygwin from PATH
+ set( __new_path "$ENV{PATH}")
+ __LIST_FILTER( __new_path "cygwin" )
+ set(ENV{PATH} "${__new_path}")
+ unset(__new_path)
+ endif()
+endif()
+
+
+# detect current host platform
+if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) )
+ set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" )
+ mark_as_advanced( ANDROID_NDK_HOST_X64 )
+endif()
+
+set( TOOL_OS_SUFFIX "" )
+if( CMAKE_HOST_APPLE )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" )
+elseif( CMAKE_HOST_WIN32 )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" )
+ set( TOOL_OS_SUFFIX ".exe" )
+elseif( CMAKE_HOST_UNIX )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" )
+else()
+ message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" )
+endif()
+
+if( NOT ANDROID_NDK_HOST_X64 )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} )
+endif()
+
+# see if we have path to Android NDK
+if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN )
+ __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
+endif()
+if( NOT ANDROID_NDK )
+ # see if we have path to Android standalone toolchain
+ __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN )
+
+ if( NOT ANDROID_STANDALONE_TOOLCHAIN )
+ #try to find Android NDK in one of the the default locations
+ set( __ndkSearchPaths )
+ foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
+ foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
+ list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" )
+ endforeach()
+ endforeach()
+ __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
+ unset( __ndkSearchPaths )
+
+ if( ANDROID_NDK )
+ message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" )
+ message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" )
+ else()
+ #try to find Android standalone toolchain in one of the the default locations
+ __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
+
+ if( ANDROID_STANDALONE_TOOLCHAIN )
+ message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" )
+ message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" )
+ endif( ANDROID_STANDALONE_TOOLCHAIN )
+ endif( ANDROID_NDK )
+ endif( NOT ANDROID_STANDALONE_TOOLCHAIN )
+endif( NOT ANDROID_NDK )
+
+# remember found paths
+if( ANDROID_NDK )
+ get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE )
+ set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE )
+ set( BUILD_WITH_ANDROID_NDK True )
+ if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" )
+ file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" )
+ string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" )
+ else()
+ set( ANDROID_NDK_RELEASE "r1x" )
+ set( ANDROID_NDK_RELEASE_FULL "unreleased" )
+ endif()
+ string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" )
+ string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum )
+ math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" )
+elseif( ANDROID_STANDALONE_TOOLCHAIN )
+ get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE )
+ # try to detect change
+ if( CMAKE_AR )
+ string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length )
+ string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath )
+ if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN )
+ message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." )
+ endif()
+ unset( __androidStandaloneToolchainPreviousPath )
+ unset( __length )
+ endif()
+ set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE )
+ set( BUILD_WITH_STANDALONE_TOOLCHAIN True )
+else()
+ list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH)
+ message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain.
+ You should either set an environment variable:
+ export ANDROID_NDK=~/my-android-ndk
+ or
+ export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
+ or put the toolchain or NDK in the default path:
+ sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk
+ sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
+endif()
+
+# android NDK layout
+if( BUILD_WITH_ANDROID_NDK )
+ if( NOT DEFINED ANDROID_NDK_LAYOUT )
+ # try to automatically detect the layout
+ if( EXISTS "${ANDROID_NDK}/RELEASE.TXT")
+ set( ANDROID_NDK_LAYOUT "RELEASE" )
+ elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" )
+ set( ANDROID_NDK_LAYOUT "LINARO" )
+ elseif( EXISTS "${ANDROID_NDK}/../../gcc/" )
+ set( ANDROID_NDK_LAYOUT "ANDROID" )
+ endif()
+ endif()
+ set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" )
+ mark_as_advanced( ANDROID_NDK_LAYOUT )
+ if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment
+ set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" )
+ elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment
+ set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" )
+ else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE"
+ set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" )
+ endif()
+ get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE )
+
+ # try to detect change of NDK
+ if( CMAKE_AR )
+ string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length )
+ string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath )
+ if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH )
+ message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first.
+ " )
+ endif()
+ unset( __androidNdkPreviousPath )
+ unset( __length )
+ endif()
+endif()
+
+
+# get all the details about standalone toolchain
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" )
+ set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ set( __availableToolchains "standalone" )
+ __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ if( NOT __availableToolchainMachines )
+ message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." )
+ endif()
+ if( __availableToolchainMachines MATCHES x86_64 )
+ set( __availableToolchainArchs "x86_64" )
+ elseif( __availableToolchainMachines MATCHES i686 )
+ set( __availableToolchainArchs "x86" )
+ elseif( __availableToolchainMachines MATCHES aarch64 )
+ set( __availableToolchainArchs "arm64" )
+ elseif( __availableToolchainMachines MATCHES arm )
+ set( __availableToolchainArchs "arm" )
+ elseif( __availableToolchainMachines MATCHES mips64el )
+ set( __availableToolchainArchs "mips64" )
+ elseif( __availableToolchainMachines MATCHES mipsel )
+ set( __availableToolchainArchs "mips" )
+ endif()
+ execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion
+ OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE )
+ string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" )
+ if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" )
+ list( APPEND __availableToolchains "standalone-clang" )
+ list( APPEND __availableToolchainMachines ${__availableToolchainMachines} )
+ list( APPEND __availableToolchainArchs ${__availableToolchainArchs} )
+ list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} )
+ endif()
+endif()
+
+macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath )
+ foreach( __toolchain ${${__availableToolchainsLst}} )
+ if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" )
+ SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" )
+ FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" )
+ if( __toolchainVersionStr )
+ string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" )
+ string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" )
+ else()
+ string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" )
+ endif()
+ unset( __toolchainVersionStr )
+ unset( __toolchainVersionRegex )
+ else()
+ set( __gcc_toolchain "${__toolchain}" )
+ endif()
+ __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" )
+ if( __machine )
+ string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" )
+ if( __machine MATCHES x86_64 )
+ set( __arch "x86_64" )
+ elseif( __machine MATCHES i686 )
+ set( __arch "x86" )
+ elseif( __machine MATCHES aarch64 )
+ set( __arch "arm64" )
+ elseif( __machine MATCHES arm )
+ set( __arch "arm" )
+ elseif( __machine MATCHES mips64el )
+ set( __arch "mips64" )
+ elseif( __machine MATCHES mipsel )
+ set( __arch "mips" )
+ else()
+ set( __arch "" )
+ endif()
+ #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n")
+ if (__arch)
+ list( APPEND __availableToolchainMachines "${__machine}" )
+ list( APPEND __availableToolchainArchs "${__arch}" )
+ list( APPEND __availableToolchainCompilerVersions "${__version}" )
+ list( APPEND ${__availableToolchainsVar} "${__toolchain}" )
+ endif()
+ endif()
+ unset( __gcc_toolchain )
+ endforeach()
+endmacro()
+
+# get all the details about NDK
+if( BUILD_WITH_ANDROID_NDK )
+ file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" )
+ string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" )
+ set( __availableToolchains "" )
+ set( __availableToolchainMachines "" )
+ set( __availableToolchainArchs "" )
+ set( __availableToolchainCompilerVersions "" )
+ if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" )
+ # do not go through all toolchains if we know the name
+ set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" )
+ __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+ if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
+ __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
+ if( __availableToolchains )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} )
+ endif()
+ endif()
+ endif()
+ if( NOT __availableToolchains )
+ file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
+ if( __availableToolchainsLst )
+ list(SORT __availableToolchainsLst) # we need clang to go after gcc
+ endif()
+ __LIST_FILTER( __availableToolchainsLst "^[.]" )
+ __LIST_FILTER( __availableToolchainsLst "llvm" )
+ __LIST_FILTER( __availableToolchainsLst "renderscript" )
+ __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+ if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
+ __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
+ if( __availableToolchains )
+ set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} )
+ endif()
+ endif()
+ endif()
+ if( NOT __availableToolchains )
+ message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." )
+ endif()
+endif()
+
+# build list of available ABIs
+set( ANDROID_SUPPORTED_ABIS "" )
+set( __uniqToolchainArchNames ${__availableToolchainArchs} )
+list( REMOVE_DUPLICATES __uniqToolchainArchNames )
+list( SORT __uniqToolchainArchNames )
+foreach( __arch ${__uniqToolchainArchNames} )
+ list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} )
+endforeach()
+unset( __uniqToolchainArchNames )
+if( NOT ANDROID_SUPPORTED_ABIS )
+ message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." )
+endif()
+
+# choose target ABI
+__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} )
+# verify that target ABI is supported
+list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
+if( __androidAbiIdx EQUAL -1 )
+ string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" )
+ message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain.
+ Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\"
+ " )
+endif()
+unset( __androidAbiIdx )
+
+# set target ABI options
+if( ANDROID_ABI STREQUAL "x86" )
+ set( X86 true )
+ set( ANDROID_NDK_ABI_NAME "x86" )
+ set( ANDROID_ARCH_NAME "x86" )
+ set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "i686" )
+elseif( ANDROID_ABI STREQUAL "x86_64" )
+ set( X86 true )
+ set( X86_64 true )
+ set( ANDROID_NDK_ABI_NAME "x86_64" )
+ set( ANDROID_ARCH_NAME "x86_64" )
+ set( CMAKE_SYSTEM_PROCESSOR "x86_64" )
+ set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" )
+elseif( ANDROID_ABI STREQUAL "mips64" )
+ set( MIPS64 true )
+ set( ANDROID_NDK_ABI_NAME "mips64" )
+ set( ANDROID_ARCH_NAME "mips64" )
+ set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "mips64" )
+elseif( ANDROID_ABI STREQUAL "mips" )
+ set( MIPS true )
+ set( ANDROID_NDK_ABI_NAME "mips" )
+ set( ANDROID_ARCH_NAME "mips" )
+ set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "mips" )
+elseif( ANDROID_ABI STREQUAL "arm64-v8a" )
+ set( ARM64_V8A true )
+ set( ANDROID_NDK_ABI_NAME "arm64-v8a" )
+ set( ANDROID_ARCH_NAME "arm64" )
+ set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" )
+ set( CMAKE_SYSTEM_PROCESSOR "aarch64" )
+ set( VFPV3 true )
+ set( NEON true )
+elseif( ANDROID_ABI STREQUAL "armeabi" )
+ set( ARMEABI true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv5te" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" )
+ set( ARMEABI_V6 true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv6" )
+ # need always fallback to older platform
+ set( ARMEABI true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a")
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+ set( NEON true )
+else()
+ message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." )
+endif()
+
+if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" )
+ # really dirty hack
+ # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run...
+ file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" )
+endif()
+
+if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
+ __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF )
+ set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
+ mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
+else()
+ unset( ANDROID_FORCE_ARM_BUILD CACHE )
+endif()
+
+# choose toolchain
+if( ANDROID_TOOLCHAIN_NAME )
+ list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx )
+ if( __toolchainIdx EQUAL -1 )
+ list( SORT __availableToolchains )
+ string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" )
+ set( toolchains_list " * ${toolchains_list}")
+ message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain.
+To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" )
+ endif()
+ list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch )
+ if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME )
+ message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." )
+ endif()
+else()
+ set( __toolchainIdx -1 )
+ set( __applicableToolchains "" )
+ set( __toolchainMaxVersion "0.0.0" )
+ list( LENGTH __availableToolchains __availableToolchainsCount )
+ math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" )
+ foreach( __idx RANGE ${__availableToolchainsCount} )
+ list( GET __availableToolchainArchs ${__idx} __toolchainArch )
+ if( __toolchainArch STREQUAL ANDROID_ARCH_NAME )
+ list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion )
+ string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}")
+ if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion )
+ set( __toolchainMaxVersion "${__toolchainVersion}" )
+ set( __toolchainIdx ${__idx} )
+ endif()
+ endif()
+ endforeach()
+ unset( __availableToolchainsCount )
+ unset( __toolchainMaxVersion )
+ unset( __toolchainVersion )
+endif()
+unset( __toolchainArch )
+if( __toolchainIdx EQUAL -1 )
+ message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." )
+endif()
+list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME )
+list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME )
+list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION )
+
+unset( __toolchainIdx )
+unset( __availableToolchains )
+unset( __availableToolchainMachines )
+unset( __availableToolchainArchs )
+unset( __availableToolchainCompilerVersions )
+
+# choose native API level
+__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL )
+string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" )
+string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL )
+# adjust API level
+set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} )
+foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level )
+ set( __real_api_level ${__level} )
+ endif()
+endforeach()
+if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level )
+ message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'")
+ set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} )
+endif()
+unset(__real_api_level)
+# validate
+list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx )
+if( __levelIdx EQUAL -1 )
+ message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." )
+else()
+ if( BUILD_WITH_ANDROID_NDK )
+ __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" )
+ if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 )
+ message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." )
+ endif()
+ unset( __realApiLevel )
+ endif()
+ set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
+ set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} )
+ list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
+ set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+endif()
+unset( __levelIdx )
+
+
+# remember target ABI
+set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE )
+list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} )
+set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} )
+
+
+# runtime choice (STL, rtti, exceptions)
+if( NOT ANDROID_STL )
+ set( ANDROID_STL gnustl_static )
+endif()
+set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" )
+set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" )
+mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
+
+if( BUILD_WITH_ANDROID_NDK )
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
+ message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
+The possible values are:
+ none -> Do not configure the runtime.
+ system -> Use the default minimal system C++ runtime library.
+ system_re -> Same as system but with rtti and exceptions.
+ gabi++_static -> Use the GAbi++ runtime as a static library.
+ gabi++_shared -> Use the GAbi++ runtime as a shared library.
+ stlport_static -> Use the STLport runtime as a static library.
+ stlport_shared -> Use the STLport runtime as a shared library.
+ gnustl_static -> (default) Use the GNU STL as a static library.
+ gnustl_shared -> Use the GNU STL as a shared library.
+ c++_static -> Use libc++ as a static library.
+ c++_shared -> Use libc++ as a shared library.
+" )
+ endif()
+elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$")
+ message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
+The possible values are:
+ none -> Do not configure the runtime.
+ gnustl_static -> (default) Use the GNU STL as a static library.
+ gnustl_shared -> Use the GNU STL as a shared library.
+" )
+ endif()
+endif()
+
+unset( ANDROID_RTTI )
+unset( ANDROID_EXCEPTIONS )
+unset( ANDROID_STL_INCLUDE_DIRS )
+unset( __libstl )
+unset( __libsupcxx )
+
+if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" )
+ message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf).
+You are strongly recommended to switch to another NDK release.
+" )
+endif()
+
+if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" )
+ message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header:
+See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2
+ diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+ index 5e28c64..65892a1 100644
+ --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+ +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h
+ @@ -51,7 +51,11 @@ typedef long int ssize_t;
+ #endif
+ #ifndef _PTRDIFF_T
+ #define _PTRDIFF_T
+ -typedef long ptrdiff_t;
+ +# ifdef __ANDROID__
+ + typedef int ptrdiff_t;
+ +# else
+ + typedef long ptrdiff_t;
+ +# endif
+ #endif
+" )
+endif()
+
+
+# setup paths and STL for standalone toolchain
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" )
+
+ if( NOT ANDROID_STL STREQUAL "none" )
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" )
+ if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" )
+ # old location ( pre r8c )
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" )
+ endif()
+ if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" )
+ list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" )
+ elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" )
+ list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" )
+ else()
+ list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" )
+ endif()
+ # always search static GNU STL to get the location of libsupc++.a
+ if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" )
+ elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" )
+ elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" )
+ elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" )
+ endif()
+ if( __libstl )
+ set( __libsupcxx "${__libstl}/libsupc++.a" )
+ set( __libstl "${__libstl}/libstdc++.a" )
+ endif()
+ if( NOT EXISTS "${__libsupcxx}" )
+ message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain.
+ Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c.
+ You need to either upgrade to newer NDK or manually copy
+ $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a
+ to
+ ${__libsupcxx}
+ " )
+ endif()
+ if( ANDROID_STL STREQUAL "gnustl_shared" )
+ if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" )
+ elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" )
+ elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" )
+ set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" )
+ endif()
+ endif()
+ endif()
+endif()
+
+# clang
+if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" )
+ set( ANDROID_COMPILER_IS_CLANG 1 )
+ execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE )
+ string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}")
+elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" )
+ string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}")
+ string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
+ if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" )
+ message( FATAL_ERROR "Could not find the Clang compiler driver" )
+ endif()
+ set( ANDROID_COMPILER_IS_CLANG 1 )
+ set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+else()
+ set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
+ unset( ANDROID_COMPILER_IS_CLANG CACHE )
+endif()
+
+string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" )
+if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" )
+ set( _clang_name "clang" )
+endif()
+
+
+# setup paths and STL for NDK
+if( BUILD_WITH_ANDROID_NDK )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
+ set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" )
+
+ if( ANDROID_STL STREQUAL "none" )
+ # do nothing
+ elseif( ANDROID_STL STREQUAL "system" )
+ set( ANDROID_RTTI OFF )
+ set( ANDROID_EXCEPTIONS OFF )
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
+ elseif( ANDROID_STL STREQUAL "system_re" )
+ set( ANDROID_RTTI ON )
+ set( ANDROID_EXCEPTIONS ON )
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
+ elseif( ANDROID_STL MATCHES "gabi" )
+ if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+ message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
+ endif()
+ set( ANDROID_RTTI ON )
+ set( ANDROID_EXCEPTIONS OFF )
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" )
+ set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" )
+ elseif( ANDROID_STL MATCHES "stlport" )
+ if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d
+ set( ANDROID_EXCEPTIONS ON )
+ else()
+ set( ANDROID_EXCEPTIONS OFF )
+ endif()
+ if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+ set( ANDROID_RTTI OFF )
+ else()
+ set( ANDROID_RTTI ON )
+ endif()
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" )
+ set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" )
+ elseif( ANDROID_STL MATCHES "gnustl" )
+ set( ANDROID_EXCEPTIONS ON )
+ set( ANDROID_RTTI ON )
+ if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" )
+ if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" )
+ # gnustl binary for 4.7 compiler is buggy :(
+ # TODO: look for right fix
+ set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" )
+ else()
+ set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" )
+ endif()
+ else()
+ set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" )
+ endif()
+ set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" )
+ if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
+ set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
+ else()
+ set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
+ endif()
+ elseif( ANDROID_STL MATCHES "c\\+\\+_shared" OR ANDROID_STL MATCHES "c\\+\\+_static" )
+ set( ANDROID_EXCEPTIONS ON )
+ set( ANDROID_RTTI ON )
+ set( ANDROID_CXX_ROOT "${ANDROID_NDK}/sources/cxx-stl/" )
+ set( ANDROID_LLVM_ROOT "${ANDROID_CXX_ROOT}/llvm-libc++" )
+ if( X86 )
+ set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/gabi++/include" )
+ else()
+ set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/llvm-libc++abi/include" )
+ endif()
+ set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_LLVM_ROOT}/libcxx/include"
+ "${ANDROID_ABI_INCLUDE_DIRS}" )
+ # android support sfiles
+ include_directories ( SYSTEM ${ANDROID_NDK}/sources/android/support/include )
+ if( ANDROID_STL MATCHES "c\\+\\+_shared" AND EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/libc++_shared.so" )
+ set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/libc++_shared.so" )
+ elseif( ANDROID_STL MATCHES "c\\+\\+_static" AND EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/libc++_static.a" )
+ set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/libc++_static.a" )
+ else()
+ message( "c++ library doesn't exist" )
+ endif()
+ else()
+ message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
+ endif()
+ # find libsupc++.a - rtti & exceptions
+ if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" )
+ set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer
+ if( NOT EXISTS "${__libsupcxx}" )
+ set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8
+ endif()
+ if( NOT EXISTS "${__libsupcxx}" ) # before r7
+ if( ARMEABI_V7A )
+ if( ANDROID_FORCE_ARM_BUILD )
+ set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" )
+ else()
+ set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" )
+ endif()
+ elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD )
+ set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" )
+ else()
+ set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" )
+ endif()
+ endif()
+ if( NOT EXISTS "${__libsupcxx}")
+ message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.")
+ endif()
+ endif()
+endif()
+
+
+# case of shared STL linkage
+if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl )
+ string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" )
+ # TODO: check if .so file exists before the renaming
+endif()
+
+
+# ccache support
+__INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE )
+if( _ndk_ccache )
+ if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE )
+ unset( NDK_CCACHE CACHE )
+ endif()
+ find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary")
+else()
+ unset( NDK_CCACHE CACHE )
+endif()
+unset( _ndk_ccache )
+
+
+# setup the cross-compiler
+if( NOT CMAKE_C_COMPILER )
+ if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" )
+ set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" )
+ set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" )
+ if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
+ set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+ else()
+ set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
+ set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+ endif()
+ else()
+ if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
+ set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
+ else()
+ set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" )
+ set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" )
+ endif()
+ endif()
+ set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" )
+ set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" )
+ if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" )
+ # Use gcc-ar if we have it for better LTO support.
+ set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
+ else()
+ set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
+ endif()
+ set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" )
+ set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" )
+ set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
+ set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" )
+ set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" )
+endif()
+
+set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" )
+if( APPLE )
+ find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool )
+ if( NOT CMAKE_INSTALL_NAME_TOOL )
+ message( FATAL_ERROR "Could not find install_name_tool, please check your installation." )
+ endif()
+ mark_as_advanced( CMAKE_INSTALL_NAME_TOOL )
+endif()
+
+# Force set compilers because standard identification works badly for us
+include( CMakeForceCompiler )
+CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
+if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_C_COMPILER_ID Clang )
+endif()
+set( CMAKE_C_PLATFORM_ID Linux )
+if( X86_64 OR MIPS64 OR ARM64_V8A )
+ set( CMAKE_C_SIZEOF_DATA_PTR 8 )
+else()
+ set( CMAKE_C_SIZEOF_DATA_PTR 4 )
+endif()
+set( CMAKE_C_HAS_ISYSROOT 1 )
+set( CMAKE_C_COMPILER_ABI ELF )
+CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU )
+if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_CXX_COMPILER_ID Clang)
+endif()
+set( CMAKE_CXX_PLATFORM_ID Linux )
+set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} )
+set( CMAKE_CXX_HAS_ISYSROOT 1 )
+set( CMAKE_CXX_COMPILER_ABI ELF )
+set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C )
+# force ASM compiler (required for CMake < 2.8.5)
+set( CMAKE_ASM_COMPILER_ID_RUN TRUE )
+set( CMAKE_ASM_COMPILER_ID GNU )
+set( CMAKE_ASM_COMPILER_WORKS TRUE )
+set( CMAKE_ASM_COMPILER_FORCED TRUE )
+set( CMAKE_COMPILER_IS_GNUASM 1)
+set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm )
+
+foreach( lang C CXX ASM )
+ if( ANDROID_COMPILER_IS_CLANG )
+ set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} )
+ else()
+ set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} )
+ endif()
+endforeach()
+
+# flags and definitions
+remove_definitions( -DANDROID )
+add_definitions( -DANDROID )
+
+if( ANDROID_SYSROOT MATCHES "[ ;\"]" )
+ if( CMAKE_HOST_WIN32 )
+ # try to convert path to 8.3 form
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" )
+ execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}"
+ OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE __result ERROR_QUIET )
+ if( __result EQUAL 0 )
+ file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT )
+ set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" )
+ else()
+ set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" )
+ endif()
+ else()
+ set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" )
+ endif()
+ if( NOT _CMAKE_IN_TRY_COMPILE )
+ # quotes can break try_compile and compiler identification
+ message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n")
+ endif()
+else()
+ set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" )
+endif()
+
+# NDK flags
+if (ARM64_V8A )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
+ endif()
+elseif( ARMEABI OR ARMEABI_V7A)
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
+ set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" )
+ endif()
+ else()
+ # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI
+ set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
+ endif()
+ endif()
+elseif( X86 OR X86_64 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
+ endif()
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
+ set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
+elseif( MIPS OR MIPS64 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" )
+ set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" )
+ set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" )
+ if( NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" )
+ set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
+ endif()
+elseif()
+ set( ANDROID_CXX_FLAGS_RELEASE "" )
+ set( ANDROID_CXX_FLAGS_DEBUG "" )
+endif()
+
+set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries
+
+if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" )
+endif()
+
+if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/
+endif()
+
+# ABI-specific flags
+if( ARMEABI_V7A )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" )
+ if( NEON )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" )
+ elseif( VFPV3 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" )
+ else()
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" )
+ endif()
+elseif( ARMEABI_V6 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2
+elseif( ARMEABI )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" )
+endif()
+
+if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+else()
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+endif()
+
+# STL
+if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" )
+ if( EXISTS "${__libstl}" )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" )
+ endif()
+ if( EXISTS "${__libsupcxx}" )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" )
+ # C objects:
+ set( CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_C_CREATE_SHARED_MODULE "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" )
+ set( CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" )
+ set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" )
+ set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" )
+ set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" )
+ endif()
+ if( ANDROID_STL MATCHES "gnustl" )
+ if( NOT EXISTS "${ANDROID_LIBM_PATH}" )
+ set( ANDROID_LIBM_PATH -lm )
+ endif()
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" )
+ endif()
+endif()
+
+# variables controlling optional build flags
+if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
+ # libGLESv2.so in NDK's prior to r7 refers to missing external symbols.
+ # So this flag option is required for all projects using OpenGL from native.
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON )
+else()
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF )
+endif()
+__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON )
+__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON )
+__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON )
+__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON )
+__INIT_VARIABLE( ANDROID_RELRO VALUES ON )
+
+set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" )
+set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
+set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" )
+set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" )
+set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
+set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" )
+mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO )
+
+# linker flags
+set( ANDROID_LINKER_FLAGS "" )
+
+if( ARMEABI_V7A )
+ # this is *required* to use the following linker flags that routes around
+ # a CPU bug in some Cortex-A8 implementations:
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" )
+endif()
+
+if( ANDROID_NO_UNDEFINED )
+ if( MIPS )
+ # there is some sysroot-related problem in mips linker...
+ if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" )
+ endif()
+ else()
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" )
+ endif()
+endif()
+
+if( ANDROID_SO_UNDEFINED )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" )
+endif()
+
+if( ANDROID_FUNCTION_LEVEL_LINKING )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" )
+endif()
+
+if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" )
+ if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" )
+ elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" )
+ elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE )
+ message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342
+ On Linux and OS X host platform you can workaround this problem using gold linker (default).
+ Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems.
+" )
+ endif()
+endif() # version 4.6
+
+if( ANDROID_NOEXECSTACK )
+ if( ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" )
+ else()
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" )
+ endif()
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" )
+endif()
+
+if( ANDROID_RELRO )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" )
+endif()
+
+if( ANDROID_COMPILER_IS_CLANG )
+ set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" )
+ if( BUILD_WITH_ANDROID_NDK )
+ set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" )
+ endif()
+endif()
+
+# cache flags
+set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" )
+set( CMAKE_C_FLAGS "" CACHE STRING "c flags" )
+set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" )
+set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" )
+set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" )
+set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" )
+set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" )
+set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" )
+set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" )
+
+# put flags to cache (for debug purpose only)
+set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" )
+set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" )
+set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" )
+set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" )
+
+# finish flags
+set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" )
+set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" )
+set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" )
+set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" )
+set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" )
+set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" )
+set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" )
+set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" )
+set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" )
+
+if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" )
+ set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" )
+ set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" )
+endif()
+
+# pie/pic
+if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE))
+ set( CMAKE_POSITION_INDEPENDENT_CODE TRUE )
+ set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
+else()
+ set( CMAKE_POSITION_INDEPENDENT_CODE FALSE )
+ set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" )
+ set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" )
+endif()
+
+# configure rtti
+if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES )
+ if( ANDROID_RTTI )
+ set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" )
+ else()
+ set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" )
+ endif()
+endif()
+
+# configure exceptios
+if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES )
+ if( ANDROID_EXCEPTIONS )
+ set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" )
+ set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" )
+ else()
+ set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" )
+ set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" )
+ endif()
+endif()
+
+# global includes and link directories
+include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} )
+get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning
+link_directories( "${__android_install_path}" )
+
+# detect if need link crtbegin_so.o explicitly
+if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK )
+ set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" )
+ string( REPLACE "<CMAKE_CXX_COMPILER>" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_C_COMPILER>" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_CXX_FLAGS>" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" )
+ string( REPLACE "<LANGUAGE_COMPILE_FLAGS>" "" __cmd "${__cmd}" )
+ string( REPLACE "<LINK_FLAGS>" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS>" "-shared" __cmd "${__cmd}" )
+ string( REPLACE "<CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG>" "" __cmd "${__cmd}" )
+ string( REPLACE "<TARGET_SONAME>" "" __cmd "${__cmd}" )
+ string( REPLACE "<TARGET>" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" )
+ string( REPLACE "<OBJECTS>" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" )
+ string( REPLACE "<LINK_LIBRARIES>" "" __cmd "${__cmd}" )
+ separate_arguments( __cmd )
+ foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN )
+ if( ${__var} )
+ set( __tmp "${${__var}}" )
+ separate_arguments( __tmp )
+ string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}")
+ endif()
+ endforeach()
+ string( REPLACE "'" "" __cmd "${__cmd}" )
+ string( REPLACE "\"" "" __cmd "${__cmd}" )
+ execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET )
+ if( __cmd_result EQUAL 0 )
+ set( ANDROID_EXPLICIT_CRT_LINK ON )
+ else()
+ set( ANDROID_EXPLICIT_CRT_LINK OFF )
+ endif()
+endif()
+
+if( ANDROID_EXPLICIT_CRT_LINK )
+ set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" )
+ set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" )
+endif()
+
+# setup output directories
+set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
+
+if( DEFINED LIBRARY_OUTPUT_PATH_ROOT
+ OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml"
+ OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") )
+ set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" )
+ if( NOT _CMAKE_IN_TRY_COMPILE )
+ if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
+ set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
+ else()
+ set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
+ endif()
+ set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" )
+ endif()
+endif()
+
+# copy shaed stl library to build directory
+if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH )
+ get_filename_component( __libstlname "${__libstl}" NAME )
+ execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
+ if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
+ message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
+ endif()
+ unset( __fileCopyProcess )
+ unset( __libstlname )
+endif()
+
+
+# set these global flags for cmake client scripts to change behavior
+set( ANDROID True )
+set( BUILD_ANDROID True )
+
+# where is the target environment
+set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" )
+
+# only search for libraries and includes in the ndk toolchain
+set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+
+# export toolchain settings for the try_compile() command
+if( NOT _CMAKE_IN_TRY_COMPILE )
+ set( __toolchain_config "")
+ foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN
+ ANDROID_NDK_HOST_X64
+ ANDROID_NDK
+ ANDROID_NDK_LAYOUT
+ ANDROID_STANDALONE_TOOLCHAIN
+ ANDROID_TOOLCHAIN_NAME
+ ANDROID_ABI
+ ANDROID_NATIVE_API_LEVEL
+ ANDROID_STL
+ ANDROID_STL_FORCE_FEATURES
+ ANDROID_FORCE_ARM_BUILD
+ ANDROID_NO_UNDEFINED
+ ANDROID_SO_UNDEFINED
+ ANDROID_FUNCTION_LEVEL_LINKING
+ ANDROID_GOLD_LINKER
+ ANDROID_NOEXECSTACK
+ ANDROID_RELRO
+ ANDROID_LIBM_PATH
+ ANDROID_EXPLICIT_CRT_LINK
+ ANDROID_APP_PIE
+ )
+ if( DEFINED ${__var} )
+ if( ${__var} MATCHES " ")
+ set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
+ else()
+ set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
+ endif()
+ endif()
+ endforeach()
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" )
+ unset( __toolchain_config )
+endif()
+
+
+# force cmake to produce / instead of \ in build commands for Ninja generator
+if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 )
+ # it is a bad hack after all
+ # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW
+ set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW
+ set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion
+ enable_language( C )
+ enable_language( CXX )
+ # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it
+ unset( MINGW )
+endif()
+
+
+# Variables controlling behavior or set by cmake toolchain:
+# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
+# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version)
+# ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none
+# ANDROID_FORBID_SYGWIN : ON/OFF
+# ANDROID_NO_UNDEFINED : ON/OFF
+# ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version)
+# ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF
+# ANDROID_GOLD_LINKER : ON/OFF
+# ANDROID_NOEXECSTACK : ON/OFF
+# ANDROID_RELRO : ON/OFF
+# ANDROID_FORCE_ARM_BUILD : ON/OFF
+# ANDROID_STL_FORCE_FEATURES : ON/OFF
+# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
+# Can be set only at the first run:
+# ANDROID_NDK : path to your NDK install
+# NDK_CCACHE : path to your ccache executable
+# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain
+# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems)
+# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID)
+# LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
+# ANDROID_STANDALONE_TOOLCHAIN
+#
+# Primary read-only variables:
+# ANDROID : always TRUE
+# ARMEABI : TRUE for arm v6 and older devices
+# ARMEABI_V6 : TRUE for arm v6
+# ARMEABI_V7A : TRUE for arm v7a
+# ARM64_V8A : TRUE for arm64-v8a
+# NEON : TRUE if NEON unit is enabled
+# VFPV3 : TRUE if VFP version 3 is enabled
+# X86 : TRUE if configured for x86
+# X86_64 : TRUE if configured for x86_64
+# MIPS : TRUE if configured for mips
+# MIPS64 : TRUE if configured for mips64
+# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
+# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
+# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
+# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI
+# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK
+# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor)
+# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI
+# ANDROID_SYSROOT : path to the compiler sysroot
+# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
+# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used
+#
+# Secondary (less stable) read-only variables:
+# ANDROID_COMPILER_VERSION : GCC version used (not Clang version)
+# ANDROID_CLANG_VERSION : version of clang compiler if clang is used
+# ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform
+# ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI
+# ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux"
+# ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK)
+# ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools
+# ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK
+# ANDROID_STL_INCLUDE_DIRS : stl include paths
+# ANDROID_RTTI : if rtti is enabled by the runtime
+# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime
+# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used
+#
+# Defaults:
+# ANDROID_DEFAULT_NDK_API_LEVEL
+# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
+# ANDROID_NDK_SEARCH_PATHS
+# ANDROID_SUPPORTED_ABIS_${ARCH}
+# ANDROID_SUPPORTED_NDK_VERSIONS
diff --git a/cmake/toolchains/iOS.toolchain.cmake b/cmake/toolchains/iOS.toolchain.cmake
new file mode 100644
index 0000000..c697857
--- /dev/null
+++ b/cmake/toolchains/iOS.toolchain.cmake
@@ -0,0 +1,188 @@
+# Copyright (c) 2016, Bogdan Cristea <cristeab@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
+# files which are included with CMake 2.8.4
+# It has been altered for iOS development
+
+# Options:
+#
+# IOS_PLATFORM = OS (default) or SIMULATOR
+# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
+# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
+# SIMULATOR - used to build for the Simulator platforms, which have an x86_64 arch.
+#
+# IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
+# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
+# If set manually, it will override the default location and force the user of a particular Developer Platform
+#
+# IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
+# By default this location is automatcially chosen based on the IOS_DEVELOPER_ROOT value.
+# In this case it will always be the most up-to-date SDK found in the IOS_DEVELOPER_ROOT path.
+# If set manually, this will force the use of a specific SDK version
+
+# Macros:
+#
+# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
+# A convenience macro for setting xcode specific properties on targets
+# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
+#
+# find_host_package (PROGRAM ARGS)
+# A macro used to find executable programs on the host system, not within the iOS environment.
+# Thanks to the android-cmake project for providing the command
+
+# Standard settings
+set (CMAKE_SYSTEM_NAME Darwin)
+set (CMAKE_SYSTEM_VERSION 1)
+set (UNIX True)
+set (APPLE True)
+set (IOS True)
+
+# Required as of cmake 2.8.10
+set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
+
+# Determine the cmake host system version so we know where to find the iOS SDKs
+find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
+if (CMAKE_UNAME)
+ exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
+ string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
+endif (CMAKE_UNAME)
+
+set(CMAKE_C_COMPILER /usr/bin/clang CACHE FILEPATH "" FORCE)
+set(CMAKE_CXX_COMPILER /usr/bin/clang++ CACHE FILEPATH "" FORCE)
+set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
+
+# Skip the platform compiler checks for cross compiling
+set (CMAKE_CXX_COMPILER_WORKS TRUE)
+set (CMAKE_C_COMPILER_WORKS TRUE)
+
+# All iOS/Darwin specific settings - some may be redundant
+set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set (CMAKE_SHARED_MODULE_PREFIX "lib")
+set (CMAKE_SHARED_MODULE_SUFFIX ".so")
+set (CMAKE_MODULE_EXISTS 1)
+set (CMAKE_DL_LIBS "")
+
+set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
+set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
+set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
+
+# Hidden visibilty is required for cxx on iOS
+set (CMAKE_C_FLAGS_INIT "")
+set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden")
+
+set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
+set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
+
+set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
+
+# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
+# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
+if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+ find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
+endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+
+# Setup iOS platform unless specified manually with IOS_PLATFORM
+if (NOT DEFINED IOS_PLATFORM)
+ set (IOS_PLATFORM "OS")
+endif (NOT DEFINED IOS_PLATFORM)
+set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform: OS or SIMULATOR")
+
+# Check the platform selection and setup for developer root
+if (IOS_PLATFORM STREQUAL OS)
+ set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
+
+ # This causes the installers to properly locate the output libraries
+ set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
+elseif (IOS_PLATFORM STREQUAL SIMULATOR)
+ set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
+
+ # This causes the installers to properly locate the output libraries
+ set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
+else ()
+ message (FATAL_ERROR "Unsupported IOS_PLATFORM value '${IOS_PLATFORM}' selected. Please choose OS or SIMULATOR")
+endif ()
+
+# Setup iOS developer location unless specified manually with IOS_DEVELOPER_ROOT
+exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE XCODE_DEVELOPER_DIR)
+set (IOS_DEVELOPER_ROOT "${XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer" CACHE PATH "Location of iOS Platform")
+
+# Find and use the most recent iOS sdk unless specified manually with IOS_SDK_ROOT
+if (NOT DEFINED IOS_SDK_ROOT)
+ file (GLOB _IOS_SDKS "${IOS_DEVELOPER_ROOT}/SDKs/*")
+ if (_IOS_SDKS)
+ list (SORT _IOS_SDKS)
+ list (REVERSE _IOS_SDKS)
+ list (GET _IOS_SDKS 0 IOS_SDK_ROOT)
+ else (_IOS_SDKS)
+ message (FATAL_ERROR "No iOS SDK's found in default search path ${IOS_DEVELOPER_ROOT}. Manually set IOS_SDK_ROOT or install the iOS SDK.")
+ endif (_IOS_SDKS)
+ message (STATUS "Toolchain using default iOS SDK: ${IOS_SDK_ROOT}")
+endif (NOT DEFINED IOS_SDK_ROOT)
+set (IOS_SDK_ROOT ${IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
+
+# Set the sysroot default to the most recent SDK
+set (CMAKE_OSX_SYSROOT ${IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
+
+# set the architecture for iOS
+if (${IOS_PLATFORM} STREQUAL OS)
+ set (OSX_UNIVERSAL true)
+ set (IOS_ARCH arm64)
+elseif (${IOS_PLATFORM} STREQUAL SIMULATOR)
+ set (IOS_ARCH x86_64)
+endif (${IOS_PLATFORM} STREQUAL OS)
+
+set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS" FORCE)
+
+# Set the find root to the iOS developer roots and to user defined paths
+set (CMAKE_FIND_ROOT_PATH ${IOS_DEVELOPER_ROOT} ${IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING "iOS find search path root")
+
+# default to searching for frameworks first
+set (CMAKE_FIND_FRAMEWORK FIRST)
+
+# set up the default search directories for frameworks
+set (CMAKE_SYSTEM_FRAMEWORK_PATH
+ ${IOS_SDK_ROOT}/System/Library/Frameworks
+ ${IOS_SDK_ROOT}/System/Library/PrivateFrameworks
+ ${IOS_SDK_ROOT}/Developer/Library/Frameworks
+)
+
+# only search the iOS sdks, not the remainder of the host filesystem
+set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+
+# This macro lets you find executable programs on the host system
+macro (find_host_package)
+ set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+ set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+ set (IOS FALSE)
+
+ find_package(${ARGN})
+
+ set (IOS TRUE)
+ set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+ set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endmacro (find_host_package)
diff --git a/changelog b/debian/changelog
index 080f1ce..080f1ce 100644
--- a/changelog
+++ b/debian/changelog
diff --git a/control b/debian/control
index 9d9ac3f..9d9ac3f 100644
--- a/control
+++ b/debian/control
diff --git a/copyright b/debian/copyright
index cfa65e4..cfa65e4 100644
--- a/copyright
+++ b/debian/copyright
diff --git a/gbp.conf b/debian/gbp.conf
index cec628c..cec628c 100644
--- a/gbp.conf
+++ b/debian/gbp.conf
diff --git a/libsfml-audio2.5.install b/debian/libsfml-audio2.5.install
index 8a7b276..8a7b276 100644
--- a/libsfml-audio2.5.install
+++ b/debian/libsfml-audio2.5.install
diff --git a/libsfml-dev.install b/debian/libsfml-dev.install
index 2dadef7..2dadef7 100644
--- a/libsfml-dev.install
+++ b/debian/libsfml-dev.install
diff --git a/libsfml-doc.README.Debian b/debian/libsfml-doc.README.Debian
index e4a0bfb..e4a0bfb 100644
--- a/libsfml-doc.README.Debian
+++ b/debian/libsfml-doc.README.Debian
diff --git a/libsfml-doc.doc-base b/debian/libsfml-doc.doc-base
index 9a4377d..9a4377d 100644
--- a/libsfml-doc.doc-base
+++ b/debian/libsfml-doc.doc-base
diff --git a/libsfml-doc.docs b/debian/libsfml-doc.docs
index f9a1781..f9a1781 100644
--- a/libsfml-doc.docs
+++ b/debian/libsfml-doc.docs
diff --git a/libsfml-doc.examples b/debian/libsfml-doc.examples
index e39721e..e39721e 100644
--- a/libsfml-doc.examples
+++ b/debian/libsfml-doc.examples
diff --git a/libsfml-graphics2.5.install b/debian/libsfml-graphics2.5.install
index 1853f3b..1853f3b 100644
--- a/libsfml-graphics2.5.install
+++ b/debian/libsfml-graphics2.5.install
diff --git a/libsfml-network2.5.install b/debian/libsfml-network2.5.install
index b769faf..b769faf 100644
--- a/libsfml-network2.5.install
+++ b/debian/libsfml-network2.5.install
diff --git a/libsfml-system2.5.install b/debian/libsfml-system2.5.install
index 19b0317..19b0317 100644
--- a/libsfml-system2.5.install
+++ b/debian/libsfml-system2.5.install
diff --git a/libsfml-system2.5.lintian-overrides b/debian/libsfml-system2.5.lintian-overrides
index d91ea2e..d91ea2e 100644
--- a/libsfml-system2.5.lintian-overrides
+++ b/debian/libsfml-system2.5.lintian-overrides
diff --git a/libsfml-window2.5.install b/debian/libsfml-window2.5.install
index bf25e6e..bf25e6e 100644
--- a/libsfml-window2.5.install
+++ b/debian/libsfml-window2.5.install
diff --git a/missing-sources/sfml-final-clean.svg b/debian/missing-sources/sfml-final-clean.svg
index 35ec49b..35ec49b 100644
--- a/missing-sources/sfml-final-clean.svg
+++ b/debian/missing-sources/sfml-final-clean.svg
diff --git a/patches/01_remove-googleapi-css.patch b/debian/patches/01_remove-googleapi-css.patch
index 776be09..776be09 100644
--- a/patches/01_remove-googleapi-css.patch
+++ b/debian/patches/01_remove-googleapi-css.patch
diff --git a/patches/02_build-doc-once.patch b/debian/patches/02_build-doc-once.patch
index 3674295..3674295 100644
--- a/patches/02_build-doc-once.patch
+++ b/debian/patches/02_build-doc-once.patch
diff --git a/patches/06_pkgconfig-libs-private.patch b/debian/patches/06_pkgconfig-libs-private.patch
index 050453b..050453b 100644
--- a/patches/06_pkgconfig-libs-private.patch
+++ b/debian/patches/06_pkgconfig-libs-private.patch
diff --git a/patches/series b/debian/patches/series
index 8fe6881..8fe6881 100644
--- a/patches/series
+++ b/debian/patches/series
diff --git a/rules b/debian/rules
index 0064c41..0064c41 100755
--- a/rules
+++ b/debian/rules
diff --git a/source/format b/debian/source/format
index 163aaf8..163aaf8 100644
--- a/source/format
+++ b/debian/source/format
diff --git a/tests/CMakeLists.txt b/debian/tests/CMakeLists.txt
index f265619..f265619 100644
--- a/tests/CMakeLists.txt
+++ b/debian/tests/CMakeLists.txt
diff --git a/tests/build b/debian/tests/build
index efb514a..efb514a 100644
--- a/tests/build
+++ b/debian/tests/build
diff --git a/tests/cmake b/debian/tests/cmake
index 507477e..507477e 100644
--- a/tests/cmake
+++ b/debian/tests/cmake
diff --git a/tests/control b/debian/tests/control
index 4a1a5d5..4a1a5d5 100644
--- a/tests/control
+++ b/debian/tests/control
diff --git a/tests/sfml_test.cpp b/debian/tests/sfml_test.cpp
index f4840c4..f4840c4 100644
--- a/tests/sfml_test.cpp
+++ b/debian/tests/sfml_test.cpp
diff --git a/watch b/debian/watch
index 48a60a9..48a60a9 100644
--- a/watch
+++ b/debian/watch
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..123b44c
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,62 @@
+
+# find doxygen
+if(SFML_OS_MACOSX)
+ # Add some path to search doxygen in more directories.
+ set(ADDITIONAL_PATHS
+ /Developer/Applications/Doxygen.app/Contents/Resources
+ /Developer/Applications/Doxygen.app/Contents/MacOS
+ $ENV{HOME}/Applications/Doxygen.app/Contents/Resources
+ $ENV{HOME}/Applications/Doxygen.app/Contents/MacOS
+ $ENV{HOME}/Applications/Developer/Doxygen.app/Contents/Resources
+ $ENV{HOME}/Applications/Developer/Doxygen.app/Contents/MacOS)
+
+ set(CMAKE_PROGRAM_PATH ${CMAKE_PROGRAM_PATH} ${ADDITIONAL_PATHS})
+endif()
+
+find_package(Doxygen REQUIRED)
+
+# set the input and output documentation paths
+set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR})
+set(DOXYGEN_OUTPUT_DIR ${PROJECT_BINARY_DIR}/doc)
+
+# see if we can generate the CHM documentation
+if(SFML_OS_WINDOWS)
+ # if HHC is found, we can generate the CHM (compressed HTML) output
+ find_program(DOXYGEN_HHC_PROGRAM
+ NAMES hhc.exe
+ PATHS "C:/Program Files/HTML Help Workshop" "C:/Program Files (x86)/HTML Help Workshop"
+ DOC "HTML Help Compiler program")
+ if(DOXYGEN_HHC_PROGRAM)
+ set(DOXYGEN_GENERATE_HTMLHELP YES)
+ else()
+ set(DOXYGEN_GENERATE_HTMLHELP NO)
+ endif()
+else()
+ set(DOXYGEN_HHC_PROGRAM)
+ set(DOXYGEN_GENERATE_HTMLHELP NO)
+endif()
+
+# configure the source Doxyfile by copying it and replacing all @variables@
+set(DOXYGEN_CONFIGURED_INPUT ${DOXYGEN_OUTPUT_DIR}/doxyfile)
+configure_file(${DOXYGEN_INPUT_DIR}/doc/doxyfile.in ${DOXYGEN_CONFIGURED_INPUT} @ONLY)
+configure_file(${DOXYGEN_INPUT_DIR}/doc/header.html.in ${DOXYGEN_OUTPUT_DIR}/header.html @ONLY)
+
+# copy the files needed by the documentation
+configure_file(${DOXYGEN_INPUT_DIR}/doc/doxygen.css ${DOXYGEN_OUTPUT_DIR}/html/doxygen.css COPYONLY)
+
+# target setup
+add_custom_target(doc ALL
+ COMMAND ${CMAKE_COMMAND} -E echo_append "Building API Documentation..."
+ COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIGURED_INPUT}
+ COMMAND ${CMAKE_COMMAND} -E echo "Done."
+ WORKING_DIRECTORY ${DOXYGEN_INPUT_DIR})
+
+# setup install rules
+install(DIRECTORY ${DOXYGEN_OUTPUT_DIR}/html
+ DESTINATION ${SFML_MISC_INSTALL_PREFIX}/doc
+ COMPONENT doc)
+if(DOXYGEN_HHC_PROGRAM)
+ install(FILES ${DOXYGEN_OUTPUT_DIR}/sfml.chm
+ DESTINATION ${SFML_MISC_INSTALL_PREFIX}/doc
+ COMPONENT doc)
+endif()
diff --git a/doc/doxyfile.in b/doc/doxyfile.in
new file mode 100644
index 0000000..104ff75
--- /dev/null
+++ b/doc/doxyfile.in
@@ -0,0 +1,2470 @@
+# Doxyfile 1.8.14
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = SFML
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+
+#---------------------------------------------------------------------------
+# SFML specific aliases
+#---------------------------------------------------------------------------
+
+# sfplatform{platform(s)}
+# sfplatform{platform(s), header}
+#
+# Warns the user that some specific class or function is only available on
+# specific platforms.
+#
+# This shouldn't be used for incomplete implementations. It's meant for things
+# that will never appear on another platform, e.g. Android's native activity.
+#
+# If a header is given, the user is informed, that this header must be included
+# for the mentioned element to be defined.
+
+ALIASES = "sfplatform{1}=<dl class=\"attention\"><dt>Platform Limitation</dt><dd><b>This is only available on \1.</b></dd></dl>" \
+ "sfplatform{2}=<dl class=\"attention\"><dt>Platform Limitation</dt><dd><b>This is only available on \1</b> and to use it, you'll have to specifically include \2 in your code.</dd></dl>"
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = "@DOXYGEN_INPUT_DIR@/include/SFML" \
+ "@DOXYGEN_INPUT_DIR@/doc/mainpage.hpp"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.hpp
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = .git \
+ extlibs \
+ src \
+ examples \
+ install \
+ build \
+ tools \
+ cmake
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = priv
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 3
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = "@DOXYGEN_OUTPUT_DIR@/header.html"
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = "@DOXYGEN_INPUT_DIR@/doc/footer.html"
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET = "@DOXYGEN_INPUT_DIR@/doc/doxygen.css"
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "SFML Documentation"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.sfml-dev.SFML
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.sfml-dev.SFML
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = SFML
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = @DOXYGEN_GENERATE_HTMLHELP@
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE = ../SFML.chm
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION = "@DOXYGEN_HHC_PROGRAM@"
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = SFML_SYSTEM_API \
+ SFML_NETWORK_API \
+ SFML_WINDOW_API \
+ SFML_AUDIO_API \
+ SFML_GRAPHICS_API \
+ SFML_DEPRECATED \
+ SFML_DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = @DOXYGEN_OUTPUT_DIR@/SFML.tag
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/doxygen.css b/doc/doxygen.css
new file mode 100644
index 0000000..9c2fc6a
--- /dev/null
+++ b/doc/doxygen.css
@@ -0,0 +1,1450 @@
+/* The standard CSS for doxygen */
+
+/* @group Heading Levels */
+
+div.contents .textblock h1 {
+ text-align: left;
+ font-size: 20pt;
+ font-weight: normal;
+ margin-top: 1.5em;
+ padding: 0 0 0.4em 0;
+ border-bottom: 1px solid #999;
+ border-top-width: 0;
+ border-left-width: 0;
+ border-right-width: 0;
+ background-color: transparent;
+}
+
+h1.groupheader {
+ font-size: 150%;
+}
+
+.title {
+ font-size: 20pt;
+ font-weight: normal;
+ margin: 10px 2px;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+ margin-top: 2px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex {
+ margin-bottom: 1em;
+}
+
+div.qindex, div.navtab{
+ background-color: #eee;
+ border: 1px solid #999;
+ text-align: center;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+a.el {
+ padding: 1px;
+ text-decoration: none;
+ color: #577E25;
+}
+
+a.el:hover {
+ text-decoration: underline;
+}
+
+pre.fragment {
+ /*border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;*/
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-size: 10pt;
+ padding: 0.5em 1em;
+ background-color: #f5f5f5;
+ border: 1px solid #bbb;
+ border-radius(5px);
+}
+
+div.fragment {
+ /*margin: 0 0 0 5px;
+ padding: 0.5em 1em;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-size: 10pt;
+ background-color: #eef7e3;
+ border-left: 3px solid #8DC841;
+ border-right: 0;
+ border-bottom: 0;*/
+
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-size: 10pt;
+ padding: 0.5em 1em;
+ background-color: #f5f5f5;
+ border: 1px solid #bbb;
+ border-radius(5px);
+}
+
+div.line {
+ min-height: 13px;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ line-height: normal;
+}
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+
+div.ah {
+ width: 100%;
+ background-color: #eee;
+ font-weight: bold;
+ color: #000;
+ margin-bottom: 1px;
+ margin-top: 1px;
+ border: solid 1px #999;
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ width: 950px;
+ margin: 0 auto;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ display: none;
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.memberdecls td, .fieldtable tr {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+ background-color: cyan;
+ /*box-shadow: 0 0 15px cyan;*/
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memSeparator {
+ border-bottom: 1px solid #DEE4F0;
+ line-height: 1px;
+ margin: 0px;
+ padding: 0px;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
+ font-size: 80%;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #4665A2;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memtitle {
+ display: none;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ /*margin-bottom: 10px;*/
+ margin-right: 5px;
+ display: table !important;
+ width: 100%;
+}
+
+.memname {
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memname td {
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border-top: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 0px 6px 0px;
+ color: #000;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ background-color: #eee;
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+
+}
+
+.memdoc, dl.reflist dd {
+ border: 1px solid #A8B8D9;
+ padding: 6px 10px 2px 10px;
+ background-color: #FBFCFD;
+ background-color: #FFFFFF;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: bottom;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: #728DC1;
+ border-top:1px solid #5373B4;
+ border-left:1px solid #5373B4;
+ border-right:1px solid #C4CFE5;
+ border-bottom:1px solid #C4CFE5;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 3px;
+ font-size: 7pt;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+
+
+/* @end */
+
+/* these are for tree view when not used as main index */
+
+div.directory {
+ margin: 10px 0px;
+ border-top: 1px solid #bbb;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 0px;
+ vertical-align: top;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding: 5px 5px 5px 0;
+}
+
+.directory td.entry a {
+ outline:none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 3px;
+ /*border-left: 1px solid rgba(0,0,0,0.05);*/
+}
+
+.directory tr.even {
+ padding-left: 6px;
+ background-color: #F7F8FB;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ white-space: nowrap;
+ width: 100%;
+ text-align: right;
+ font-size: 9pt;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding-left: 2px;
+ padding-right: 2px;
+ color: #3D578C;
+}
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table table {
+ width: 90%;
+}
+
+.memitem table table {
+ width: auto;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ width: 100%;
+ margin-bottom: 10px;
+ border: 1px solid #A8B8D9;
+ border-spacing: 0px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #A8B8D9;
+ border-bottom: 1px solid #A8B8D9;
+ vertical-align: top;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #A8B8D9;
+ width: 100%;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable th {
+ background-color: #E2E8F2;
+ font-size: 90%;
+ color: #253555;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom: 1px solid #A8B8D9;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath {
+ display: none;
+}
+
+.navpath ul {
+ font-size: 11px;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li {
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right:15px;
+ color:#364D7C;
+}
+
+.navpath li.navelem a {
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+ color: #283A5D;
+ font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ text-decoration: none;
+}
+
+.navpath li.navelem a:hover {
+ color:#6884BD;
+}
+
+.navpath li.footer {
+ list-style-type:none;
+ float:right;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:none;
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+ font-size: 8pt;
+}
+
+
+div.summary {
+ font-size: 8pt;
+ padding-right: 5px;
+}
+
+div.summary a {
+ white-space: nowrap;
+ padding: 1px;
+ text-decoration: none;
+ color: #577E25;
+}
+
+div.summary a:hover {
+ text-decoration: underline;
+}
+
+div.ingroups {
+ font-size: 8pt;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a {
+ white-space: nowrap;
+}
+
+div.header {
+ width: 950px;
+ margin: 2em auto;
+ border-bottom: 1px solid #999;
+}
+
+dl {
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #D0C000;
+}
+
+dl.warning, dl.attention {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00D000;
+}
+
+dl.deprecated {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #505050;
+}
+
+dl.todo {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00C0E0;
+}
+
+dl.test {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #3030E0;
+}
+
+dl.bug {
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #C08050;
+}
+
+dl.section dd {
+ margin-bottom: 6px;
+}
+
+
+#projectlogo {
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+}
+
+#projectlogo img {
+ border: 0px none;
+}
+
+#projectname {
+ font: 300% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief {
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber {
+ font: 50% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea {
+ padding: 0px;
+ margin: 0px;
+ width: 100%;
+ border-bottom: 1px solid #5373B4;
+}
+
+.image {
+ text-align: center;
+}
+
+.dotgraph {
+ text-align: center;
+}
+
+.mscgraph {
+ text-align: center;
+}
+
+.caption {
+ font-weight: bold;
+}
+
+div.zoom {
+ border: 1px solid #90A5CE;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#334975;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F4F6FA;
+ border: 1px solid #D8DFEE;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #4665A2;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+@media print {
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+
+ #doc-content {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
+/* tabs.css */
+.tabs, .tabs2, .tabs3 {
+ width: 100%;
+ z-index: 101;
+ font-size: 11pt;
+ background-color: #EAF5DB;
+ border-left: 1px solid #999;
+ border-right: 1px solid #999;
+ border-bottom: 1px solid #999;
+ padding: 0;
+ margin: 0;
+}
+
+.tabs2 {
+ font-size: 10pt;
+}
+.tabs3 {
+ font-size: 9pt;
+}
+
+#navrow1 .tablist, #navrow2 .tablist, #navrow3 .tablist, #navrow4 .tablist {
+ margin: 0;
+ padding: 0;
+ display: table;
+}
+
+.tablist li {
+ float: left;
+ display: table-cell;
+ list-style: none;
+}
+
+#navrow1 {
+ border-top: 1px solid #999;
+ margin-top: 2em;
+}
+
+#navrow1 .tablist a, #navrow2 .tablist a, #navrow3 .tablist a, #navrow4 .tablist a {
+ display: block;
+ margin: 8px 0;
+ padding: 0 8px;
+ border-right: 1px solid #bbb;
+}
+
+.tablist li {
+ margin-bottom: 0 !important;
+}
+
+.tablist li.current a {
+ font-weight: bold;
+}
+
+
+
+
+
+/* SFML css */
+body {
+ font-family: 'Ubuntu', 'Arial', sans-serif;
+ line-height: 140%;
+ margin: 0 0 2em 0;
+ padding: 0;
+}
+
+#banner-container {
+ width: 100%;
+ margin-top: 25px;
+ border-top: 2px solid #999;
+ border-bottom: 2px solid #999;
+ background-color: rgb(140, 200, 65);
+}
+
+#banner {
+ width: 950px;
+ height: 60px;
+ line-height: 54px;
+ margin: 0 auto;
+ text-align: center;
+}
+
+#banner #sfml {
+ display: inline;
+ vertical-align: top;
+ margin-left: 15px;
+ color: #fff;
+ font-size: 50pt;
+ text-shadow: rgba(0, 0, 0, 0.5) 1px 1px 5px;
+}
+
+#footer-container {
+ clear: both;
+ width: 100%;
+ margin-top: 50px;
+ border-top: 1px solid #999;
+}
+
+#footer {
+ width: 950px;
+ margin: 10px auto;
+ text-align: center;
+ font-size: 10pt;
+ color: #555;
+}
+
+#footer a {
+ padding: 1px;
+ text-decoration: none;
+ color: rgb(70, 100, 30);
+}
+
+#footer a:hover {
+ text-decoration: underline;
+}
+
+div.contents, #content {
+ width: 950px;
+ margin: 0 auto;
+ padding: 0;
+}
+
+div.contents h1 {
+ color: #333;
+ padding: 0.5em 0;
+ margin-top: 30px;
+ margin-bottom: 0;
+ text-align: center;
+ font-size: 26pt;
+ font-weight: normal;
+}
+
+div.contents h2 {
+ font-size: 20pt;
+ font-weight: normal;
+ margin-top: 1.5em;
+ padding-bottom: 0.4em;
+ border-bottom: 1px solid #999;
+}
+
+div.contents h3 {
+ font-size: 16pt;
+ font-weight: normal;
+}
+
+div.contents p {
+ color: #333;
+ text-align: justify;
+}
+
+div.contents a, #content a {
+ padding: 1px;
+ text-decoration: none;
+ color: rgb(70, 100, 30);
+}
+
+div.contents a:hover, #content a:hover {
+ text-decoration: underline;
+}
+
+div.contents code {
+ font-size: 11pt;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+}
+
+div.contents pre code {
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-size: 10pt;
+ padding: 0.5em 1em;
+ background-color: #f5f5f5;
+ border: 1px solid #bbb;
+}
+
+div.contents ul {
+ list-style-type: square;
+ list-style-position: outside;
+ margin: 0 0 0 1.5em;
+ padding: 0;
+}
+
+div.contents ul li {
+ color: #333;
+ margin: 0 0 0.3em 0;
+}
+
+
+.icon {
+ font-family: Arial, Helvetica;
+ font-weight: bold;
+ font-size: 12px;
+ height: 14px;
+ width: 16px;
+ display: inline-block;
+ background-color: #8cc445;
+ color: white;
+ text-align: center;
+ border-radius: 4px;
+ margin-left: 2px;
+ margin-right: 2px;
+ line-height: normal;
+}
+
+.icona {
+ width: 24px;
+ height: 22px;
+ display: inline-block;
+}
+
+.iconfopen {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2folderopen.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.iconfclosed {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2folderclosed.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.icondoc {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2doc.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+/* tooltip related style info */
+
+.ttc {
+ position: absolute;
+ display: none;
+}
+
+#powerTip {
+ cursor: default;
+ white-space: nowrap;
+ background-color: white;
+ border: 1px solid gray;
+ border-radius: 4px 4px 4px 4px;
+ box-shadow: 1px 1px 7px gray;
+ display: none;
+ font-size: smaller;
+ max-width: 80%;
+ opacity: 0.9;
+ padding: 1ex 1em 1em;
+ position: absolute;
+ z-index: 2147483647;
+}
+
+#powerTip div.ttdoc {
+ color: grey;
+ font-style: italic;
+}
+
+#powerTip div.ttname a {
+ font-weight: bold;
+}
+
+#powerTip div.ttname {
+ font-weight: bold;
+}
+
+#powerTip div.ttdeci {
+ color: #006318;
+}
+
+#powerTip div {
+ margin: 0px;
+ padding: 0px;
+ font: 12px/16px Roboto,sans-serif;
+}
+
+#powerTip:before, #powerTip:after {
+ content: "";
+ position: absolute;
+ margin: 0px;
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.w:after, #powerTip.w:before,
+#powerTip.e:after, #powerTip.e:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.nw:after, #powerTip.nw:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+}
+
+#powerTip.n:after, #powerTip.s:after,
+#powerTip.w:after, #powerTip.e:after,
+#powerTip.nw:after, #powerTip.ne:after,
+#powerTip.sw:after, #powerTip.se:after {
+ border-color: rgba(255, 255, 255, 0);
+}
+
+#powerTip.n:before, #powerTip.s:before,
+#powerTip.w:before, #powerTip.e:before,
+#powerTip.nw:before, #powerTip.ne:before,
+#powerTip.sw:before, #powerTip.se:before {
+ border-color: rgba(128, 128, 128, 0);
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.nw:after, #powerTip.nw:before {
+ top: 100%;
+}
+
+#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {
+ border-top-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+#powerTip.n:before {
+ border-top-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+#powerTip.n:after, #powerTip.n:before {
+ left: 50%;
+}
+
+#powerTip.nw:after, #powerTip.nw:before {
+ right: 14px;
+}
+
+#powerTip.ne:after, #powerTip.ne:before {
+ left: 14px;
+}
+
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ bottom: 100%;
+}
+
+#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {
+ border-bottom-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+
+#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {
+ border-bottom-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+
+#powerTip.s:after, #powerTip.s:before {
+ left: 50%;
+}
+
+#powerTip.sw:after, #powerTip.sw:before {
+ right: 14px;
+}
+
+#powerTip.se:after, #powerTip.se:before {
+ left: 14px;
+}
+
+#powerTip.e:after, #powerTip.e:before {
+ left: 100%;
+}
+#powerTip.e:after {
+ border-left-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.e:before {
+ border-left-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+#powerTip.w:after, #powerTip.w:before {
+ right: 100%;
+}
+#powerTip.w:after {
+ border-right-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.w:before {
+ border-right-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+.arrow {
+ cursor: pointer;
+}
diff --git a/doc/footer.html b/doc/footer.html
new file mode 100644
index 0000000..c9cd937
--- /dev/null
+++ b/doc/footer.html
@@ -0,0 +1,10 @@
+ </div>
+ <div id="footer-container">
+ <div id="footer">
+ SFML is licensed under the terms and conditions of the <a href="https://www.sfml-dev.org/license.php">zlib/png license</a>.<br>
+ Copyright &copy; Laurent Gomila &nbsp;::&nbsp;
+ Documentation generated by <a href="http://www.doxygen.org/" title="doxygen website">doxygen</a> &nbsp;::&nbsp;
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/doc/header.html.in b/doc/header.html.in
new file mode 100644
index 0000000..cc42ea2
--- /dev/null
+++ b/doc/header.html.in
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>SFML - Simple and Fast Multimedia Library</title>
+ <meta http-equiv="Content-Type" content="text/html;"/>
+ <meta charset="utf-8"/>
+ <!--<link rel='stylesheet' type='text/css' href="https://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic"/>-->
+ <link rel="stylesheet" type="text/css" href="doxygen.css" title="default" media="screen,print" />
+ <script type="text/javascript" src="jquery.js"></script>
+ <script type="text/javascript" src="dynsections.js"></script>
+ </head>
+ <body>
+ <div id="banner-container">
+ <div id="banner">
+ <span id="sfml">SFML @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</span>
+ </div>
+ </div>
+ <div id="content">
diff --git a/doc/mainpage.hpp b/doc/mainpage.hpp
new file mode 100644
index 0000000..16f2c43
--- /dev/null
+++ b/doc/mainpage.hpp
@@ -0,0 +1,71 @@
+////////////////////////////////////////////////////////////
+/// \mainpage
+///
+/// \section welcome Welcome
+/// Welcome to the official SFML documentation. Here you will find a detailed
+/// view of all the SFML <a href="./annotated.php">classes</a> and functions. <br/>
+/// If you are looking for tutorials, you can visit the official website
+/// at <a href="https://www.sfml-dev.org/">www.sfml-dev.org</a>.
+///
+/// \section example Short example
+/// Here is a short example, to show you how simple it is to use SFML:
+///
+/// \code
+///
+/// #include <SFML/Audio.hpp>
+/// #include <SFML/Graphics.hpp>
+///
+/// int main()
+/// {
+/// // Create the main window
+/// sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
+///
+/// // Load a sprite to display
+/// sf::Texture texture;
+/// if (!texture.loadFromFile("cute_image.jpg"))
+/// return EXIT_FAILURE;
+/// sf::Sprite sprite(texture);
+///
+/// // Create a graphical text to display
+/// sf::Font font;
+/// if (!font.loadFromFile("arial.ttf"))
+/// return EXIT_FAILURE;
+/// sf::Text text("Hello SFML", font, 50);
+///
+/// // Load a music to play
+/// sf::Music music;
+/// if (!music.openFromFile("nice_music.ogg"))
+/// return EXIT_FAILURE;
+///
+/// // Play the music
+/// music.play();
+///
+/// // Start the game loop
+/// while (window.isOpen())
+/// {
+/// // Process events
+/// sf::Event event;
+/// while (window.pollEvent(event))
+/// {
+/// // Close window: exit
+/// if (event.type == sf::Event::Closed)
+/// window.close();
+/// }
+///
+/// // Clear screen
+/// window.clear();
+///
+/// // Draw the sprite
+/// window.draw(sprite);
+///
+/// // Draw the string
+/// window.draw(text);
+///
+/// // Update the window
+/// window.display();
+/// }
+///
+/// return EXIT_SUCCESS;
+/// }
+/// \endcode
+////////////////////////////////////////////////////////////
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..a13f585
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,38 @@
+
+# iOS Demo
+if(SFML_OS_IOS)
+ add_subdirectory(iOS)
+else(SFML_OS_IOS)
+
+ # add the examples subdirectories
+ if(SFML_BUILD_NETWORK)
+ add_subdirectory(ftp)
+ add_subdirectory(sockets)
+ endif()
+ if(SFML_BUILD_NETWORK AND SFML_BUILD_AUDIO)
+ add_subdirectory(voip)
+ endif()
+ if(SFML_BUILD_AUDIO)
+ add_subdirectory(sound)
+ add_subdirectory(sound_capture)
+ endif()
+ if(SFML_BUILD_WINDOW)
+ add_subdirectory(window)
+ endif()
+ if(SFML_BUILD_GRAPHICS)
+ add_subdirectory(joystick)
+ add_subdirectory(opengl)
+ add_subdirectory(shader)
+ add_subdirectory(island)
+ if(SFML_OS_WINDOWS)
+ add_subdirectory(win32)
+ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
+ add_subdirectory(X11)
+ elseif(SFML_OS_MACOSX)
+ add_subdirectory(cocoa)
+ endif()
+ endif()
+ if(SFML_BUILD_GRAPHICS AND SFML_BUILD_AUDIO)
+ add_subdirectory(pong)
+ endif()
+endif(SFML_OS_IOS) \ No newline at end of file
diff --git a/examples/X11/CMakeLists.txt b/examples/X11/CMakeLists.txt
new file mode 100644
index 0000000..27509a6
--- /dev/null
+++ b/examples/X11/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/X11)
+
+# all source files
+set(SRC ${SRCROOT}/X11.cpp)
+
+# define the X11 target
+sfml_add_example(X11Example GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-window OpenGL X11)
diff --git a/examples/X11/X11.cpp b/examples/X11/X11.cpp
new file mode 100644
index 0000000..746bf07
--- /dev/null
+++ b/examples/X11/X11.cpp
@@ -0,0 +1,217 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/OpenGL.hpp>
+#include <X11/Xlib.h>
+#include <iostream>
+#include <cmath>
+
+
+////////////////////////////////////////////////////////////
+/// Initialize OpenGL states into the specified view
+///
+/// \param Window Target window to initialize
+///
+////////////////////////////////////////////////////////////
+void initialize(sf::Window& window)
+{
+ // Activate the window
+ window.setActive();
+
+ // Setup OpenGL states
+ // Set color and depth clear value
+ glClearDepth(1.f);
+ glClearColor(0.f, 0.5f, 0.5f, 0.f);
+
+ // Enable Z-buffer read and write
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+
+ // Setup a perspective projection
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ static const double pi = 3.141592654;
+ GLdouble extent = std::tan(90.0 * pi / 360.0);
+ glFrustum(-extent, extent, -extent, extent, 1.0, 500.0);
+
+ // Enable position and texture coordinates vertex components
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+}
+
+////////////////////////////////////////////////////////////
+/// Draw the OpenGL scene (a rotating cube) into
+/// the specified view
+///
+/// \param window Target window for rendering
+/// \param elapsedTime Time elapsed since the last draw
+///
+////////////////////////////////////////////////////////////
+void draw(sf::Window& window, float elapsedTime)
+{
+ // Activate the window
+ window.setActive();
+
+ // Clear color and depth buffers
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Apply some transformations
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.f, 0.f, -200.f);
+ glRotatef(elapsedTime * 10.f, 1.f, 0.f, 0.f);
+ glRotatef(elapsedTime * 6.f, 0.f, 1.f, 0.f);
+ glRotatef(elapsedTime * 18.f, 0.f, 0.f, 1.f);
+
+ // Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
+ static const GLfloat cube[] =
+ {
+ // positions // colors
+ -50, -50, -50, 1, 1, 0,
+ -50, 50, -50, 1, 1, 0,
+ -50, -50, 50, 1, 1, 0,
+ -50, -50, 50, 1, 1, 0,
+ -50, 50, -50, 1, 1, 0,
+ -50, 50, 50, 1, 1, 0,
+
+ 50, -50, -50, 1, 1, 0,
+ 50, 50, -50, 1, 1, 0,
+ 50, -50, 50, 1, 1, 0,
+ 50, -50, 50, 1, 1, 0,
+ 50, 50, -50, 1, 1, 0,
+ 50, 50, 50, 1, 1, 0,
+
+ -50, -50, -50, 1, 0, 1,
+ 50, -50, -50, 1, 0, 1,
+ -50, -50, 50, 1, 0, 1,
+ -50, -50, 50, 1, 0, 1,
+ 50, -50, -50, 1, 0, 1,
+ 50, -50, 50, 1, 0, 1,
+
+ -50, 50, -50, 1, 0, 1,
+ 50, 50, -50, 1, 0, 1,
+ -50, 50, 50, 1, 0, 1,
+ -50, 50, 50, 1, 0, 1,
+ 50, 50, -50, 1, 0, 1,
+ 50, 50, 50, 1, 0, 1,
+
+ -50, -50, -50, 0, 1, 1,
+ 50, -50, -50, 0, 1, 1,
+ -50, 50, -50, 0, 1, 1,
+ -50, 50, -50, 0, 1, 1,
+ 50, -50, -50, 0, 1, 1,
+ 50, 50, -50, 0, 1, 1,
+
+ -50, -50, 50, 0, 1, 1,
+ 50, -50, 50, 0, 1, 1,
+ -50, 50, 50, 0, 1, 1,
+ -50, 50, 50, 0, 1, 1,
+ 50, -50, 50, 0, 1, 1,
+ 50, 50, 50, 0, 1, 1
+ };
+
+ // Draw the cube
+ glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), cube);
+ glColorPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), cube + 3);
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Error code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Open a connection with the X server
+ Display* display = XOpenDisplay(NULL);
+ if (!display)
+ return EXIT_FAILURE;
+
+ // Get the default screen
+ int screen = DefaultScreen(display);
+
+ // Let's create the main window
+ XSetWindowAttributes attributes;
+ attributes.background_pixel = BlackPixel(display, screen);
+ attributes.event_mask = KeyPressMask;
+ Window window = XCreateWindow(display, RootWindow(display, screen),
+ 0, 0, 650, 330, 0,
+ DefaultDepth(display, screen),
+ InputOutput,
+ DefaultVisual(display, screen),
+ CWBackPixel | CWEventMask, &attributes);
+ if (!window)
+ return EXIT_FAILURE;
+
+ // Set the window's name
+ XStoreName(display, window , "SFML Window");
+
+ // Let's create the windows which will serve as containers for our SFML views
+ Window view1 = XCreateWindow(display, window,
+ 10, 10, 310, 310, 0,
+ DefaultDepth(display, screen),
+ InputOutput,
+ DefaultVisual(display, screen),
+ 0, NULL);
+ Window view2 = XCreateWindow(display, window,
+ 330, 10, 310, 310, 0,
+ DefaultDepth(display, screen),
+ InputOutput,
+ DefaultVisual(display, screen),
+ 0, NULL);
+
+ // Show our windows
+ XMapWindow(display, window);
+ XFlush(display);
+
+ // Create our SFML views
+ sf::Window sfmlView1(view1);
+ sf::Window sfmlView2(view2);
+
+ // Create a clock for measuring elapsed time
+ sf::Clock clock;
+
+ // Initialize our views
+ initialize(sfmlView1);
+ initialize(sfmlView2);
+
+ // Start the event loop
+ bool running = true;
+ while (running)
+ {
+ while (XPending(display))
+ {
+ // Get the next pending event
+ XEvent event;
+ XNextEvent(display, &event);
+
+ // Process it
+ switch (event.type)
+ {
+ // Any key is pressed: quit
+ case KeyPress:
+ running = false;
+ break;
+ }
+ }
+
+ // Draw something into our views
+ draw(sfmlView1, clock.getElapsedTime().asSeconds());
+ draw(sfmlView2, clock.getElapsedTime().asSeconds() * 0.3f);
+
+ // Display the views on screen
+ sfmlView1.display();
+ sfmlView2.display();
+ }
+
+ // Close the display
+ XCloseDisplay(display);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/android/.gitignore b/examples/android/.gitignore
new file mode 100644
index 0000000..a76e965
--- /dev/null
+++ b/examples/android/.gitignore
@@ -0,0 +1,8 @@
+local.properties
+.idea
+.gradle
+build
+android.iml
+app/build
+app/.externalNativeBuild
+app/src/main/obj
diff --git a/examples/android/app/app.iml b/examples/android/app/app.iml
new file mode 100644
index 0000000..232000a
--- /dev/null
+++ b/examples/android/app/app.iml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="android-gradle" name="Android-Gradle">
+ <configuration>
+ <option name="GRADLE_PROJECT_PATH" value=":app" />
+ </configuration>
+ </facet>
+ <facet type="native-android-gradle" name="Native-Android-Gradle">
+ <configuration>
+ <option name="SELECTED_BUILD_VARIANT" value="debug" />
+ </configuration>
+ </facet>
+ <facet type="android" name="Android">
+ <configuration>
+ <option name="SELECTED_BUILD_VARIANT" value="debug" />
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
+ <afterSyncTasks>
+ <task>generateDebugSources</task>
+ </afterSyncTasks>
+ <option name="ALLOW_USER_CONFIGURATION" value="false" />
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+ </configuration>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
+ <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
+ <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/main/cpp" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/jni" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes-jar" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndkBuild" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/splits-support" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
+ <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
+ </content>
+ <orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/examples/android/app/build.gradle b/examples/android/app/build.gradle
new file mode 100644
index 0000000..b1fb031
--- /dev/null
+++ b/examples/android/app/build.gradle
@@ -0,0 +1,39 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 27
+ defaultConfig {
+ applicationId "org.sfmldev.android"
+ minSdkVersion 14
+ targetSdkVersion 19
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ ndkBuild {
+ // cppFlags "-std=c++14 -frtti -fexceptions"
+ }
+
+ }
+ ndk {
+ abiFilters 'armeabi-v7a'
+ }
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ ndkBuild {
+ path "src/main/jni/Android.mk"
+
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/examples/android/app/proguard-rules.pro b/examples/android/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/examples/android/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/examples/android/app/src/main/AndroidManifest.xml b/examples/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..20fbbe5
--- /dev/null
+++ b/examples/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.sfmldev.android"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-feature android:glEsVersion="0x00010001" />
+
+ <uses-sdk android:minSdkVersion="14"
+ android:targetSdkVersion="19" />
+
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application android:label="@string/app_name"
+ android:icon="@drawable/sfml_logo"
+ android:hasCode="false"
+ android:allowBackup="true">
+
+ <activity android:name="android.app.NativeActivity"
+ android:label="@string/app_name"
+ android:icon="@drawable/sfml_logo"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+
+ <meta-data android:name="android.app.lib_name" android:value="sfml-activity-d" />
+ <meta-data android:name="sfml.app.lib_name" android:value="sfml-example" />
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/examples/android/app/src/main/assets/image.png b/examples/android/app/src/main/assets/image.png
new file mode 100644
index 0000000..29ba010
--- /dev/null
+++ b/examples/android/app/src/main/assets/image.png
Binary files differ
diff --git a/examples/android/app/src/main/assets/sansation.ttf b/examples/android/app/src/main/assets/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/android/app/src/main/assets/sansation.ttf
Binary files differ
diff --git a/examples/android/app/src/main/jni/Android.mk b/examples/android/app/src/main/jni/Android.mk
new file mode 100644
index 0000000..e848c11
--- /dev/null
+++ b/examples/android/app/src/main/jni/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sfml-example
+
+LOCAL_SRC_FILES := main.cpp
+
+LOCAL_SHARED_LIBRARIES := sfml-system-d
+LOCAL_SHARED_LIBRARIES += sfml-window-d
+LOCAL_SHARED_LIBRARIES += sfml-graphics-d
+LOCAL_SHARED_LIBRARIES += sfml-audio-d
+LOCAL_SHARED_LIBRARIES += sfml-network-d
+LOCAL_SHARED_LIBRARIES += sfml-activity-d
+LOCAL_SHARED_LIBRARIES += openal
+LOCAL_WHOLE_STATIC_LIBRARIES := sfml-main-d
+
+include $(BUILD_SHARED_LIBRARY)
+
+$(call import-module,third_party/sfml)
diff --git a/examples/android/app/src/main/jni/Application.mk b/examples/android/app/src/main/jni/Application.mk
new file mode 100644
index 0000000..df10f28
--- /dev/null
+++ b/examples/android/app/src/main/jni/Application.mk
@@ -0,0 +1,8 @@
+NDK_TOOLCHAIN_VERSION := 4.9
+APP_PLATFORM := android-14
+# APP_STL has to match CMAKE_ANDROID_STL_TYPE
+APP_STL := c++_static
+APP_ABI := armeabi-v7a
+APP_MODULES := sfml-activity-d sfml-example
+APP_OPTIM := debug
+APP_CFLAG := -g -ggdb -O0 \ No newline at end of file
diff --git a/examples/android/app/src/main/jni/main.cpp b/examples/android/app/src/main/jni/main.cpp
new file mode 100644
index 0000000..edf67b4
--- /dev/null
+++ b/examples/android/app/src/main/jni/main.cpp
@@ -0,0 +1,176 @@
+#include <SFML/System.hpp>
+#include <SFML/Window.hpp>
+#include <SFML/Graphics.hpp>
+#include <SFML/Audio.hpp>
+#include <SFML/Network.hpp>
+
+// Do we want to showcase direct JNI/NDK interaction?
+// Undefine this to get real cross-platform code.
+// Uncomment this to try JNI access; this seems to be broken in latest NDKs
+//#define USE_JNI
+
+#if defined(USE_JNI)
+// These headers are only needed for direct NDK/JDK interaction
+#include <jni.h>
+#include <android/native_activity.h>
+
+// Since we want to get the native activity from SFML, we'll have to use an
+// extra header here:
+#include <SFML/System/NativeActivity.hpp>
+
+// NDK/JNI sub example - call Java code from native code
+int vibrate(sf::Time duration)
+{
+ // First we'll need the native activity handle
+ ANativeActivity *activity = sf::getNativeActivity();
+
+ // Retrieve the JVM and JNI environment
+ JavaVM* vm = activity->vm;
+ JNIEnv* env = activity->env;
+
+ // First, attach this thread to the main thread
+ JavaVMAttachArgs attachargs;
+ attachargs.version = JNI_VERSION_1_6;
+ attachargs.name = "NativeThread";
+ attachargs.group = NULL;
+ jint res = vm->AttachCurrentThread(&env, &attachargs);
+
+ if (res == JNI_ERR)
+ return EXIT_FAILURE;
+
+ // Retrieve class information
+ jclass natact = env->FindClass("android/app/NativeActivity");
+ jclass context = env->FindClass("android/content/Context");
+
+ // Get the value of a constant
+ jfieldID fid = env->GetStaticFieldID(context, "VIBRATOR_SERVICE", "Ljava/lang/String;");
+ jobject svcstr = env->GetStaticObjectField(context, fid);
+
+ // Get the method 'getSystemService' and call it
+ jmethodID getss = env->GetMethodID(natact, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+ jobject vib_obj = env->CallObjectMethod(activity->clazz, getss, svcstr);
+
+ // Get the object's class and retrieve the member name
+ jclass vib_cls = env->GetObjectClass(vib_obj);
+ jmethodID vibrate = env->GetMethodID(vib_cls, "vibrate", "(J)V");
+
+ // Determine the timeframe
+ jlong length = duration.asMilliseconds();
+
+ // Bzzz!
+ env->CallVoidMethod(vib_obj, vibrate, length);
+
+ // Free references
+ env->DeleteLocalRef(vib_obj);
+ env->DeleteLocalRef(vib_cls);
+ env->DeleteLocalRef(svcstr);
+ env->DeleteLocalRef(context);
+ env->DeleteLocalRef(natact);
+
+ // Detach thread again
+ vm->DetachCurrentThread();
+}
+#endif
+
+// This is the actual Android example. You don't have to write any platform
+// specific code, unless you want to use things not directly exposed.
+// ('vibrate()' in this example; undefine 'USE_JNI' above to disable it)
+int main(int argc, char *argv[])
+{
+ sf::VideoMode screen(sf::VideoMode::getDesktopMode());
+
+ sf::RenderWindow window(screen, "");
+ window.setFramerateLimit(30);
+
+ sf::Texture texture;
+ if(!texture.loadFromFile("image.png"))
+ return EXIT_FAILURE;
+
+ sf::Sprite image(texture);
+ image.setPosition(screen.width / 2, screen.height / 2);
+ image.setOrigin(texture.getSize().x/2, texture.getSize().y/2);
+
+ sf::Font font;
+ if (!font.loadFromFile("sansation.ttf"))
+ return EXIT_FAILURE;
+
+ sf::Text text("Tap anywhere to move the logo.", font, 64);
+ text.setFillColor(sf::Color::Black);
+ text.setPosition(10, 10);
+
+ // Loading canary.wav fails for me for now; haven't had time to test why
+
+ /*sf::Music music;
+ if(!music.openFromFile("canary.wav"))
+ return EXIT_FAILURE;
+
+ music.play();*/
+
+ sf::View view = window.getDefaultView();
+
+ sf::Color background = sf::Color::White;
+
+ // We shouldn't try drawing to the screen while in background
+ // so we'll have to track that. You can do minor background
+ // work, but keep battery life in mind.
+ bool active = true;
+
+ while (window.isOpen())
+ {
+ sf::Event event;
+
+ while (active ? window.pollEvent(event) : window.waitEvent(event))
+ {
+ switch (event.type)
+ {
+ case sf::Event::Closed:
+ window.close();
+ break;
+ case sf::Event::KeyPressed:
+ if (event.key.code == sf::Keyboard::Escape)
+ window.close();
+ break;
+ case sf::Event::Resized:
+ view.setSize(event.size.width, event.size.height);
+ view.setCenter(event.size.width/2, event.size.height/2);
+ window.setView(view);
+ break;
+ case sf::Event::LostFocus:
+ background = sf::Color::Black;
+ break;
+ case sf::Event::GainedFocus:
+ background = sf::Color::White;
+ break;
+
+ // On Android MouseLeft/MouseEntered are (for now) triggered,
+ // whenever the app loses or gains focus.
+ case sf::Event::MouseLeft:
+ active = false;
+ break;
+ case sf::Event::MouseEntered:
+ active = true;
+ break;
+ case sf::Event::TouchBegan:
+ if (event.touch.finger == 0)
+ {
+ image.setPosition(event.touch.x, event.touch.y);
+#if defined(USE_JNI)
+ vibrate(sf::milliseconds(10));
+#endif
+ }
+ break;
+ }
+ }
+
+ if (active)
+ {
+ window.clear(background);
+ window.draw(image);
+ window.draw(text);
+ window.display();
+ }
+ else {
+ sf::sleep(sf::milliseconds(100));
+ }
+ }
+}
diff --git a/examples/android/app/src/main/res/drawable-hdpi/sfml_logo.png b/examples/android/app/src/main/res/drawable-hdpi/sfml_logo.png
new file mode 100644
index 0000000..7bae333
--- /dev/null
+++ b/examples/android/app/src/main/res/drawable-hdpi/sfml_logo.png
Binary files differ
diff --git a/examples/android/app/src/main/res/drawable-ldpi/sfml_logo.png b/examples/android/app/src/main/res/drawable-ldpi/sfml_logo.png
new file mode 100644
index 0000000..6552c56
--- /dev/null
+++ b/examples/android/app/src/main/res/drawable-ldpi/sfml_logo.png
Binary files differ
diff --git a/examples/android/app/src/main/res/drawable-mdpi/sfml_logo.png b/examples/android/app/src/main/res/drawable-mdpi/sfml_logo.png
new file mode 100644
index 0000000..8778688
--- /dev/null
+++ b/examples/android/app/src/main/res/drawable-mdpi/sfml_logo.png
Binary files differ
diff --git a/examples/android/app/src/main/res/drawable-xhdpi/sfml_logo.png b/examples/android/app/src/main/res/drawable-xhdpi/sfml_logo.png
new file mode 100644
index 0000000..ff0d3aa
--- /dev/null
+++ b/examples/android/app/src/main/res/drawable-xhdpi/sfml_logo.png
Binary files differ
diff --git a/examples/android/app/src/main/res/drawable-xxhdpi/sfml_logo.png b/examples/android/app/src/main/res/drawable-xxhdpi/sfml_logo.png
new file mode 100644
index 0000000..8a66e84
--- /dev/null
+++ b/examples/android/app/src/main/res/drawable-xxhdpi/sfml_logo.png
Binary files differ
diff --git a/examples/android/app/src/main/res/values/strings.xml b/examples/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..acedde6
--- /dev/null
+++ b/examples/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">SFML</string>
+</resources>
diff --git a/examples/android/build.gradle b/examples/android/build.gradle
new file mode 100644
index 0000000..56292ed
--- /dev/null
+++ b/examples/android/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.0'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/examples/android/gradle.properties b/examples/android/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/examples/android/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/examples/android/settings.gradle b/examples/android/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/examples/android/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/examples/cocoa/CMakeLists.txt b/examples/cocoa/CMakeLists.txt
new file mode 100644
index 0000000..dfa46be
--- /dev/null
+++ b/examples/cocoa/CMakeLists.txt
@@ -0,0 +1,61 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/cocoa)
+
+# Usage: compile_xib(INPUT path/to/file.xib OUTPUT path/to/file.nib)
+function(compile_xib)
+ cmake_parse_arguments(THIS "" "INPUT;OUTPUT" "" ${ARGN})
+ if (NOT THIS_INPUT)
+ message(FATAL_ERROR "Missing required argument INPUT in call to compile_xib()")
+ endif()
+
+ if (NOT THIS_OUTPUT)
+ message(FATAL_ERROR "Missing required argument OUTPUT in call to compile_xib()")
+ endif()
+
+ if (NOT DEFINED IBTOOL)
+ find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
+ endif()
+ if(NOT IBTOOL)
+ message(FATAL_ERROR "ibtool is required to compile .xib files but wasn't found.")
+ endif()
+
+ # Default args taken from Xcode 9 when it generates a nib from a xib
+ set(DEFAULT_ARGS --errors --warnings --notices --module cocoa --auto-activate-custom-fonts --target-device mac --output-format human-readable-text)
+
+ add_custom_command(OUTPUT "${THIS_OUTPUT}"
+ COMMAND "${IBTOOL}" ${DEFAULT_ARGS} "${THIS_INPUT}" --compile "${THIS_OUTPUT}"
+ DEPENDS "${THIS_INPUT}"
+ COMMENT "Generating ${THIS_OUTPUT}"
+ VERBATIM)
+endfunction()
+
+# all source files
+set(SRC ${SRCROOT}/CocoaAppDelegate.h
+ ${SRCROOT}/CocoaAppDelegate.mm
+ ${SRCROOT}/NSString+stdstring.h
+ ${SRCROOT}/NSString+stdstring.mm
+ ${SRCROOT}/main.m)
+
+compile_xib(INPUT "${SRCROOT}/MainMenu.xib" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/MainMenu.nib")
+
+# all resource files
+set(RESOURCES ${SRCROOT}/resources/logo.png
+ ${SRCROOT}/resources/icon.icns
+ ${SRCROOT}/resources/sansation.ttf
+ ${SRCROOT}/resources/blue.png
+ ${SRCROOT}/resources/green.png
+ ${SRCROOT}/resources/red.png
+ ${SRCROOT}/resources/Credits.rtf
+ ${CMAKE_CURRENT_BINARY_DIR}/MainMenu.nib)
+set_source_files_properties(${RESOURCES} PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
+
+# define the cocoa target and customize it
+sfml_add_example(cocoa
+ SOURCES ${SRC}
+ BUNDLE_RESOURCES ${RESOURCES}
+ DEPENDS sfml-system sfml-window sfml-graphics)
+set_target_properties(cocoa PROPERTIES
+ MACOSX_BUNDLE TRUE
+ MACOSX_BUNDLE_INFO_PLIST ${SRCROOT}/resources/Cocoa-Info.plist)
+target_link_libraries(cocoa PRIVATE "-framework Cocoa" "-framework Foundation" sfml-graphics)
diff --git a/examples/cocoa/CocoaAppDelegate.h b/examples/cocoa/CocoaAppDelegate.h
new file mode 100644
index 0000000..9dab138
--- /dev/null
+++ b/examples/cocoa/CocoaAppDelegate.h
@@ -0,0 +1,71 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+#import <Cocoa/Cocoa.h>
+#import <SFML/Graphics.hpp>
+
+/*
+ * NB: We need pointers for C++ objects fields in Obj-C interface !
+ * The recommended way is to use PIMPL idiom.
+ *
+ * It's elegant. Moreover, we do no constrain
+ * other file including this one to be Obj-C++.
+ */
+
+struct SFMLmainWindow;
+
+@interface CocoaAppDelegate : NSObject <NSApplicationDelegate>
+{
+@private
+ NSWindow* m_window;
+ NSView* m_sfmlView;
+ NSTextField* m_textField;
+ SFMLmainWindow* m_mainWindow;
+ NSTimer* m_renderTimer;
+ BOOL m_visible;
+ BOOL m_initialized;
+}
+
+@property (retain) IBOutlet NSWindow* window;
+@property (assign) IBOutlet NSView* sfmlView;
+@property (assign) IBOutlet NSTextField* textField;
+
+-(IBAction)colorChanged:(NSPopUpButton*)sender;
+-(IBAction)rotationChanged:(NSSlider*)sender;
+-(IBAction)visibleChanged:(NSButton*)sender;
+-(IBAction)textChanged:(NSTextField*)sender;
+-(IBAction)updateText:(NSButton*)sender;
+
+@end
+
+/*
+ * This interface is used to prevent the system alert produced when the SFML view
+ * has the focus and the user press a key.
+ */
+@interface SilentWindow : NSWindow
+
+-(void)keyDown:(NSEvent*)theEvent;
+
+@end
diff --git a/examples/cocoa/CocoaAppDelegate.mm b/examples/cocoa/CocoaAppDelegate.mm
new file mode 100644
index 0000000..a58ca87
--- /dev/null
+++ b/examples/cocoa/CocoaAppDelegate.mm
@@ -0,0 +1,236 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+#import "CocoaAppDelegate.h"
+#import "NSString+stdstring.h"
+
+// These define are used for converting the color of the NSPopUpButton
+#define BLUE @"Blue"
+#define GREEN @"Green"
+#define RED @"Red"
+
+// Our PIMPL
+struct SFMLmainWindow
+{
+ SFMLmainWindow(sf::WindowHandle win) :
+ renderWindow(win),
+ background(sf::Color::Blue)
+ {
+ std::string resPath = [[[NSBundle mainBundle] resourcePath] tostdstring];
+ if (!logo.loadFromFile(resPath + "/logo.png"))
+ NSLog(@"Couldn't load the logo image");
+
+ logo.setSmooth(true);
+
+ sprite.setTexture(logo, true);
+ sf::FloatRect rect = sprite.getLocalBounds();
+ sf::Vector2f size(rect.width, rect.height);
+ sprite.setOrigin(size / 2.f);
+ sprite.scale(0.3, 0.3);
+
+ unsigned int ww = renderWindow.getSize().x;
+ unsigned int wh = renderWindow.getSize().y;
+ sprite.setPosition(sf::Vector2f(ww, wh) / 2.f);
+
+ if (!font.loadFromFile(resPath + "/sansation.ttf"))
+ NSLog(@"Couldn't load the font");
+
+ text.setFillColor(sf::Color::White);
+ text.setFont(font);
+ }
+
+ sf::RenderWindow renderWindow;
+ sf::Font font;
+ sf::Text text;
+ sf::Texture logo;
+ sf::Sprite sprite;
+ sf::Color background;
+};
+
+// Private stuff
+@interface CocoaAppDelegate ()
+
+@property (assign) SFMLmainWindow* mainWindow;
+@property (retain) NSTimer* renderTimer;
+@property (assign) BOOL visible;
+
+@property (assign) BOOL initialized;
+
+-(void)renderMainWindow:(NSTimer*)aTimer;
+
+@end
+
+
+// Finally, the implementation
+@implementation CocoaAppDelegate
+
+@synthesize window = m_window;
+@synthesize sfmlView = m_sfmlView;
+@synthesize textField = m_textField;
+
+@synthesize mainWindow = m_mainWindow;
+@synthesize renderTimer = m_renderTimer;
+@synthesize visible = m_visible;
+
+@synthesize initialized = m_initialized;
+
+- (id)init
+{
+ self = [super init];
+ if (self)
+ self.initialized = NO;
+
+ return self;
+}
+
+-(void)applicationDidFinishLaunching:(NSNotification*)aNotification
+{
+ (void)aNotification;
+
+ if (!self.initialized)
+ {
+ // Init the SFML render area.
+ self.mainWindow = new SFMLmainWindow(self.sfmlView);
+ self.mainWindow->text.setString([self.textField.stringValue tostdwstring]);
+ self.visible = YES;
+
+ // Launch the timer to periodically display our stuff into the Cocoa view.
+ self.renderTimer = [NSTimer timerWithTimeInterval:1.f/60.f
+ target:self
+ selector:@selector(renderMainWindow:)
+ userInfo:nil
+ repeats:YES];
+ [[NSRunLoop mainRunLoop] addTimer:self.renderTimer
+ forMode:NSDefaultRunLoopMode];
+ [[NSRunLoop mainRunLoop] addTimer:self.renderTimer
+ forMode:NSEventTrackingRunLoopMode];
+ /*
+ * This is really some ugly code but in order to have the timer fired
+ * periodically we need to add it to the two above runloop mode.
+ *
+ * The default mode allows timer firing while the user doesn't do anything
+ * while the second mode allows timer firing while he is using a slider
+ * or a menu.
+ */
+
+ self.initialized = YES;
+ }
+}
+
+-(void)dealloc
+{
+ [self.renderTimer invalidate];
+ self.mainWindow->renderWindow.close();
+
+ self.window = nil;
+ self.sfmlView = nil;
+ self.textField = nil;
+
+ delete (SFMLmainWindow*) self.mainWindow;
+ self.mainWindow = 0;
+ self.renderTimer = nil;
+
+ [super dealloc];
+}
+
+-(void)renderMainWindow:(NSTimer*)aTimer
+{
+ (void)aTimer;
+
+ // Scaling
+ /* /!\ we do this at 60fps so choose low scaling factor! /!\ */
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
+ self.mainWindow->sprite.scale(1.01f, 1.01f);
+
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
+ self.mainWindow->sprite.scale(0.99f, 0.99f);
+
+ // Clear the window, display some stuff and display it into our view.
+
+ self.mainWindow->renderWindow.clear(self.mainWindow->background);
+
+ if (self.visible)
+ self.mainWindow->renderWindow.draw(self.mainWindow->sprite);
+
+ self.mainWindow->renderWindow.draw(self.mainWindow->text);
+
+ self.mainWindow->renderWindow.display();
+}
+
+-(IBAction)colorChanged:(NSPopUpButton*)sender
+{
+ if (self.initialized)
+ {
+ // Convert title to color
+ NSString* color = [[sender selectedItem] title];
+ if ([color isEqualToString:BLUE])
+ self.mainWindow->background = sf::Color::Blue;
+ else if ([color isEqualToString:GREEN])
+ self.mainWindow->background = sf::Color::Green;
+ else
+ self.mainWindow->background = sf::Color::Red;
+ }
+}
+
+-(IBAction)rotationChanged:(NSSlider*)sender
+{
+ if (self.initialized)
+ {
+ float angle = [sender floatValue];
+ self.mainWindow->sprite.setRotation(angle);
+ }
+}
+
+-(IBAction)visibleChanged:(NSButton*)sender
+{
+ if (self.initialized)
+ self.visible = [sender state] == NSOnState;
+}
+
+-(IBAction)textChanged:(NSTextField*)sender
+{
+ if (self.initialized)
+ self.mainWindow->text.setString([[sender stringValue] tostdwstring]);
+}
+
+- (IBAction)updateText:(NSButton*)sender
+{
+ (void)sender;
+
+ // Simply simulate textChanged:
+ [self textChanged:self.textField];
+}
+
+@end
+
+@implementation SilentWindow
+
+-(void)keyDown:(NSEvent*)theEvent
+{
+ (void)theEvent;
+ // Do nothing except preventing this alert.
+}
+
+@end
diff --git a/examples/cocoa/MainMenu.xib b/examples/cocoa/MainMenu.xib
new file mode 100644
index 0000000..2001ff5
--- /dev/null
+++ b/examples/cocoa/MainMenu.xib
@@ -0,0 +1,4180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1070</int>
+ <string key="IBDocument.SystemVersion">11C74</string>
+ <string key="IBDocument.InterfaceBuilderVersion">1938</string>
+ <string key="IBDocument.AppKitVersion">1138.23</string>
+ <string key="IBDocument.HIToolboxVersion">567.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">1938</string>
+ </object>
+ <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSPopUpButton</string>
+ <string>NSMenuItem</string>
+ <string>NSMenu</string>
+ <string>NSTextFieldCell</string>
+ <string>NSButtonCell</string>
+ <string>NSButton</string>
+ <string>NSSlider</string>
+ <string>NSSliderCell</string>
+ <string>NSCustomObject</string>
+ <string>NSCustomView</string>
+ <string>NSView</string>
+ <string>NSWindowTemplate</string>
+ <string>NSTextField</string>
+ <string>NSPopUpButtonCell</string>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1021">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSCustomObject" id="1014">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1050">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSMenu" id="649796088">
+ <string key="NSTitle">AMainMenu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="694149608">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Cocoa</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="35465992">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="502551668">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="110575045">
+ <string key="NSTitle">Cocoa</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="238522557">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">About Cocoa</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="304266470">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="609285721">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Preferences…</string>
+ <string key="NSKeyEquiv">,</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="481834944">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1046388886">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Services</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="752062318">
+ <string key="NSTitle">Services</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <string key="NSName">_NSServicesMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="646227648">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="755159360">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide Cocoa</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="342932134">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide Others</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="908899353">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Show All</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1056857174">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="632727374">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Quit Cocoa</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="379814623">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">File</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="720053764">
+ <string key="NSTitle">File</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="705341025">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">New</string>
+ <string key="NSKeyEquiv">n</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="722745758">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open…</string>
+ <string key="NSKeyEquiv">o</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1025936716">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open Recent</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1065607017">
+ <string key="NSTitle">Open Recent</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="759406840">
+ <reference key="NSMenu" ref="1065607017"/>
+ <string key="NSTitle">Clear Menu</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSRecentDocumentsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="425164168">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="776162233">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Close</string>
+ <string key="NSKeyEquiv">w</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1023925487">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Save</string>
+ <string key="NSKeyEquiv">s</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="117038363">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Save As…</string>
+ <string key="NSKeyEquiv">S</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="579971712">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Revert to Saved</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1010469920">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="294629803">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Page Setup...</string>
+ <string key="NSKeyEquiv">P</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSToolTip"/>
+ </object>
+ <object class="NSMenuItem" id="49223823">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Print…</string>
+ <string key="NSKeyEquiv">p</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="952259628">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Edit</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="789758025">
+ <string key="NSTitle">Edit</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1058277027">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Undo</string>
+ <string key="NSKeyEquiv">z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="790794224">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Redo</string>
+ <string key="NSKeyEquiv">Z</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1040322652">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="296257095">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Cut</string>
+ <string key="NSKeyEquiv">x</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="860595796">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Copy</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="29853731">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="82994268">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste and Match Style</string>
+ <string key="NSKeyEquiv">V</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="437104165">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Delete</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="583158037">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Select All</string>
+ <string key="NSKeyEquiv">a</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="212016141">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="892235320">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Find</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="963351320">
+ <string key="NSTitle">Find</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="447796847">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find…</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="326711663">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Next</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="270902937">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Previous</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="159080638">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Use Selection for Find</string>
+ <string key="NSKeyEquiv">e</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">7</int>
+ </object>
+ <object class="NSMenuItem" id="88285865">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Jump to Selection</string>
+ <string key="NSKeyEquiv">j</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="972420730">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Spelling and Grammar</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="769623530">
+ <string key="NSTitle">Spelling and Grammar</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="679648819">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Show Spelling and Grammar</string>
+ <string key="NSKeyEquiv">:</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="96193923">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Document Now</string>
+ <string key="NSKeyEquiv">;</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="859480356">
+ <reference key="NSMenu" ref="769623530"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="948374510">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Spelling While Typing</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="967646866">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Grammar With Spelling</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="795346622">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Correct Spelling Automatically</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="507821607">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="698887838">
+ <string key="NSTitle">Substitutions</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="65139061">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Show Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="19036812">
+ <reference key="NSMenu" ref="698887838"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="605118523">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Copy/Paste</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="197661976">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Quotes</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="672708820">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Dashes</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="708854459">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Links</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="537092702">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Text Replacement</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="288088188">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Transformations</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="579392910">
+ <string key="NSTitle">Transformations</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1060694897">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Upper Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="879586729">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Lower Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="56570060">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Capitalize</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="676164635">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Speech</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="785027613">
+ <string key="NSTitle">Speech</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="731782645">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Start Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="680220178">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Stop Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="302598603">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Format</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="941447902">
+ <string key="NSTitle">Format</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="792887677">
+ <reference key="NSMenu" ref="941447902"/>
+ <string key="NSTitle">Font</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="786677654">
+ <string key="NSTitle">Font</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="159677712">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Show Fonts</string>
+ <string key="NSKeyEquiv">t</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="305399458">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Bold</string>
+ <string key="NSKeyEquiv">b</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="814362025">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Italic</string>
+ <string key="NSKeyEquiv">i</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="330926929">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Underline</string>
+ <string key="NSKeyEquiv">u</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="533507878">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="158063935">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Bigger</string>
+ <string key="NSKeyEquiv">+</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="885547335">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Smaller</string>
+ <string key="NSKeyEquiv">-</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">4</int>
+ </object>
+ <object class="NSMenuItem" id="901062459">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="767671776">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Kern</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="175441468">
+ <string key="NSTitle">Kern</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="252969304">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="766922938">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Use None</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="677519740">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Tighten</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="238351151">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Loosen</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="691570813">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Ligature</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1058217995">
+ <string key="NSTitle">Ligature</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="706297211">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="568384683">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use None</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="663508465">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use All</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="769124883">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Baseline</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="18263474">
+ <string key="NSTitle">Baseline</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="257962622">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="644725453">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Superscript</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1037576581">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Subscript</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="941806246">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Raise</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1045724900">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Lower</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="739652853">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1012600125">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Show Colors</string>
+ <string key="NSKeyEquiv">C</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="214559597">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="596732606">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Copy Style</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="393423671">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Paste Style</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSFontMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="215659978">
+ <reference key="NSMenu" ref="941447902"/>
+ <string key="NSTitle">Text</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="446991534">
+ <string key="NSTitle">Text</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="875092757">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Align Left</string>
+ <string key="NSKeyEquiv">{</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="630155264">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Center</string>
+ <string key="NSKeyEquiv">|</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="945678886">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Justify</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="512868991">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Align Right</string>
+ <string key="NSKeyEquiv">}</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="163117631">
+ <reference key="NSMenu" ref="446991534"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="31516759">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Writing Direction</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="956096989">
+ <string key="NSTitle">Writing Direction</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="257099033">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <string key="NSTitle">Paragraph</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="551969625">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="249532473">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="607364498">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="508151438">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="981751889">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <string key="NSTitle">Selection</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="380031999">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="825984362">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="560145579">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="908105787">
+ <reference key="NSMenu" ref="446991534"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="644046920">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Show Ruler</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="231811626">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Copy Ruler</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1310720</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="883618387">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Paste Ruler</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1310720</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="586577488">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="466310130">
+ <string key="NSTitle">View</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="102151532">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Show Toolbar</string>
+ <string key="NSKeyEquiv">t</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="237841660">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Customize Toolbar…</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="713487014">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Window</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="835318025">
+ <string key="NSTitle">Window</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1011231497">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Minimize</string>
+ <string key="NSKeyEquiv">m</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="575023229">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Zoom</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="299356726">
+ <reference key="NSMenu" ref="835318025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="625202149">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Bring All to Front</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSWindowsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="448692316">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Help</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="992780483">
+ <string key="NSTitle">Help</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="105068016">
+ <reference key="NSMenu" ref="992780483"/>
+ <string key="NSTitle">Cocoa Help</string>
+ <string key="NSKeyEquiv">?</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSHelpMenu</string>
+ </object>
+ </object>
+ </object>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ <object class="NSWindowTemplate" id="972006081">
+ <int key="NSWindowStyleMask">7</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{232, 390}, {485, 379}}</string>
+ <int key="NSWTFlags">1417150464</int>
+ <string key="NSWindowTitle">Cocoa</string>
+ <string key="NSWindowClass">SilentWindow</string>
+ <nil key="NSViewClass"/>
+ <nil key="NSUserInterfaceItemIdentifier"/>
+ <object class="NSView" key="NSWindowView" id="439893737">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSPopUpButton" id="895645105">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{366, 35}, {97, 26}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="422780221"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSPopUpButtonCell" key="NSCell" id="939854878">
+ <int key="NSCellFlags">-2076049856</int>
+ <int key="NSCellFlags2">134219776</int>
+ <object class="NSFont" key="NSSupport" id="507345084">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="895645105"/>
+ <int key="NSButtonFlags">-2035138305</int>
+ <int key="NSButtonFlags2">129</int>
+ <reference key="NSAlternateImage" ref="507345084"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ <object class="NSMenuItem" key="NSMenuItem" id="468569656">
+ <reference key="NSMenu" ref="526523505"/>
+ <string key="NSTitle">Blue</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <int key="NSState">1</int>
+ <object class="NSCustomResource" key="NSImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">blue</string>
+ </object>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">_popUpItemAction:</string>
+ <reference key="NSTarget" ref="939854878"/>
+ </object>
+ <bool key="NSMenuItemRespectAlignment">YES</bool>
+ <object class="NSMenu" key="NSMenu" id="526523505">
+ <string key="NSTitle">Color</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="468569656"/>
+ <object class="NSMenuItem" id="461530193">
+ <reference key="NSMenu" ref="526523505"/>
+ <string key="NSTitle">Green</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">green</string>
+ </object>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">_popUpItemAction:</string>
+ <reference key="NSTarget" ref="939854878"/>
+ </object>
+ <object class="NSMenuItem" id="969578911">
+ <reference key="NSMenu" ref="526523505"/>
+ <string key="NSTitle">Red</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">red</string>
+ </object>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">_popUpItemAction:</string>
+ <reference key="NSTarget" ref="939854878"/>
+ </object>
+ </object>
+ <reference key="NSMenuFont" ref="507345084"/>
+ </object>
+ <int key="NSSelectedIndex">-1</int>
+ <int key="NSPreferredEdge">1</int>
+ <bool key="NSUsesItemFromMenu">YES</bool>
+ <bool key="NSAltersState">YES</bool>
+ <int key="NSArrowPosition">2</int>
+ </object>
+ </object>
+ <object class="NSSlider" id="186246764">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{234, 34}, {28, 30}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="886444468"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSSliderCell" key="NSCell" id="171036244">
+ <int key="NSCellFlags">67501824</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents"/>
+ <reference key="NSControlView" ref="186246764"/>
+ <double key="NSMaxValue">359</double>
+ <double key="NSMinValue">0.0</double>
+ <double key="NSValue">0.0</double>
+ <double key="NSAltIncValue">0.0</double>
+ <int key="NSNumberOfTickMarks">0</int>
+ <int key="NSTickMarkPosition">1</int>
+ <bool key="NSAllowsTickMarkValuesOnly">NO</bool>
+ <bool key="NSVertical">NO</bool>
+ <int key="NSSliderType">1</int>
+ </object>
+ </object>
+ <object class="NSButton" id="336088134">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{18, 40}, {64, 18}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="482000415"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="934915496">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Visible</string>
+ <reference key="NSSupport" ref="507345084"/>
+ <reference key="NSControlView" ref="336088134"/>
+ <int key="NSButtonFlags">1211912703</int>
+ <int key="NSButtonFlags2">2</int>
+ <object class="NSCustomResource" key="NSNormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSSwitch</string>
+ </object>
+ <object class="NSButtonImageSource" key="NSAlternateImage">
+ <string key="NSImageName">NSSwitch</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="482000415">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{172, 41}, {57, 17}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="186246764"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="575979405">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">Rotation</string>
+ <reference key="NSSupport" ref="507345084"/>
+ <reference key="NSControlView" ref="482000415"/>
+ <object class="NSColor" key="NSBackgroundColor" id="86428082">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="429197527">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor" id="1073457999">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextField" id="886444468">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{325, 39}, {39, 17}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="895645105"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="67668546">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">Color</string>
+ <reference key="NSSupport" ref="507345084"/>
+ <reference key="NSControlView" ref="886444468"/>
+ <reference key="NSBackgroundColor" ref="86428082"/>
+ <reference key="NSTextColor" ref="429197527"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="969295846">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{20, 337}, {359, 22}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="301002623"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1043401668">
+ <int key="NSCellFlags">-1803944383</int>
+ <int key="NSCellFlags2">272630848</int>
+ <string key="NSContents">Hello SFML!</string>
+ <reference key="NSSupport" ref="507345084"/>
+ <string key="NSPlaceholderString">Enter some text here</string>
+ <reference key="NSControlView" ref="969295846"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textColor</string>
+ <reference key="NSColor" ref="1073457999"/>
+ </object>
+ <object class="NSArray" key="NSAllowedInputLocales">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSAllRomanInputSourcesLocaleIdentifier</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSCustomView" id="301002623">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{20, 72}, {440, 260}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="531630843"/>
+ <string key="NSClassName">NSView</string>
+ </object>
+ <object class="NSButton" id="531630843">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{381, 331}, {85, 32}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="336088134"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="1053978795">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Update</string>
+ <reference key="NSSupport" ref="507345084"/>
+ <reference key="NSControlView" ref="531630843"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">129</int>
+ <reference key="NSAlternateImage" ref="507345084"/>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="422780221">
+ <reference key="NSNextResponder" ref="439893737"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 2}, {451, 17}}</string>
+ <reference key="NSSuperview" ref="439893737"/>
+ <reference key="NSWindow"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="702743979">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents">Tips : you can use up and down arrows to scale the logo.</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="422780221"/>
+ <reference key="NSBackgroundColor" ref="86428082"/>
+ <reference key="NSTextColor" ref="429197527"/>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{485, 379}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="969295846"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1058}}</string>
+ <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
+ <bool key="NSAutorecalculatesContentBorderThicknessMinY">NO</bool>
+ <double key="NSContentBorderThicknessMinY">22</double>
+ <bool key="NSWindowIsRestorable">YES</bool>
+ </object>
+ <object class="NSCustomObject" id="976324537">
+ <string key="NSClassName">CocoaAppDelegate</string>
+ </object>
+ <object class="NSCustomObject" id="755631768">
+ <string key="NSClassName">NSFontManager</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="1050"/>
+ <reference key="destination" ref="632727374"/>
+ </object>
+ <int key="connectionID">449</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontStandardAboutPanel:</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="238522557"/>
+ </object>
+ <int key="connectionID">142</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="976324537"/>
+ </object>
+ <int key="connectionID">495</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performMiniaturize:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1011231497"/>
+ </object>
+ <int key="connectionID">37</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">arrangeInFront:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="625202149"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">print:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="49223823"/>
+ </object>
+ <int key="connectionID">86</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runPageLayout:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="294629803"/>
+ </object>
+ <int key="connectionID">87</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clearRecentDocuments:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="759406840"/>
+ </object>
+ <int key="connectionID">127</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="776162233"/>
+ </object>
+ <int key="connectionID">193</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleContinuousSpellChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="948374510"/>
+ </object>
+ <int key="connectionID">222</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">undo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1058277027"/>
+ </object>
+ <int key="connectionID">223</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copy:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="860595796"/>
+ </object>
+ <int key="connectionID">224</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">checkSpelling:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="96193923"/>
+ </object>
+ <int key="connectionID">225</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">paste:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="29853731"/>
+ </object>
+ <int key="connectionID">226</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">stopSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="680220178"/>
+ </object>
+ <int key="connectionID">227</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cut:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="296257095"/>
+ </object>
+ <int key="connectionID">228</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showGuessPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="679648819"/>
+ </object>
+ <int key="connectionID">230</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">redo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="790794224"/>
+ </object>
+ <int key="connectionID">231</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectAll:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="583158037"/>
+ </object>
+ <int key="connectionID">232</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">startSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="731782645"/>
+ </object>
+ <int key="connectionID">233</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">delete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="437104165"/>
+ </object>
+ <int key="connectionID">235</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performZoom:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="575023229"/>
+ </object>
+ <int key="connectionID">240</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="447796847"/>
+ </object>
+ <int key="connectionID">241</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">centerSelectionInVisibleArea:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="88285865"/>
+ </object>
+ <int key="connectionID">245</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleGrammarChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="967646866"/>
+ </object>
+ <int key="connectionID">347</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleSmartInsertDelete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="605118523"/>
+ </object>
+ <int key="connectionID">355</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticQuoteSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="197661976"/>
+ </object>
+ <int key="connectionID">356</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticLinkDetection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="708854459"/>
+ </object>
+ <int key="connectionID">357</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">saveDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1023925487"/>
+ </object>
+ <int key="connectionID">362</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">saveDocumentAs:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="117038363"/>
+ </object>
+ <int key="connectionID">363</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">revertDocumentToSaved:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="579971712"/>
+ </object>
+ <int key="connectionID">364</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runToolbarCustomizationPalette:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="237841660"/>
+ </object>
+ <int key="connectionID">365</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleToolbarShown:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="102151532"/>
+ </object>
+ <int key="connectionID">366</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hide:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="755159360"/>
+ </object>
+ <int key="connectionID">367</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hideOtherApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="342932134"/>
+ </object>
+ <int key="connectionID">368</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unhideAllApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="908899353"/>
+ </object>
+ <int key="connectionID">370</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">newDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="705341025"/>
+ </object>
+ <int key="connectionID">373</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">openDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="722745758"/>
+ </object>
+ <int key="connectionID">374</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">raiseBaseline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="941806246"/>
+ </object>
+ <int key="connectionID">426</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">lowerBaseline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1045724900"/>
+ </object>
+ <int key="connectionID">427</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copyFont:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="596732606"/>
+ </object>
+ <int key="connectionID">428</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">subscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1037576581"/>
+ </object>
+ <int key="connectionID">429</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">superscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="644725453"/>
+ </object>
+ <int key="connectionID">430</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">tightenKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="677519740"/>
+ </object>
+ <int key="connectionID">431</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">underline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="330926929"/>
+ </object>
+ <int key="connectionID">432</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontColorPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1012600125"/>
+ </object>
+ <int key="connectionID">433</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useAllLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="663508465"/>
+ </object>
+ <int key="connectionID">434</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">loosenKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="238351151"/>
+ </object>
+ <int key="connectionID">435</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteFont:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="393423671"/>
+ </object>
+ <int key="connectionID">436</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="257962622"/>
+ </object>
+ <int key="connectionID">437</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useStandardKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="252969304"/>
+ </object>
+ <int key="connectionID">438</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useStandardLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="706297211"/>
+ </object>
+ <int key="connectionID">439</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">turnOffLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="568384683"/>
+ </object>
+ <int key="connectionID">440</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">turnOffKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="766922938"/>
+ </object>
+ <int key="connectionID">441</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticSpellingCorrection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="795346622"/>
+ </object>
+ <int key="connectionID">456</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontSubstitutionsPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="65139061"/>
+ </object>
+ <int key="connectionID">458</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticDashSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="672708820"/>
+ </object>
+ <int key="connectionID">461</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticTextReplacement:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="537092702"/>
+ </object>
+ <int key="connectionID">463</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">uppercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1060694897"/>
+ </object>
+ <int key="connectionID">464</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">capitalizeWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="56570060"/>
+ </object>
+ <int key="connectionID">467</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">lowercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="879586729"/>
+ </object>
+ <int key="connectionID">468</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteAsPlainText:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="82994268"/>
+ </object>
+ <int key="connectionID">486</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="326711663"/>
+ </object>
+ <int key="connectionID">487</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="270902937"/>
+ </object>
+ <int key="connectionID">488</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="159080638"/>
+ </object>
+ <int key="connectionID">489</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHelp:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="105068016"/>
+ </object>
+ <int key="connectionID">493</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignCenter:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="630155264"/>
+ </object>
+ <int key="connectionID">518</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="883618387"/>
+ </object>
+ <int key="connectionID">519</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="644046920"/>
+ </object>
+ <int key="connectionID">520</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="512868991"/>
+ </object>
+ <int key="connectionID">521</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copyRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="231811626"/>
+ </object>
+ <int key="connectionID">522</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignJustified:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="945678886"/>
+ </object>
+ <int key="connectionID">523</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="875092757"/>
+ </object>
+ <int key="connectionID">524</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionNatural:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="551969625"/>
+ </object>
+ <int key="connectionID">525</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionLeftToRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="249532473"/>
+ </object>
+ <int key="connectionID">526</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionRightToLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="607364498"/>
+ </object>
+ <int key="connectionID">527</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionNatural:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="380031999"/>
+ </object>
+ <int key="connectionID">528</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionLeftToRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="825984362"/>
+ </object>
+ <int key="connectionID">529</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionRightToLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="560145579"/>
+ </object>
+ <int key="connectionID">530</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">initialFirstResponder</string>
+ <reference key="source" ref="972006081"/>
+ <reference key="destination" ref="969295846"/>
+ </object>
+ <int key="connectionID">559</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">addFontTrait:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="305399458"/>
+ </object>
+ <int key="connectionID">421</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">addFontTrait:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="814362025"/>
+ </object>
+ <int key="connectionID">422</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">modifyFont:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="885547335"/>
+ </object>
+ <int key="connectionID">423</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontFontPanel:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="159677712"/>
+ </object>
+ <int key="connectionID">424</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">modifyFont:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="158063935"/>
+ </object>
+ <int key="connectionID">425</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="972006081"/>
+ </object>
+ <int key="connectionID">532</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">colorChanged:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="895645105"/>
+ </object>
+ <int key="connectionID">557</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">sfmlView</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="301002623"/>
+ </object>
+ <int key="connectionID">558</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">rotationChanged:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="186246764"/>
+ </object>
+ <int key="connectionID">560</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">visibleChanged:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="336088134"/>
+ </object>
+ <int key="connectionID">561</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">textChanged:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="969295846"/>
+ </object>
+ <int key="connectionID">562</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">textField</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="969295846"/>
+ </object>
+ <int key="connectionID">566</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">updateText:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="531630843"/>
+ </object>
+ <int key="connectionID">567</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1048"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1021"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1014"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1050"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="649796088"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="713487014"/>
+ <reference ref="694149608"/>
+ <reference ref="952259628"/>
+ <reference ref="379814623"/>
+ <reference ref="586577488"/>
+ <reference ref="302598603"/>
+ <reference ref="448692316"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="713487014"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="835318025"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="694149608"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="110575045"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">217</int>
+ <reference key="object" ref="952259628"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="789758025"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">83</int>
+ <reference key="object" ref="379814623"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="720053764"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">81</int>
+ <reference key="object" ref="720053764"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1023925487"/>
+ <reference ref="117038363"/>
+ <reference ref="49223823"/>
+ <reference ref="722745758"/>
+ <reference ref="705341025"/>
+ <reference ref="1025936716"/>
+ <reference ref="294629803"/>
+ <reference ref="776162233"/>
+ <reference ref="425164168"/>
+ <reference ref="579971712"/>
+ <reference ref="1010469920"/>
+ </object>
+ <reference key="parent" ref="379814623"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">75</int>
+ <reference key="object" ref="1023925487"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">80</int>
+ <reference key="object" ref="117038363"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">78</int>
+ <reference key="object" ref="49223823"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">72</int>
+ <reference key="object" ref="722745758"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">82</int>
+ <reference key="object" ref="705341025"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">124</int>
+ <reference key="object" ref="1025936716"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1065607017"/>
+ </object>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">77</int>
+ <reference key="object" ref="294629803"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">73</int>
+ <reference key="object" ref="776162233"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">79</int>
+ <reference key="object" ref="425164168"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">112</int>
+ <reference key="object" ref="579971712"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">74</int>
+ <reference key="object" ref="1010469920"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">125</int>
+ <reference key="object" ref="1065607017"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="759406840"/>
+ </object>
+ <reference key="parent" ref="1025936716"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">126</int>
+ <reference key="object" ref="759406840"/>
+ <reference key="parent" ref="1065607017"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">205</int>
+ <reference key="object" ref="789758025"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="437104165"/>
+ <reference ref="583158037"/>
+ <reference ref="1058277027"/>
+ <reference ref="212016141"/>
+ <reference ref="296257095"/>
+ <reference ref="29853731"/>
+ <reference ref="860595796"/>
+ <reference ref="1040322652"/>
+ <reference ref="790794224"/>
+ <reference ref="892235320"/>
+ <reference ref="972420730"/>
+ <reference ref="676164635"/>
+ <reference ref="507821607"/>
+ <reference ref="288088188"/>
+ <reference ref="82994268"/>
+ </object>
+ <reference key="parent" ref="952259628"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">202</int>
+ <reference key="object" ref="437104165"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">198</int>
+ <reference key="object" ref="583158037"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">207</int>
+ <reference key="object" ref="1058277027"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">214</int>
+ <reference key="object" ref="212016141"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">199</int>
+ <reference key="object" ref="296257095"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">203</int>
+ <reference key="object" ref="29853731"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">197</int>
+ <reference key="object" ref="860595796"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">206</int>
+ <reference key="object" ref="1040322652"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">215</int>
+ <reference key="object" ref="790794224"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">218</int>
+ <reference key="object" ref="892235320"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="963351320"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">216</int>
+ <reference key="object" ref="972420730"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="769623530"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">200</int>
+ <reference key="object" ref="769623530"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="948374510"/>
+ <reference ref="96193923"/>
+ <reference ref="679648819"/>
+ <reference ref="967646866"/>
+ <reference ref="859480356"/>
+ <reference ref="795346622"/>
+ </object>
+ <reference key="parent" ref="972420730"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">219</int>
+ <reference key="object" ref="948374510"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">201</int>
+ <reference key="object" ref="96193923"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">204</int>
+ <reference key="object" ref="679648819"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">220</int>
+ <reference key="object" ref="963351320"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="270902937"/>
+ <reference ref="88285865"/>
+ <reference ref="159080638"/>
+ <reference ref="326711663"/>
+ <reference ref="447796847"/>
+ </object>
+ <reference key="parent" ref="892235320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">213</int>
+ <reference key="object" ref="270902937"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">210</int>
+ <reference key="object" ref="88285865"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">221</int>
+ <reference key="object" ref="159080638"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">208</int>
+ <reference key="object" ref="326711663"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">209</int>
+ <reference key="object" ref="447796847"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="110575045"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="238522557"/>
+ <reference ref="755159360"/>
+ <reference ref="908899353"/>
+ <reference ref="632727374"/>
+ <reference ref="646227648"/>
+ <reference ref="609285721"/>
+ <reference ref="481834944"/>
+ <reference ref="304266470"/>
+ <reference ref="1046388886"/>
+ <reference ref="1056857174"/>
+ <reference ref="342932134"/>
+ </object>
+ <reference key="parent" ref="694149608"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">58</int>
+ <reference key="object" ref="238522557"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">134</int>
+ <reference key="object" ref="755159360"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">150</int>
+ <reference key="object" ref="908899353"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">136</int>
+ <reference key="object" ref="632727374"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">144</int>
+ <reference key="object" ref="646227648"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">129</int>
+ <reference key="object" ref="609285721"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">143</int>
+ <reference key="object" ref="481834944"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">236</int>
+ <reference key="object" ref="304266470"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">131</int>
+ <reference key="object" ref="1046388886"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="752062318"/>
+ </object>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">149</int>
+ <reference key="object" ref="1056857174"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">145</int>
+ <reference key="object" ref="342932134"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">130</int>
+ <reference key="object" ref="752062318"/>
+ <reference key="parent" ref="1046388886"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="835318025"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="299356726"/>
+ <reference ref="625202149"/>
+ <reference ref="575023229"/>
+ <reference ref="1011231497"/>
+ </object>
+ <reference key="parent" ref="713487014"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">92</int>
+ <reference key="object" ref="299356726"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="625202149"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">239</int>
+ <reference key="object" ref="575023229"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="1011231497"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">295</int>
+ <reference key="object" ref="586577488"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="466310130"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">296</int>
+ <reference key="object" ref="466310130"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="102151532"/>
+ <reference ref="237841660"/>
+ </object>
+ <reference key="parent" ref="586577488"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">297</int>
+ <reference key="object" ref="102151532"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">298</int>
+ <reference key="object" ref="237841660"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">211</int>
+ <reference key="object" ref="676164635"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="785027613"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">212</int>
+ <reference key="object" ref="785027613"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="680220178"/>
+ <reference ref="731782645"/>
+ </object>
+ <reference key="parent" ref="676164635"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">195</int>
+ <reference key="object" ref="680220178"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">196</int>
+ <reference key="object" ref="731782645"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">346</int>
+ <reference key="object" ref="967646866"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">348</int>
+ <reference key="object" ref="507821607"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="698887838"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">349</int>
+ <reference key="object" ref="698887838"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="605118523"/>
+ <reference ref="197661976"/>
+ <reference ref="708854459"/>
+ <reference ref="65139061"/>
+ <reference ref="19036812"/>
+ <reference ref="672708820"/>
+ <reference ref="537092702"/>
+ </object>
+ <reference key="parent" ref="507821607"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">350</int>
+ <reference key="object" ref="605118523"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">351</int>
+ <reference key="object" ref="197661976"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">354</int>
+ <reference key="object" ref="708854459"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">371</int>
+ <reference key="object" ref="972006081"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="439893737"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Main Window</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">372</int>
+ <reference key="object" ref="439893737"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="895645105"/>
+ <reference ref="886444468"/>
+ <reference ref="336088134"/>
+ <reference ref="186246764"/>
+ <reference ref="482000415"/>
+ <reference ref="969295846"/>
+ <reference ref="301002623"/>
+ <reference ref="531630843"/>
+ <reference ref="422780221"/>
+ </object>
+ <reference key="parent" ref="972006081"/>
+ <string key="objectName">Content View</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">375</int>
+ <reference key="object" ref="302598603"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="941447902"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">376</int>
+ <reference key="object" ref="941447902"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="792887677"/>
+ <reference ref="215659978"/>
+ </object>
+ <reference key="parent" ref="302598603"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">377</int>
+ <reference key="object" ref="792887677"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="786677654"/>
+ </object>
+ <reference key="parent" ref="941447902"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">388</int>
+ <reference key="object" ref="786677654"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="159677712"/>
+ <reference ref="305399458"/>
+ <reference ref="814362025"/>
+ <reference ref="330926929"/>
+ <reference ref="533507878"/>
+ <reference ref="158063935"/>
+ <reference ref="885547335"/>
+ <reference ref="901062459"/>
+ <reference ref="767671776"/>
+ <reference ref="691570813"/>
+ <reference ref="769124883"/>
+ <reference ref="739652853"/>
+ <reference ref="1012600125"/>
+ <reference ref="214559597"/>
+ <reference ref="596732606"/>
+ <reference ref="393423671"/>
+ </object>
+ <reference key="parent" ref="792887677"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">389</int>
+ <reference key="object" ref="159677712"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">390</int>
+ <reference key="object" ref="305399458"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">391</int>
+ <reference key="object" ref="814362025"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">392</int>
+ <reference key="object" ref="330926929"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">393</int>
+ <reference key="object" ref="533507878"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">394</int>
+ <reference key="object" ref="158063935"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">395</int>
+ <reference key="object" ref="885547335"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">396</int>
+ <reference key="object" ref="901062459"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">397</int>
+ <reference key="object" ref="767671776"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="175441468"/>
+ </object>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">398</int>
+ <reference key="object" ref="691570813"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1058217995"/>
+ </object>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">399</int>
+ <reference key="object" ref="769124883"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="18263474"/>
+ </object>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">400</int>
+ <reference key="object" ref="739652853"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">401</int>
+ <reference key="object" ref="1012600125"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">402</int>
+ <reference key="object" ref="214559597"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">403</int>
+ <reference key="object" ref="596732606"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">404</int>
+ <reference key="object" ref="393423671"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">405</int>
+ <reference key="object" ref="18263474"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="257962622"/>
+ <reference ref="644725453"/>
+ <reference ref="1037576581"/>
+ <reference ref="941806246"/>
+ <reference ref="1045724900"/>
+ </object>
+ <reference key="parent" ref="769124883"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">406</int>
+ <reference key="object" ref="257962622"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">407</int>
+ <reference key="object" ref="644725453"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">408</int>
+ <reference key="object" ref="1037576581"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">409</int>
+ <reference key="object" ref="941806246"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">410</int>
+ <reference key="object" ref="1045724900"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">411</int>
+ <reference key="object" ref="1058217995"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="706297211"/>
+ <reference ref="568384683"/>
+ <reference ref="663508465"/>
+ </object>
+ <reference key="parent" ref="691570813"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">412</int>
+ <reference key="object" ref="706297211"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">413</int>
+ <reference key="object" ref="568384683"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">414</int>
+ <reference key="object" ref="663508465"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">415</int>
+ <reference key="object" ref="175441468"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="252969304"/>
+ <reference ref="766922938"/>
+ <reference ref="677519740"/>
+ <reference ref="238351151"/>
+ </object>
+ <reference key="parent" ref="767671776"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">416</int>
+ <reference key="object" ref="252969304"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">417</int>
+ <reference key="object" ref="766922938"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">418</int>
+ <reference key="object" ref="677519740"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">419</int>
+ <reference key="object" ref="238351151"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">420</int>
+ <reference key="object" ref="755631768"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">450</int>
+ <reference key="object" ref="288088188"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="579392910"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">451</int>
+ <reference key="object" ref="579392910"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1060694897"/>
+ <reference ref="879586729"/>
+ <reference ref="56570060"/>
+ </object>
+ <reference key="parent" ref="288088188"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">452</int>
+ <reference key="object" ref="1060694897"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">453</int>
+ <reference key="object" ref="859480356"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">454</int>
+ <reference key="object" ref="795346622"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">457</int>
+ <reference key="object" ref="65139061"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">459</int>
+ <reference key="object" ref="19036812"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">460</int>
+ <reference key="object" ref="672708820"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">462</int>
+ <reference key="object" ref="537092702"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">465</int>
+ <reference key="object" ref="879586729"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">466</int>
+ <reference key="object" ref="56570060"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">485</int>
+ <reference key="object" ref="82994268"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">490</int>
+ <reference key="object" ref="448692316"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="992780483"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">491</int>
+ <reference key="object" ref="992780483"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="105068016"/>
+ </object>
+ <reference key="parent" ref="448692316"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">492</int>
+ <reference key="object" ref="105068016"/>
+ <reference key="parent" ref="992780483"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">494</int>
+ <reference key="object" ref="976324537"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">496</int>
+ <reference key="object" ref="215659978"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="446991534"/>
+ </object>
+ <reference key="parent" ref="941447902"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">497</int>
+ <reference key="object" ref="446991534"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="875092757"/>
+ <reference ref="630155264"/>
+ <reference ref="945678886"/>
+ <reference ref="512868991"/>
+ <reference ref="163117631"/>
+ <reference ref="31516759"/>
+ <reference ref="908105787"/>
+ <reference ref="644046920"/>
+ <reference ref="231811626"/>
+ <reference ref="883618387"/>
+ </object>
+ <reference key="parent" ref="215659978"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">498</int>
+ <reference key="object" ref="875092757"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">499</int>
+ <reference key="object" ref="630155264"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">500</int>
+ <reference key="object" ref="945678886"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">501</int>
+ <reference key="object" ref="512868991"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">502</int>
+ <reference key="object" ref="163117631"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">503</int>
+ <reference key="object" ref="31516759"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="956096989"/>
+ </object>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">504</int>
+ <reference key="object" ref="908105787"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">505</int>
+ <reference key="object" ref="644046920"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">506</int>
+ <reference key="object" ref="231811626"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">507</int>
+ <reference key="object" ref="883618387"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">508</int>
+ <reference key="object" ref="956096989"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="257099033"/>
+ <reference ref="551969625"/>
+ <reference ref="249532473"/>
+ <reference ref="607364498"/>
+ <reference ref="508151438"/>
+ <reference ref="981751889"/>
+ <reference ref="380031999"/>
+ <reference ref="825984362"/>
+ <reference ref="560145579"/>
+ </object>
+ <reference key="parent" ref="31516759"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">509</int>
+ <reference key="object" ref="257099033"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">510</int>
+ <reference key="object" ref="551969625"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">511</int>
+ <reference key="object" ref="249532473"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">512</int>
+ <reference key="object" ref="607364498"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">513</int>
+ <reference key="object" ref="508151438"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">514</int>
+ <reference key="object" ref="981751889"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">515</int>
+ <reference key="object" ref="380031999"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">516</int>
+ <reference key="object" ref="825984362"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">517</int>
+ <reference key="object" ref="560145579"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">533</int>
+ <reference key="object" ref="895645105"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="939854878"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ <string key="objectName">Color</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">534</int>
+ <reference key="object" ref="939854878"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="526523505"/>
+ </object>
+ <reference key="parent" ref="895645105"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">535</int>
+ <reference key="object" ref="526523505"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="969578911"/>
+ <reference ref="468569656"/>
+ <reference ref="461530193"/>
+ </object>
+ <reference key="parent" ref="939854878"/>
+ <string key="objectName">Menu - Color</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">536</int>
+ <reference key="object" ref="969578911"/>
+ <reference key="parent" ref="526523505"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">537</int>
+ <reference key="object" ref="468569656"/>
+ <reference key="parent" ref="526523505"/>
+ <string key="objectName">Menu Item - Red</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">538</int>
+ <reference key="object" ref="461530193"/>
+ <reference key="parent" ref="526523505"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">541</int>
+ <reference key="object" ref="336088134"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="934915496"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ <string key="objectName">Visible</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">542</int>
+ <reference key="object" ref="934915496"/>
+ <reference key="parent" ref="336088134"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">545</int>
+ <reference key="object" ref="886444468"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="67668546"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">546</int>
+ <reference key="object" ref="67668546"/>
+ <reference key="parent" ref="886444468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">539</int>
+ <reference key="object" ref="186246764"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="171036244"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ <string key="objectName">Rotation</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">540</int>
+ <reference key="object" ref="171036244"/>
+ <reference key="parent" ref="186246764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">543</int>
+ <reference key="object" ref="482000415"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="575979405"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">544</int>
+ <reference key="object" ref="575979405"/>
+ <reference key="parent" ref="482000415"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">552</int>
+ <reference key="object" ref="969295846"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1043401668"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ <string key="objectName">Text</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">553</int>
+ <reference key="object" ref="1043401668"/>
+ <reference key="parent" ref="969295846"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">554</int>
+ <reference key="object" ref="301002623"/>
+ <reference key="parent" ref="439893737"/>
+ <string key="objectName">SFML view</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">564</int>
+ <reference key="object" ref="531630843"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1053978795"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">565</int>
+ <reference key="object" ref="1053978795"/>
+ <reference key="parent" ref="531630843"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">568</int>
+ <reference key="object" ref="422780221"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="702743979"/>
+ </object>
+ <reference key="parent" ref="439893737"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">569</int>
+ <reference key="object" ref="702743979"/>
+ <reference key="parent" ref="422780221"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.IBPluginDependency</string>
+ <string>-3.IBPluginDependency</string>
+ <string>112.IBPluginDependency</string>
+ <string>124.IBPluginDependency</string>
+ <string>125.IBPluginDependency</string>
+ <string>126.IBPluginDependency</string>
+ <string>129.IBPluginDependency</string>
+ <string>130.IBPluginDependency</string>
+ <string>131.IBPluginDependency</string>
+ <string>134.IBPluginDependency</string>
+ <string>136.IBPluginDependency</string>
+ <string>143.IBPluginDependency</string>
+ <string>144.IBPluginDependency</string>
+ <string>145.IBPluginDependency</string>
+ <string>149.IBPluginDependency</string>
+ <string>150.IBPluginDependency</string>
+ <string>19.IBPluginDependency</string>
+ <string>195.IBPluginDependency</string>
+ <string>196.IBPluginDependency</string>
+ <string>197.IBPluginDependency</string>
+ <string>198.IBPluginDependency</string>
+ <string>199.IBPluginDependency</string>
+ <string>200.IBPluginDependency</string>
+ <string>201.IBPluginDependency</string>
+ <string>202.IBPluginDependency</string>
+ <string>203.IBPluginDependency</string>
+ <string>204.IBPluginDependency</string>
+ <string>205.IBPluginDependency</string>
+ <string>206.IBPluginDependency</string>
+ <string>207.IBPluginDependency</string>
+ <string>208.IBPluginDependency</string>
+ <string>209.IBPluginDependency</string>
+ <string>210.IBPluginDependency</string>
+ <string>211.IBPluginDependency</string>
+ <string>212.IBPluginDependency</string>
+ <string>213.IBPluginDependency</string>
+ <string>214.IBPluginDependency</string>
+ <string>215.IBPluginDependency</string>
+ <string>216.IBPluginDependency</string>
+ <string>217.IBPluginDependency</string>
+ <string>218.IBPluginDependency</string>
+ <string>219.IBPluginDependency</string>
+ <string>220.IBPluginDependency</string>
+ <string>221.IBPluginDependency</string>
+ <string>23.IBPluginDependency</string>
+ <string>236.IBPluginDependency</string>
+ <string>239.IBPluginDependency</string>
+ <string>24.IBPluginDependency</string>
+ <string>29.IBPluginDependency</string>
+ <string>295.IBPluginDependency</string>
+ <string>296.IBPluginDependency</string>
+ <string>297.IBPluginDependency</string>
+ <string>298.IBPluginDependency</string>
+ <string>346.IBPluginDependency</string>
+ <string>348.IBPluginDependency</string>
+ <string>349.IBPluginDependency</string>
+ <string>350.IBPluginDependency</string>
+ <string>351.IBPluginDependency</string>
+ <string>354.IBPluginDependency</string>
+ <string>371.IBNSWindowAutoPositionCentersHorizontal</string>
+ <string>371.IBNSWindowAutoPositionCentersVertical</string>
+ <string>371.IBPluginDependency</string>
+ <string>371.IBWindowTemplateEditedContentRect</string>
+ <string>371.NSWindowTemplate.visibleAtLaunch</string>
+ <string>372.IBPluginDependency</string>
+ <string>375.IBPluginDependency</string>
+ <string>376.IBPluginDependency</string>
+ <string>377.IBPluginDependency</string>
+ <string>388.IBPluginDependency</string>
+ <string>389.IBPluginDependency</string>
+ <string>390.IBPluginDependency</string>
+ <string>391.IBPluginDependency</string>
+ <string>392.IBPluginDependency</string>
+ <string>393.IBPluginDependency</string>
+ <string>394.IBPluginDependency</string>
+ <string>395.IBPluginDependency</string>
+ <string>396.IBPluginDependency</string>
+ <string>397.IBPluginDependency</string>
+ <string>398.IBPluginDependency</string>
+ <string>399.IBPluginDependency</string>
+ <string>400.IBPluginDependency</string>
+ <string>401.IBPluginDependency</string>
+ <string>402.IBPluginDependency</string>
+ <string>403.IBPluginDependency</string>
+ <string>404.IBPluginDependency</string>
+ <string>405.IBPluginDependency</string>
+ <string>406.IBPluginDependency</string>
+ <string>407.IBPluginDependency</string>
+ <string>408.IBPluginDependency</string>
+ <string>409.IBPluginDependency</string>
+ <string>410.IBPluginDependency</string>
+ <string>411.IBPluginDependency</string>
+ <string>412.IBPluginDependency</string>
+ <string>413.IBPluginDependency</string>
+ <string>414.IBPluginDependency</string>
+ <string>415.IBPluginDependency</string>
+ <string>416.IBPluginDependency</string>
+ <string>417.IBPluginDependency</string>
+ <string>418.IBPluginDependency</string>
+ <string>419.IBPluginDependency</string>
+ <string>420.IBPluginDependency</string>
+ <string>450.IBPluginDependency</string>
+ <string>451.IBPluginDependency</string>
+ <string>452.IBPluginDependency</string>
+ <string>453.IBPluginDependency</string>
+ <string>454.IBPluginDependency</string>
+ <string>457.IBPluginDependency</string>
+ <string>459.IBPluginDependency</string>
+ <string>460.IBPluginDependency</string>
+ <string>462.IBPluginDependency</string>
+ <string>465.IBPluginDependency</string>
+ <string>466.IBPluginDependency</string>
+ <string>485.IBPluginDependency</string>
+ <string>490.IBPluginDependency</string>
+ <string>491.IBPluginDependency</string>
+ <string>492.IBPluginDependency</string>
+ <string>494.IBPluginDependency</string>
+ <string>496.IBPluginDependency</string>
+ <string>497.IBPluginDependency</string>
+ <string>498.IBPluginDependency</string>
+ <string>499.IBPluginDependency</string>
+ <string>5.IBPluginDependency</string>
+ <string>500.IBPluginDependency</string>
+ <string>501.IBPluginDependency</string>
+ <string>502.IBPluginDependency</string>
+ <string>503.IBPluginDependency</string>
+ <string>504.IBPluginDependency</string>
+ <string>505.IBPluginDependency</string>
+ <string>506.IBPluginDependency</string>
+ <string>507.IBPluginDependency</string>
+ <string>508.IBPluginDependency</string>
+ <string>509.IBPluginDependency</string>
+ <string>510.IBPluginDependency</string>
+ <string>511.IBPluginDependency</string>
+ <string>512.IBPluginDependency</string>
+ <string>513.IBPluginDependency</string>
+ <string>514.IBPluginDependency</string>
+ <string>515.IBPluginDependency</string>
+ <string>516.IBPluginDependency</string>
+ <string>517.IBPluginDependency</string>
+ <string>533.IBPluginDependency</string>
+ <string>534.IBPluginDependency</string>
+ <string>535.IBPluginDependency</string>
+ <string>536.IBPluginDependency</string>
+ <string>537.IBPluginDependency</string>
+ <string>537.object.labelIdentifier</string>
+ <string>538.IBPluginDependency</string>
+ <string>539.IBPluginDependency</string>
+ <string>540.IBPluginDependency</string>
+ <string>541.IBPluginDependency</string>
+ <string>542.IBPluginDependency</string>
+ <string>543.IBPluginDependency</string>
+ <string>544.IBPluginDependency</string>
+ <string>545.IBPluginDependency</string>
+ <string>546.IBPluginDependency</string>
+ <string>552.IBPluginDependency</string>
+ <string>553.IBPluginDependency</string>
+ <string>554.IBPluginDependency</string>
+ <string>56.IBPluginDependency</string>
+ <string>564.IBPluginDependency</string>
+ <string>565.IBPluginDependency</string>
+ <string>568.IBPluginDependency</string>
+ <string>569.IBPluginDependency</string>
+ <string>57.IBPluginDependency</string>
+ <string>58.IBPluginDependency</string>
+ <string>72.IBPluginDependency</string>
+ <string>73.IBPluginDependency</string>
+ <string>74.IBPluginDependency</string>
+ <string>75.IBPluginDependency</string>
+ <string>77.IBPluginDependency</string>
+ <string>78.IBPluginDependency</string>
+ <string>79.IBPluginDependency</string>
+ <string>80.IBPluginDependency</string>
+ <string>81.IBPluginDependency</string>
+ <string>82.IBPluginDependency</string>
+ <string>83.IBPluginDependency</string>
+ <string>92.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO"/>
+ <boolean value="NO"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{380, 496}, {480, 360}}</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>IBBuiltInLabel-Red</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">570</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">CocoaAppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>colorChanged:</string>
+ <string>rotationChanged:</string>
+ <string>textChanged:</string>
+ <string>updateText:</string>
+ <string>visibleChanged:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSPopUpButton</string>
+ <string>NSSlider</string>
+ <string>NSTextField</string>
+ <string>NSButton</string>
+ <string>NSButton</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>colorChanged:</string>
+ <string>rotationChanged:</string>
+ <string>textChanged:</string>
+ <string>updateText:</string>
+ <string>visibleChanged:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">colorChanged:</string>
+ <string key="candidateClassName">NSPopUpButton</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">rotationChanged:</string>
+ <string key="candidateClassName">NSSlider</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">textChanged:</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">updateText:</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">visibleChanged:</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>sfmlView</string>
+ <string>textField</string>
+ <string>window</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSView</string>
+ <string>NSTextField</string>
+ <string>NSWindow</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>sfmlView</string>
+ <string>textField</string>
+ <string>window</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">sfmlView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">textField</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">window</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/CocoaAppDelegate.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSDocument</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>printDocument:</string>
+ <string>revertDocumentToSaved:</string>
+ <string>runPageLayout:</string>
+ <string>saveDocument:</string>
+ <string>saveDocumentAs:</string>
+ <string>saveDocumentTo:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>printDocument:</string>
+ <string>revertDocumentToSaved:</string>
+ <string>runPageLayout:</string>
+ <string>saveDocument:</string>
+ <string>saveDocumentAs:</string>
+ <string>saveDocumentTo:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">printDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">revertDocumentToSaved:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">runPageLayout:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocumentAs:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocumentTo:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/NSDocument.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="3000" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSMenuCheckmark</string>
+ <string>NSMenuMixedState</string>
+ <string>NSSwitch</string>
+ <string>blue</string>
+ <string>green</string>
+ <string>red</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{9, 8}</string>
+ <string>{7, 2}</string>
+ <string>{15, 15}</string>
+ <string>{16, 16}</string>
+ <string>{16, 16}</string>
+ <string>{16, 16}</string>
+ </object>
+ </object>
+ </data>
+</archive>
diff --git a/examples/cocoa/NSString+stdstring.h b/examples/cocoa/NSString+stdstring.h
new file mode 100644
index 0000000..cce9bd8
--- /dev/null
+++ b/examples/cocoa/NSString+stdstring.h
@@ -0,0 +1,39 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+#import <string>
+#import <Foundation/Foundation.h>
+
+@interface NSString (NSString_stdstring)
+
++(id)stringWithstdstring:(const std::string&)string;
+
++(id)stringWithstdwstring:(const std::wstring&)string;
+
+-(std::string)tostdstring;
+
+-(std::wstring)tostdwstring;
+
+@end
diff --git a/examples/cocoa/NSString+stdstring.mm b/examples/cocoa/NSString+stdstring.mm
new file mode 100644
index 0000000..92b7984
--- /dev/null
+++ b/examples/cocoa/NSString+stdstring.mm
@@ -0,0 +1,73 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+#import "NSString+stdstring.h"
+#include <SFML/System/Utf.hpp>
+
+@implementation NSString (NSString_stdstring)
+
++(id)stringWithstdstring:(const std::string&)string
+{
+ std::string utf8;
+ utf8.reserve(string.size() + 1);
+
+ sf::Utf8::fromAnsi(string.begin(), string.end(), std::back_inserter(utf8));
+
+ NSString* str = [NSString stringWithCString:utf8.c_str()
+ encoding:NSUTF8StringEncoding];
+ return str;
+}
+
++(id)stringWithstdwstring:(const std::wstring&)string
+{
+ char* data = (char*)string.data();
+ unsigned size = string.size() * sizeof(wchar_t);
+
+ NSString* str = [[[NSString alloc] initWithBytes:data length:size
+ encoding:NSUTF32LittleEndianStringEncoding] autorelease];
+ return str;
+}
+
+-(std::string)tostdstring
+{
+ // Not sure about the encoding to use. Using [self UTF8String] doesn't
+ // work for characters like é or à.
+ const char *cstr = [self cStringUsingEncoding:NSISOLatin1StringEncoding];
+
+ if (cstr != NULL)
+ return std::string(cstr);
+ else
+ return "";
+}
+
+-(std::wstring)tostdwstring
+{
+ // According to Wikipedia, Mac OS X is Little Endian on x86 and x86-64
+ // https://en.wikipedia.org/wiki/Endianness
+ NSData* asData = [self dataUsingEncoding:NSUTF32LittleEndianStringEncoding];
+ return std::wstring((wchar_t*)[asData bytes], [asData length] / sizeof(wchar_t));
+}
+
+@end
diff --git a/examples/cocoa/main.m b/examples/cocoa/main.m
new file mode 100644
index 0000000..b7aa944
--- /dev/null
+++ b/examples/cocoa/main.m
@@ -0,0 +1,31 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char *argv[])
+{
+ return NSApplicationMain(argc, (const char **)argv);
+}
diff --git a/examples/cocoa/readme.txt b/examples/cocoa/readme.txt
new file mode 100644
index 0000000..8636b1d
--- /dev/null
+++ b/examples/cocoa/readme.txt
@@ -0,0 +1,28 @@
+SFML IN COCOA APPLICATION
+=========================
+
+This is a small example of the integration of SFML in a Cocoa application.
+
+Features
+--------
+
+ * This example shows how basic UI elements can interact with SFML
+ render areas such as sf::RenderWindow (you can use sf::Window and
+ OpenGL code too, of course).
+ * It also provides tools for converting NSString to and from
+ std::[w]string in an Objective-C Category of NSString.
+ * Moreover, it shows how you can prevent annoying the system alerts
+ produced when the SFML view has focus and the user press a key
+ (see SilentWindow interface in CocoaAppDelegate.[h|mm]).
+
+Special Considerations
+----------------------
+
+While mixing SFML into a Cocoa application you have to deal with mixing
+C++ and Objective-C. In order to proceed you should use .mm extension for
+Objective-C++ files.
+
+Be aware of the limitations of Objective-C++. Please refer to the official
+documentation provided by Apple for more information.
+
+You can also work around these limitations by using CSFML.
diff --git a/examples/cocoa/resources/Cocoa-Info.plist b/examples/cocoa/resources/Cocoa-Info.plist
new file mode 100644
index 0000000..1348f3c
--- /dev/null
+++ b/examples/cocoa/resources/Cocoa-Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>cocoa</string>
+ <key>CFBundleIconFile</key>
+ <string>icon.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.sfml-dev.cocoa</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>cocoa</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.6</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2007-2018 Marco Antognini and Laurent Gomila. Shared under zlib/libpng License.</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+</dict>
+</plist>
diff --git a/examples/cocoa/resources/Credits.rtf b/examples/cocoa/resources/Credits.rtf
new file mode 100644
index 0000000..ed40d67
--- /dev/null
+++ b/examples/cocoa/resources/Credits.rtf
@@ -0,0 +1,7 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf230
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\paperw11900\paperh16840\vieww9600\viewh8400\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj
+
+\f0\fs24 \cf0 See {\field{\*\fldinst{HYPERLINK "https://sfml-dev.org"}}{\fldrslt https://sfml-dev.org}} for more information}
diff --git a/examples/cocoa/resources/blue.png b/examples/cocoa/resources/blue.png
new file mode 100644
index 0000000..8945e85
--- /dev/null
+++ b/examples/cocoa/resources/blue.png
Binary files differ
diff --git a/examples/cocoa/resources/green.png b/examples/cocoa/resources/green.png
new file mode 100644
index 0000000..fac1b69
--- /dev/null
+++ b/examples/cocoa/resources/green.png
Binary files differ
diff --git a/examples/cocoa/resources/icon.icns b/examples/cocoa/resources/icon.icns
new file mode 100644
index 0000000..cb95460
--- /dev/null
+++ b/examples/cocoa/resources/icon.icns
Binary files differ
diff --git a/examples/cocoa/resources/logo.png b/examples/cocoa/resources/logo.png
new file mode 100644
index 0000000..7b04c41
--- /dev/null
+++ b/examples/cocoa/resources/logo.png
Binary files differ
diff --git a/examples/cocoa/resources/red.png b/examples/cocoa/resources/red.png
new file mode 100644
index 0000000..731f36b
--- /dev/null
+++ b/examples/cocoa/resources/red.png
Binary files differ
diff --git a/examples/cocoa/resources/sansation.ttf b/examples/cocoa/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/cocoa/resources/sansation.ttf
Binary files differ
diff --git a/examples/ftp/CMakeLists.txt b/examples/ftp/CMakeLists.txt
new file mode 100644
index 0000000..a65cb67
--- /dev/null
+++ b/examples/ftp/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/ftp)
+
+# all source files
+set(SRC ${SRCROOT}/Ftp.cpp)
+
+# define the ftp target
+sfml_add_example(ftp
+ SOURCES ${SRC}
+ DEPENDS sfml-network)
diff --git a/examples/ftp/Ftp.cpp b/examples/ftp/Ftp.cpp
new file mode 100644
index 0000000..e4de8ad
--- /dev/null
+++ b/examples/ftp/Ftp.cpp
@@ -0,0 +1,206 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network.hpp>
+#include <fstream>
+#include <iostream>
+
+
+////////////////////////////////////////////////////////////
+/// Print a FTP response into a standard output stream
+///
+////////////////////////////////////////////////////////////
+std::ostream& operator <<(std::ostream& stream, const sf::Ftp::Response& response)
+{
+ return stream << response.getStatus() << response.getMessage();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Choose the server address
+ sf::IpAddress address;
+ do
+ {
+ std::cout << "Enter the FTP server address: ";
+ std::cin >> address;
+ }
+ while (address == sf::IpAddress::None);
+
+ // Connect to the server
+ sf::Ftp server;
+ sf::Ftp::Response connectResponse = server.connect(address);
+ std::cout << connectResponse << std::endl;
+ if (!connectResponse.isOk())
+ return EXIT_FAILURE;
+
+ // Ask for user name and password
+ std::string user, password;
+ std::cout << "User name: ";
+ std::cin >> user;
+ std::cout << "Password: ";
+ std::cin >> password;
+
+ // Login to the server
+ sf::Ftp::Response loginResponse = server.login(user, password);
+ std::cout << loginResponse << std::endl;
+ if (!loginResponse.isOk())
+ return EXIT_FAILURE;
+
+ // Main menu
+ int choice = 0;
+ do
+ {
+ // Main FTP menu
+ std::cout << std::endl;
+ std::cout << "Choose an action:" << std::endl;
+ std::cout << "1. Print working directory" << std::endl;
+ std::cout << "2. Print contents of working directory" << std::endl;
+ std::cout << "3. Change directory" << std::endl;
+ std::cout << "4. Create directory" << std::endl;
+ std::cout << "5. Delete directory" << std::endl;
+ std::cout << "6. Rename file" << std::endl;
+ std::cout << "7. Remove file" << std::endl;
+ std::cout << "8. Download file" << std::endl;
+ std::cout << "9. Upload file" << std::endl;
+ std::cout << "0. Disconnect" << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "Your choice: ";
+ std::cin >> choice;
+ std::cout << std::endl;
+
+ switch (choice)
+ {
+ default:
+ {
+ // Wrong choice
+ std::cout << "Invalid choice!" << std::endl;
+ std::cin.clear();
+ std::cin.ignore(10000, '\n');
+ break;
+ }
+
+ case 1:
+ {
+ // Print the current server directory
+ sf::Ftp::DirectoryResponse response = server.getWorkingDirectory();
+ std::cout << response << std::endl;
+ std::cout << "Current directory is " << response.getDirectory() << std::endl;
+ break;
+ }
+
+ case 2:
+ {
+ // Print the contents of the current server directory
+ sf::Ftp::ListingResponse response = server.getDirectoryListing();
+ std::cout << response << std::endl;
+ const std::vector<std::string>& names = response.getListing();
+ for (std::vector<std::string>::const_iterator it = names.begin(); it != names.end(); ++it)
+ std::cout << *it << std::endl;
+ break;
+ }
+
+ case 3:
+ {
+ // Change the current directory
+ std::string directory;
+ std::cout << "Choose a directory: ";
+ std::cin >> directory;
+ std::cout << server.changeDirectory(directory) << std::endl;
+ break;
+ }
+
+ case 4:
+ {
+ // Create a new directory
+ std::string directory;
+ std::cout << "Name of the directory to create: ";
+ std::cin >> directory;
+ std::cout << server.createDirectory(directory) << std::endl;
+ break;
+ }
+
+ case 5:
+ {
+ // Remove an existing directory
+ std::string directory;
+ std::cout << "Name of the directory to remove: ";
+ std::cin >> directory;
+ std::cout << server.deleteDirectory(directory) << std::endl;
+ break;
+ }
+
+ case 6:
+ {
+ // Rename a file
+ std::string source, destination;
+ std::cout << "Name of the file to rename: ";
+ std::cin >> source;
+ std::cout << "New name: ";
+ std::cin >> destination;
+ std::cout << server.renameFile(source, destination) << std::endl;
+ break;
+ }
+
+ case 7:
+ {
+ // Remove an existing directory
+ std::string filename;
+ std::cout << "Name of the file to remove: ";
+ std::cin >> filename;
+ std::cout << server.deleteFile(filename) << std::endl;
+ break;
+ }
+
+ case 8:
+ {
+ // Download a file from server
+ std::string filename, directory;
+ std::cout << "Filename of the file to download (relative to current directory): ";
+ std::cin >> filename;
+ std::cout << "Directory to download the file to: ";
+ std::cin >> directory;
+ std::cout << server.download(filename, directory) << std::endl;
+ break;
+ }
+
+ case 9:
+ {
+ // Upload a file to server
+ std::string filename, directory;
+ std::cout << "Path of the file to upload (absolute or relative to working directory): ";
+ std::cin >> filename;
+ std::cout << "Directory to upload the file to (relative to current directory): ";
+ std::cin >> directory;
+ std::cout << server.upload(filename, directory) << std::endl;
+ break;
+ }
+
+ case 0:
+ {
+ // Disconnect
+ break;
+ }
+ }
+
+ } while (choice != 0);
+
+ // Disconnect from the server
+ std::cout << "Disconnecting from server..." << std::endl;
+ std::cout << server.disconnect() << std::endl;
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to exit..." << std::endl;
+ std::cin.ignore(10000, '\n');
+ std::cin.ignore(10000, '\n');
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/iOS/CMakeLists.txt b/examples/iOS/CMakeLists.txt
new file mode 100644
index 0000000..24aca5f
--- /dev/null
+++ b/examples/iOS/CMakeLists.txt
@@ -0,0 +1,25 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/iOS)
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
+
+# All source files
+set(SRC ${SRCROOT}/main.cpp)
+
+set(RESOURCES
+ ${SRCROOT}/resources/canary.wav
+ ${SRCROOT}/resources/image.png
+ ${SRCROOT}/resources/orchestral.ogg
+ ${SRCROOT}/resources/sansation.ttf)
+
+set_source_files_properties( ${RESOURCES} PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources )
+
+# Define the window target
+sfml_add_example(ios_demo GUI_APP
+ SOURCES ${SRC} ${RESOURCES}
+ DEPENDS sfml-window sfml-system sfml-graphics sfml-audio
+ "-framework OpenGLES")
+
+# The app needs an identifier and signing to work correctly
+sfml_set_xcode_property(ios_demo CODE_SIGN_IDENTITY "iPhone Developer")
+set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.sfml.ios_demo")
diff --git a/examples/iOS/main.cpp b/examples/iOS/main.cpp
new file mode 100644
index 0000000..473b2b9
--- /dev/null
+++ b/examples/iOS/main.cpp
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <SFML/Audio.hpp>
+#include <SFML/Main.hpp>
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "");
+
+ sf::Texture texture;
+ if(!texture.loadFromFile("image.png"))
+ return EXIT_FAILURE;
+
+ sf::Sprite image(texture);
+ image.setPosition(0, 0);
+ image.setOrigin(texture.getSize().x/2, texture.getSize().y/2);
+
+ sf::Music music;
+ if(!music.openFromFile("canary.wav"))
+ return EXIT_FAILURE;
+
+ music.play();
+
+ sf::View view = window.getDefaultView();
+
+ while (window.isOpen())
+ {
+ sf::Event event;
+
+ while (window.pollEvent(event))
+ {
+ switch (event.type)
+ {
+ case sf::Event::Closed:
+ window.close();
+ break;
+ case sf::Event::Resized:
+ view.setSize(event.size.width, event.size.height);
+ view.setCenter(event.size.width/2, event.size.height/2);
+ window.setView(view);
+ break;
+ case sf::Event::TouchBegan:
+ if (event.touch.finger == 0)
+ {
+ image.setPosition(event.touch.x, event.touch.y);
+ }
+ break;
+ }
+ }
+
+ window.clear(sf::Color::White);
+ window.draw(image);
+ window.display();
+ }
+}
+
diff --git a/examples/iOS/resources/image.png b/examples/iOS/resources/image.png
new file mode 100644
index 0000000..29ba010
--- /dev/null
+++ b/examples/iOS/resources/image.png
Binary files differ
diff --git a/examples/iOS/resources/sansation.ttf b/examples/iOS/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/iOS/resources/sansation.ttf
Binary files differ
diff --git a/examples/island/CMakeLists.txt b/examples/island/CMakeLists.txt
new file mode 100644
index 0000000..38428e3
--- /dev/null
+++ b/examples/island/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/island)
+
+# all source files
+set(SRC ${SRCROOT}/Island.cpp)
+
+# define the island target
+sfml_add_example(island GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-graphics sfml-window sfml-system
+ RESOURCES_DIR resources) \ No newline at end of file
diff --git a/examples/island/Island.cpp b/examples/island/Island.cpp
new file mode 100644
index 0000000..50a8f1e
--- /dev/null
+++ b/examples/island/Island.cpp
@@ -0,0 +1,590 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#define STB_PERLIN_IMPLEMENTATION
+#include "stb_perlin.h"
+#include <SFML/Graphics.hpp>
+#include <vector>
+#include <deque>
+#include <sstream>
+#include <algorithm>
+#include <cstring>
+#include <cmath>
+
+
+namespace
+{
+ // Width and height of the application window
+ const unsigned int windowWidth = 800;
+ const unsigned int windowHeight = 600;
+
+ // Resolution of the generated terrain
+ const unsigned int resolutionX = 800;
+ const unsigned int resolutionY = 600;
+
+ // Thread pool parameters
+ const unsigned int threadCount = 4;
+ const unsigned int blockCount = 32;
+
+ struct WorkItem
+ {
+ sf::Vertex* targetBuffer;
+ unsigned int index;
+ };
+
+ std::deque<WorkItem> workQueue;
+ std::vector<sf::Thread*> threads;
+ int pendingWorkCount = 0;
+ bool workPending = true;
+ bool bufferUploadPending = false;
+ sf::Mutex workQueueMutex;
+
+ struct Setting
+ {
+ const char* name;
+ float* value;
+ };
+
+ // Terrain noise parameters
+ const int perlinOctaves = 3;
+
+ float perlinFrequency = 7.0f;
+ float perlinFrequencyBase = 4.0f;
+
+ // Terrain generation parameters
+ float heightBase = 0.0f;
+ float edgeFactor = 0.9f;
+ float edgeDropoffExponent = 1.5f;
+
+ float snowcapHeight = 0.6f;
+
+ // Terrain lighting parameters
+ float heightFactor = windowHeight / 2.0f;
+ float heightFlatten = 3.0f;
+ float lightFactor = 0.7f;
+}
+
+
+// Forward declarations of the functions we define further down
+void threadFunction();
+void generateTerrain(sf::Vertex* vertexBuffer);
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Create the window of the application
+ sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "SFML Island",
+ sf::Style::Titlebar | sf::Style::Close);
+ window.setVerticalSyncEnabled(true);
+
+ sf::Font font;
+ if (!font.loadFromFile("resources/sansation.ttf"))
+ return EXIT_FAILURE;
+
+ // Create all of our graphics resources
+ sf::Text hudText;
+ sf::Text statusText;
+ sf::Shader terrainShader;
+ sf::RenderStates terrainStates(&terrainShader);
+ sf::VertexBuffer terrain(sf::Triangles, sf::VertexBuffer::Static);
+
+ // Set up our text drawables
+ statusText.setFont(font);
+ statusText.setCharacterSize(28);
+ statusText.setFillColor(sf::Color::White);
+ statusText.setOutlineColor(sf::Color::Black);
+ statusText.setOutlineThickness(2.0f);
+
+ hudText.setFont(font);
+ hudText.setCharacterSize(14);
+ hudText.setFillColor(sf::Color::White);
+ hudText.setOutlineColor(sf::Color::Black);
+ hudText.setOutlineThickness(2.0f);
+ hudText.setPosition(5.0f, 5.0f);
+
+ // Staging buffer for our terrain data that we will upload to our VertexBuffer
+ std::vector<sf::Vertex> terrainStagingBuffer;
+
+ // Check whether the prerequisites are suppprted
+ bool prerequisitesSupported = sf::VertexBuffer::isAvailable() && sf::Shader::isAvailable();
+
+ // Set up our graphics resources and set the status text accordingly
+ if (!prerequisitesSupported)
+ {
+ statusText.setString("Shaders and/or Vertex Buffers Unsupported");
+ }
+ else if (!terrainShader.loadFromFile("resources/terrain.vert", "resources/terrain.frag"))
+ {
+ prerequisitesSupported = false;
+
+ statusText.setString("Failed to load shader program");
+ }
+ else
+ {
+ // Start up our thread pool
+ for (unsigned int i = 0; i < threadCount; i++)
+ {
+ threads.push_back(new sf::Thread(threadFunction));
+ threads.back()->launch();
+ }
+
+ // Create our VertexBuffer with enough space to hold all the terrain geometry
+ terrain.create(resolutionX * resolutionY * 6);
+
+ // Resize the staging buffer to be able to hold all the terrain geometry
+ terrainStagingBuffer.resize(resolutionX * resolutionY * 6);
+
+ // Generate the initial terrain
+ generateTerrain(&terrainStagingBuffer[0]);
+
+ statusText.setString("Generating Terrain...");
+ }
+
+ // Center the status text
+ statusText.setPosition((windowWidth - statusText.getLocalBounds().width) / 2.f, (windowHeight - statusText.getLocalBounds().height) / 2.f);
+
+ // Set up an array of pointers to our settings for arrow navigation
+ Setting settings[] =
+ {
+ {"perlinFrequency", &perlinFrequency},
+ {"perlinFrequencyBase", &perlinFrequencyBase},
+ {"heightBase", &heightBase},
+ {"edgeFactor", &edgeFactor},
+ {"edgeDropoffExponent", &edgeDropoffExponent},
+ {"snowcapHeight", &snowcapHeight},
+ {"heightFactor", &heightFactor},
+ {"heightFlatten", &heightFlatten},
+ {"lightFactor", &lightFactor}
+ };
+
+ const int settingCount = 9;
+ int currentSetting = 0;
+
+ std::ostringstream osstr;
+ sf::Clock clock;
+
+ while (window.isOpen())
+ {
+ // Handle events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Window closed or escape key pressed: exit
+ if ((event.type == sf::Event::Closed) ||
+ ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
+ {
+ window.close();
+ break;
+ }
+
+ // Arrow key pressed:
+ if (prerequisitesSupported && (event.type == sf::Event::KeyPressed))
+ {
+ switch (event.key.code)
+ {
+ case sf::Keyboard::Return: generateTerrain(&terrainStagingBuffer[0]); break;
+ case sf::Keyboard::Down: currentSetting = (currentSetting + 1) % settingCount; break;
+ case sf::Keyboard::Up: currentSetting = (currentSetting + settingCount - 1) % settingCount; break;
+ case sf::Keyboard::Left: *(settings[currentSetting].value) -= 0.1f; break;
+ case sf::Keyboard::Right: *(settings[currentSetting].value) += 0.1f; break;
+ default: break;
+ }
+ }
+ }
+
+ // Clear, draw graphics objects and display
+ window.clear();
+
+ window.draw(statusText);
+
+ if (prerequisitesSupported)
+ {
+ {
+ sf::Lock lock(workQueueMutex);
+
+ // Don't bother updating/drawing the VertexBuffer while terrain is being regenerated
+ if (!pendingWorkCount)
+ {
+ // If there is new data pending to be uploaded to the VertexBuffer, do it now
+ if (bufferUploadPending)
+ {
+ terrain.update(&terrainStagingBuffer[0]);
+ bufferUploadPending = false;
+ }
+
+ terrainShader.setUniform("lightFactor", lightFactor);
+ window.draw(terrain, terrainStates);
+ }
+ }
+
+ // Update and draw the HUD text
+ osstr.str("");
+ osstr << "Frame: " << clock.restart().asMilliseconds() << "ms\n"
+ << "perlinOctaves: " << perlinOctaves << "\n\n"
+ << "Use the arrow keys to change the values.\nUse the return key to regenerate the terrain.\n\n";
+
+ for (int i = 0; i < settingCount; ++i)
+ osstr << ((i == currentSetting) ? ">> " : " ") << settings[i].name << ": " << *(settings[i].value) << "\n";
+
+ hudText.setString(osstr.str());
+
+ window.draw(hudText);
+ }
+
+ // Display things on screen
+ window.display();
+ }
+
+ // Shut down our thread pool
+ {
+ sf::Lock lock(workQueueMutex);
+ workPending = false;
+ }
+
+ while (!threads.empty())
+ {
+ threads.back()->wait();
+ delete threads.back();
+ threads.pop_back();
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the terrain elevation at the given coordinates.
+///
+////////////////////////////////////////////////////////////
+float getElevation(float x, float y)
+{
+ x = x / resolutionX - 0.5f;
+ y = y / resolutionY - 0.5f;
+
+ float elevation = 0.0f;
+
+ for (int i = 0; i < perlinOctaves; i++)
+ {
+ elevation += stb_perlin_noise3(
+ x * perlinFrequency * std::pow(perlinFrequencyBase, i),
+ y * perlinFrequency * std::pow(perlinFrequencyBase, i),
+ 0, 0, 0, 0
+ ) * std::pow(perlinFrequencyBase, -i);
+ }
+
+ elevation = (elevation + 1.f) / 2.f;
+
+ float distance = 2.0f * std::sqrt(x * x + y * y);
+ elevation = (elevation + heightBase) * (1.0f - edgeFactor * std::pow(distance, edgeDropoffExponent));
+ elevation = std::min(std::max(elevation, 0.0f), 1.0f);
+
+ return elevation;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the terrain moisture at the given coordinates.
+///
+////////////////////////////////////////////////////////////
+float getMoisture(float x, float y)
+{
+ x = x / resolutionX - 0.5f;
+ y = y / resolutionY - 0.5f;
+
+ float moisture = stb_perlin_noise3(
+ x * 4.f + 0.5f,
+ y * 4.f + 0.5f,
+ 0, 0, 0, 0
+ );
+
+ return (moisture + 1.f) / 2.f;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the lowlands terrain color for the given moisture.
+///
+////////////////////////////////////////////////////////////
+sf::Color getLowlandsTerrainColor(float moisture)
+{
+ sf::Color color =
+ moisture < 0.27f ? sf::Color(240, 240, 180) :
+ moisture < 0.3f ? sf::Color(240 - 240 * (moisture - 0.27f) / 0.03f, 240 - 40 * (moisture - 0.27f) / 0.03f, 180 - 180 * (moisture - 0.27f) / 0.03f) :
+ moisture < 0.4f ? sf::Color(0, 200, 0) :
+ moisture < 0.48f ? sf::Color(0, 200 - 40 * (moisture - 0.4f) / 0.08f, 0) :
+ moisture < 0.6f ? sf::Color(0, 160, 0) :
+ moisture < 0.7f ? sf::Color(34 * (moisture - 0.6f) / 0.1f, 160 - 60 * (moisture - 0.6f) / 0.1f, 34 * (moisture - 0.6f) / 0.1f) :
+ sf::Color(34, 100, 34);
+
+ return color;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the highlands terrain color for the given elevation
+/// and moisture.
+///
+////////////////////////////////////////////////////////////
+sf::Color getHighlandsTerrainColor(float elevation, float moisture)
+{
+ sf::Color lowlandsColor = getLowlandsTerrainColor(moisture);
+
+ sf::Color color =
+ moisture < 0.6f ? sf::Color(112, 128, 144) :
+ sf::Color(112 + 110 * (moisture - 0.6f) / 0.4f, 128 + 56 * (moisture - 0.6f) / 0.4f, 144 - 9 * (moisture - 0.6f) / 0.4f);
+
+ float factor = std::min((elevation - 0.4f) / 0.1f, 1.f);
+
+ color.r = lowlandsColor.r * (1.f - factor) + color.r * factor;
+ color.g = lowlandsColor.g * (1.f - factor) + color.g * factor;
+ color.b = lowlandsColor.b * (1.f - factor) + color.b * factor;
+
+ return color;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the snowcap terrain color for the given elevation
+/// and moisture.
+///
+////////////////////////////////////////////////////////////
+sf::Color getSnowcapTerrainColor(float elevation, float moisture)
+{
+ sf::Color highlandsColor = getHighlandsTerrainColor(elevation, moisture);
+
+ sf::Color color = sf::Color::White;
+
+ float factor = std::min((elevation - snowcapHeight) / 0.05f, 1.f);
+
+ color.r = highlandsColor.r * (1.f - factor) + color.r * factor;
+ color.g = highlandsColor.g * (1.f - factor) + color.g * factor;
+ color.b = highlandsColor.b * (1.f - factor) + color.b * factor;
+
+ return color;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the terrain color for the given elevation and
+/// moisture.
+///
+////////////////////////////////////////////////////////////
+sf::Color getTerrainColor(float elevation, float moisture)
+{
+ sf::Color color =
+ elevation < 0.11f ? sf::Color(0, 0, elevation / 0.11f * 74.f + 181.0f) :
+ elevation < 0.14f ? sf::Color(std::pow((elevation - 0.11f) / 0.03f, 0.3f) * 48.f, std::pow((elevation - 0.11f) / 0.03f, 0.3f) * 48.f, 255) :
+ elevation < 0.16f ? sf::Color((elevation - 0.14f) * 128.f / 0.02f + 48.f, (elevation - 0.14f) * 128.f / 0.02f + 48.f, 127.0f + (0.16f - elevation) * 128.f / 0.02f) :
+ elevation < 0.17f ? sf::Color(240, 230, 140) :
+ elevation < 0.4f ? getLowlandsTerrainColor(moisture) :
+ elevation < snowcapHeight ? getHighlandsTerrainColor(elevation, moisture) :
+ getSnowcapTerrainColor(elevation, moisture);
+
+ return color;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Compute a compressed representation of the surface
+/// normal based on the given coordinates, and the elevation
+/// of the 4 adjacent neighbours.
+///
+////////////////////////////////////////////////////////////
+sf::Vector2f computeNormal(int x, int y, float left, float right, float bottom, float top)
+{
+ sf::Vector3f deltaX(1, 0, (std::pow(right, heightFlatten) - std::pow(left, heightFlatten)) * heightFactor);
+ sf::Vector3f deltaY(0, 1, (std::pow(top, heightFlatten) - std::pow(bottom, heightFlatten)) * heightFactor);
+
+ sf::Vector3f crossProduct(
+ deltaX.y * deltaY.z - deltaX.z * deltaY.y,
+ deltaX.z * deltaY.x - deltaX.x * deltaY.z,
+ deltaX.x * deltaY.y - deltaX.y * deltaY.x
+ );
+
+ // Scale cross product to make z component 1.0f so we can drop it
+ crossProduct /= crossProduct.z;
+
+ // Return "compressed" normal
+ return sf::Vector2f(crossProduct.x, crossProduct.y);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Process a terrain generation work item. Use the vector
+/// of vertices as scratch memory and upload the data to
+/// the vertex buffer when done.
+///
+////////////////////////////////////////////////////////////
+void processWorkItem(std::vector<sf::Vertex>& vertices, const WorkItem& workItem)
+{
+ unsigned int rowBlockSize = (resolutionY / blockCount) + 1;
+ unsigned int rowStart = rowBlockSize * workItem.index;
+
+ if (rowStart >= resolutionY)
+ return;
+
+ unsigned int rowEnd = std::min(rowStart + rowBlockSize, resolutionY);
+ unsigned int rowCount = rowEnd - rowStart;
+
+ const float scalingFactorX = static_cast<float>(windowWidth) / static_cast<float>(resolutionX);
+ const float scalingFactorY = static_cast<float>(windowHeight) / static_cast<float>(resolutionY);
+
+ for (unsigned int y = rowStart; y < rowEnd; y++)
+ {
+ for (int x = 0; x < resolutionX; x++)
+ {
+ int arrayIndexBase = ((y - rowStart) * resolutionX + x) * 6;
+
+ // Top left corner (first triangle)
+ if (x > 0)
+ {
+ vertices[arrayIndexBase + 0] = vertices[arrayIndexBase - 6 + 5];
+ }
+ else if (y > rowStart)
+ {
+ vertices[arrayIndexBase + 0] = vertices[arrayIndexBase - resolutionX * 6 + 1];
+ }
+ else
+ {
+ vertices[arrayIndexBase + 0].position = sf::Vector2f(x * scalingFactorX, y * scalingFactorY);
+ vertices[arrayIndexBase + 0].color = getTerrainColor(getElevation(x, y), getMoisture(x, y));
+ vertices[arrayIndexBase + 0].texCoords = computeNormal(x, y, getElevation(x - 1, y), getElevation(x + 1, y), getElevation(x, y + 1), getElevation(x, y - 1));
+ }
+
+ // Bottom left corner (first triangle)
+ if (x > 0)
+ {
+ vertices[arrayIndexBase + 1] = vertices[arrayIndexBase - 6 + 2];
+ }
+ else
+ {
+ vertices[arrayIndexBase + 1].position = sf::Vector2f(x * scalingFactorX, (y + 1) * scalingFactorY);
+ vertices[arrayIndexBase + 1].color = getTerrainColor(getElevation(x, y + 1), getMoisture(x, y + 1));
+ vertices[arrayIndexBase + 1].texCoords = computeNormal(x, y + 1, getElevation(x - 1, y + 1), getElevation(x + 1, y + 1), getElevation(x, y + 2), getElevation(x, y));
+ }
+
+ // Bottom right corner (first triangle)
+ vertices[arrayIndexBase + 2].position = sf::Vector2f((x + 1) * scalingFactorX, (y + 1) * scalingFactorY);
+ vertices[arrayIndexBase + 2].color = getTerrainColor(getElevation(x + 1, y + 1), getMoisture(x + 1, y + 1));
+ vertices[arrayIndexBase + 2].texCoords = computeNormal(x + 1, y + 1, getElevation(x, y + 1), getElevation(x + 2, y + 1), getElevation(x + 1, y + 2), getElevation(x + 1, y));
+
+ // Top left corner (second triangle)
+ vertices[arrayIndexBase + 3] = vertices[arrayIndexBase + 0];
+
+ // Bottom right corner (second triangle)
+ vertices[arrayIndexBase + 4] = vertices[arrayIndexBase + 2];
+
+ // Top right corner (second triangle)
+ if (y > rowStart)
+ {
+ vertices[arrayIndexBase + 5] = vertices[arrayIndexBase - resolutionX * 6 + 2];
+ }
+ else
+ {
+ vertices[arrayIndexBase + 5].position = sf::Vector2f((x + 1) * scalingFactorX, y * scalingFactorY);
+ vertices[arrayIndexBase + 5].color = getTerrainColor(getElevation(x + 1, y), getMoisture(x + 1, y));
+ vertices[arrayIndexBase + 5].texCoords = computeNormal(x + 1, y, getElevation(x, y), getElevation(x + 2, y), getElevation(x + 1, y + 1), getElevation(x + 1, y - 1));
+ }
+ }
+ }
+
+ // Copy the resulting geometry from our thread-local buffer into the target buffer
+ std::memcpy(workItem.targetBuffer + (resolutionX * rowStart * 6), &vertices[0], sizeof(sf::Vertex) * resolutionX * rowCount * 6);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Worker thread entry point. We use a thread pool to avoid
+/// the heavy cost of constantly recreating and starting
+/// new threads whenever we need to regenerate the terrain.
+///
+////////////////////////////////////////////////////////////
+void threadFunction()
+{
+ unsigned int rowBlockSize = (resolutionY / blockCount) + 1;
+
+ std::vector<sf::Vertex> vertices(resolutionX * rowBlockSize * 6);
+
+ WorkItem workItem = {0, 0};
+
+ // Loop until the application exits
+ for (;;)
+ {
+ workItem.targetBuffer = 0;
+
+ // Check if there are new work items in the queue
+ {
+ sf::Lock lock(workQueueMutex);
+
+ if (!workPending)
+ return;
+
+ if (!workQueue.empty())
+ {
+ workItem = workQueue.front();
+ workQueue.pop_front();
+ }
+ }
+
+ // If we didn't receive a new work item, keep looping
+ if (!workItem.targetBuffer)
+ {
+ sf::sleep(sf::milliseconds(10));
+
+ continue;
+ }
+
+ processWorkItem(vertices, workItem);
+
+ {
+ sf::Lock lock(workQueueMutex);
+
+ --pendingWorkCount;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Terrain generation entry point. This queues up the
+/// generation work items which the worker threads dequeue
+/// and process.
+///
+////////////////////////////////////////////////////////////
+void generateTerrain(sf::Vertex* buffer)
+{
+ bufferUploadPending = true;
+
+ // Make sure the work queue is empty before queuing new work
+ for (;;)
+ {
+ {
+ sf::Lock lock(workQueueMutex);
+
+ if (workQueue.empty())
+ break;
+ }
+
+ sf::sleep(sf::milliseconds(10));
+ }
+
+ // Queue all the new work items
+ {
+ sf::Lock lock(workQueueMutex);
+
+ for (unsigned int i = 0; i < blockCount; i++)
+ {
+ WorkItem workItem = {buffer, i};
+ workQueue.push_back(workItem);
+ }
+
+ pendingWorkCount = blockCount;
+ }
+}
diff --git a/examples/island/resources/sansation.ttf b/examples/island/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/island/resources/sansation.ttf
Binary files differ
diff --git a/examples/island/resources/terrain.frag b/examples/island/resources/terrain.frag
new file mode 100644
index 0000000..ae18187
--- /dev/null
+++ b/examples/island/resources/terrain.frag
@@ -0,0 +1,11 @@
+varying vec3 normal;
+uniform float lightFactor;
+
+void main()
+{
+ vec3 lightPosition = vec3(-1.0, 1.0, 1.0);
+ vec3 eyePosition = vec3(0.0, 0.0, 1.0);
+ vec3 halfVector = normalize(lightPosition + eyePosition);
+ float intensity = lightFactor + (1.0 - lightFactor) * dot(normalize(normal), normalize(halfVector));
+ gl_FragColor = gl_Color * vec4(intensity, intensity, intensity, 1.0);
+}
diff --git a/examples/island/resources/terrain.vert b/examples/island/resources/terrain.vert
new file mode 100644
index 0000000..a06996d
--- /dev/null
+++ b/examples/island/resources/terrain.vert
@@ -0,0 +1,8 @@
+varying vec3 normal;
+
+void main()
+{
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_FrontColor = gl_Color;
+ normal = vec3(gl_MultiTexCoord0.xy, 1.0);
+}
diff --git a/examples/island/stb_perlin.h b/examples/island/stb_perlin.h
new file mode 100644
index 0000000..5d76222
--- /dev/null
+++ b/examples/island/stb_perlin.h
@@ -0,0 +1,316 @@
+// stb_perlin.h - v0.3 - perlin noise
+// public domain single-file C implementation by Sean Barrett
+//
+// LICENSE
+//
+// See end of file.
+//
+//
+// to create the implementation,
+// #define STB_PERLIN_IMPLEMENTATION
+// in *one* C/CPP file that includes this file.
+//
+//
+// Documentation:
+//
+// float stb_perlin_noise3( float x,
+// float y,
+// float z,
+// int x_wrap=0,
+// int y_wrap=0,
+// int z_wrap=0)
+//
+// This function computes a random value at the coordinate (x,y,z).
+// Adjacent random values are continuous but the noise fluctuates
+// its randomness with period 1, i.e. takes on wholly unrelated values
+// at integer points. Specifically, this implements Ken Perlin's
+// revised noise function from 2002.
+//
+// The "wrap" parameters can be used to create wraparound noise that
+// wraps at powers of two. The numbers MUST be powers of two. Specify
+// 0 to mean "don't care". (The noise always wraps every 256 due
+// details of the implementation, even if you ask for larger or no
+// wrapping.)
+//
+// Fractal Noise:
+//
+// Three common fractal noise functions are included, which produce
+// a wide variety of nice effects depending on the parameters
+// provided. Note that each function will call stb_perlin_noise3
+// 'octaves' times, so this parameter will affect runtime.
+//
+// float stb_perlin_ridge_noise3(float x, float y, float z,
+// float lacunarity, float gain, float offset, int octaves,
+// int x_wrap, int y_wrap, int z_wrap);
+//
+// float stb_perlin_fbm_noise3(float x, float y, float z,
+// float lacunarity, float gain, int octaves,
+// int x_wrap, int y_wrap, int z_wrap);
+//
+// float stb_perlin_turbulence_noise3(float x, float y, float z,
+// float lacunarity, float gain,int octaves,
+// int x_wrap, int y_wrap, int z_wrap);
+//
+// Typical values to start playing with:
+// octaves = 6 -- number of "octaves" of noise3() to sum
+// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
+// gain = 0.5 -- relative weighting applied to each successive octave
+// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
+//
+//
+// Contributors:
+// Jack Mott - additional noise functions
+//
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
+extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap);
+extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
+extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef STB_PERLIN_IMPLEMENTATION
+
+// not same permutation table as Perlin's reference to avoid copyright issues;
+// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
+// @OPTIMIZE: should this be unsigned char instead of int for cache?
+static unsigned char stb__perlin_randtab[512] =
+{
+ 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
+ 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
+ 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
+ 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
+ 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
+ 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
+ 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
+ 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
+ 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
+ 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
+ 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
+ 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
+ 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
+ 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
+ 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
+ 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
+
+ // and a second copy so we don't need an extra mask or static initializer
+ 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
+ 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
+ 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
+ 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
+ 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
+ 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
+ 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
+ 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
+ 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
+ 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
+ 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
+ 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
+ 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
+ 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
+ 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
+ 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
+};
+
+static float stb__perlin_lerp(float a, float b, float t)
+{
+ return a + (b-a) * t;
+}
+
+static int stb__perlin_fastfloor(float a)
+{
+ int ai = (int) a;
+ return (a < ai) ? ai-1 : ai;
+}
+
+// different grad function from Perlin's, but easy to modify to match reference
+static float stb__perlin_grad(int hash, float x, float y, float z)
+{
+ static float basis[12][4] =
+ {
+ { 1, 1, 0 },
+ { -1, 1, 0 },
+ { 1,-1, 0 },
+ { -1,-1, 0 },
+ { 1, 0, 1 },
+ { -1, 0, 1 },
+ { 1, 0,-1 },
+ { -1, 0,-1 },
+ { 0, 1, 1 },
+ { 0,-1, 1 },
+ { 0, 1,-1 },
+ { 0,-1,-1 },
+ };
+
+ // perlin's gradient has 12 cases so some get used 1/16th of the time
+ // and some 2/16ths. We reduce bias by changing those fractions
+ // to 5/64ths and 6/64ths, and the same 4 cases get the extra weight.
+ static unsigned char indices[64] =
+ {
+ 0,1,2,3,4,5,6,7,8,9,10,11,
+ 0,9,1,11,
+ 0,1,2,3,4,5,6,7,8,9,10,11,
+ 0,1,2,3,4,5,6,7,8,9,10,11,
+ 0,1,2,3,4,5,6,7,8,9,10,11,
+ 0,1,2,3,4,5,6,7,8,9,10,11,
+ };
+
+ // if you use reference permutation table, change 63 below to 15 to match reference
+ // (this is why the ordering of the table above is funky)
+ float *grad = basis[indices[hash & 63]];
+ return grad[0]*x + grad[1]*y + grad[2]*z;
+}
+
+float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
+{
+ float u,v,w;
+ float n000,n001,n010,n011,n100,n101,n110,n111;
+ float n00,n01,n10,n11;
+ float n0,n1;
+
+ unsigned int x_mask = (x_wrap-1) & 255;
+ unsigned int y_mask = (y_wrap-1) & 255;
+ unsigned int z_mask = (z_wrap-1) & 255;
+ int px = stb__perlin_fastfloor(x);
+ int py = stb__perlin_fastfloor(y);
+ int pz = stb__perlin_fastfloor(z);
+ int x0 = px & x_mask, x1 = (px+1) & x_mask;
+ int y0 = py & y_mask, y1 = (py+1) & y_mask;
+ int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
+ int r0,r1, r00,r01,r10,r11;
+
+ #define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
+
+ x -= px; u = stb__perlin_ease(x);
+ y -= py; v = stb__perlin_ease(y);
+ z -= pz; w = stb__perlin_ease(z);
+
+ r0 = stb__perlin_randtab[x0];
+ r1 = stb__perlin_randtab[x1];
+
+ r00 = stb__perlin_randtab[r0+y0];
+ r01 = stb__perlin_randtab[r0+y1];
+ r10 = stb__perlin_randtab[r1+y0];
+ r11 = stb__perlin_randtab[r1+y1];
+
+ n000 = stb__perlin_grad(stb__perlin_randtab[r00+z0], x , y , z );
+ n001 = stb__perlin_grad(stb__perlin_randtab[r00+z1], x , y , z-1 );
+ n010 = stb__perlin_grad(stb__perlin_randtab[r01+z0], x , y-1, z );
+ n011 = stb__perlin_grad(stb__perlin_randtab[r01+z1], x , y-1, z-1 );
+ n100 = stb__perlin_grad(stb__perlin_randtab[r10+z0], x-1, y , z );
+ n101 = stb__perlin_grad(stb__perlin_randtab[r10+z1], x-1, y , z-1 );
+ n110 = stb__perlin_grad(stb__perlin_randtab[r11+z0], x-1, y-1, z );
+ n111 = stb__perlin_grad(stb__perlin_randtab[r11+z1], x-1, y-1, z-1 );
+
+ n00 = stb__perlin_lerp(n000,n001,w);
+ n01 = stb__perlin_lerp(n010,n011,w);
+ n10 = stb__perlin_lerp(n100,n101,w);
+ n11 = stb__perlin_lerp(n110,n111,w);
+
+ n0 = stb__perlin_lerp(n00,n01,v);
+ n1 = stb__perlin_lerp(n10,n11,v);
+
+ return stb__perlin_lerp(n0,n1,u);
+}
+
+float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap)
+{
+ int i;
+ float frequency = 1.0f;
+ float prev = 1.0f;
+ float amplitude = 0.5f;
+ float sum = 0.0f;
+
+ for (i = 0; i < octaves; i++) {
+ float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap));
+ r = r<0 ? -r : r; // fabs()
+ r = offset - r;
+ r = r*r;
+ sum += r*amplitude*prev;
+ prev = r;
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+ return sum;
+}
+
+float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
+{
+ int i;
+ float frequency = 1.0f;
+ float amplitude = 1.0f;
+ float sum = 0.0f;
+
+ for (i = 0; i < octaves; i++) {
+ sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+ return sum;
+}
+
+float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
+{
+ int i;
+ float frequency = 1.0f;
+ float amplitude = 1.0f;
+ float sum = 0.0f;
+
+ for (i = 0; i < octaves; i++) {
+ float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
+ r = r<0 ? -r : r; // fabs()
+ sum += r;
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+ return sum;
+}
+
+#endif // STB_PERLIN_IMPLEMENTATION
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/examples/joystick/CMakeLists.txt b/examples/joystick/CMakeLists.txt
new file mode 100644
index 0000000..f04dc7f
--- /dev/null
+++ b/examples/joystick/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/joystick)
+
+# all source files
+set(SRC ${SRCROOT}/Joystick.cpp)
+
+# define the joystick target
+sfml_add_example(joystick GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-graphics sfml-window sfml-system
+ RESOURCES_DIR resources)
diff --git a/examples/joystick/Joystick.cpp b/examples/joystick/Joystick.cpp
new file mode 100644
index 0000000..0ff7cf9
--- /dev/null
+++ b/examples/joystick/Joystick.cpp
@@ -0,0 +1,238 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <algorithm>
+#include <sstream>
+#include <iomanip>
+#include <string>
+#include <map>
+
+
+namespace
+{
+ struct JoystickObject
+ {
+ sf::Text label;
+ sf::Text value;
+ };
+
+ typedef std::map<std::string, JoystickObject> Texts;
+ Texts texts;
+ std::ostringstream sstr;
+ float threshold = 0.1f;
+
+ // Axes labels in as C strings
+ const char* axislabels[] = {"X", "Y", "Z", "R", "U", "V", "PovX", "PovY"};
+
+ // Helper to set text entries to a specified value
+ template<typename T>
+ void set(const char* label, const T& value)
+ {
+ sstr.str("");
+ sstr << value;
+ texts[label].value.setString(sstr.str());
+ }
+
+ // Update joystick identification
+ void updateIdentification(unsigned int index)
+ {
+ sstr.str("");
+ sstr << "Joystick " << index << ":";
+ texts["ID"].label.setString(sstr.str());
+ texts["ID"].value.setString(sf::Joystick::getIdentification(index).name);
+ }
+
+ // Update joystick axes
+ void updateAxes(unsigned int index)
+ {
+ for (unsigned int j = 0; j < sf::Joystick::AxisCount; ++j)
+ {
+ if (sf::Joystick::hasAxis(index, static_cast<sf::Joystick::Axis>(j)))
+ set(axislabels[j], sf::Joystick::getAxisPosition(index, static_cast<sf::Joystick::Axis>(j)));
+ }
+ }
+
+ // Update joystick buttons
+ void updateButtons(unsigned int index)
+ {
+ for (unsigned int j = 0; j < sf::Joystick::getButtonCount(index); ++j)
+ {
+ sstr.str("");
+ sstr << "Button " << j;
+
+ set(sstr.str().c_str(), sf::Joystick::isButtonPressed(index, j));
+ }
+ }
+
+ // Helper to update displayed joystick values
+ void updateValues(unsigned int index)
+ {
+ if (sf::Joystick::isConnected(index)) {
+ // Update the label-value sf::Text objects based on the current joystick state
+ updateIdentification(index);
+ updateAxes(index);
+ updateButtons(index);
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Create the window of the application
+ sf::RenderWindow window(sf::VideoMode(400, 680), "Joystick", sf::Style::Close);
+ window.setVerticalSyncEnabled(true);
+
+ // Load the text font
+ sf::Font font;
+ if (!font.loadFromFile("resources/sansation.ttf"))
+ return EXIT_FAILURE;
+
+ // Set up our string conversion parameters
+ sstr.precision(2);
+ sstr.setf(std::ios::fixed | std::ios::boolalpha);
+
+ // Set up our joystick identification sf::Text objects
+ texts["ID"].label.setPosition(5.f, 5.f);
+ texts["ID"].value.setPosition(80.f, 5.f);
+
+ texts["ID"].label.setString("<Not Connected>");
+ texts["ID"].value.setString("");
+
+ // Set up our threshold sf::Text objects
+ sstr.str("");
+ sstr << threshold << " (Change with up/down arrow keys)";
+
+ texts["Threshold"].label.setPosition(5.f, 5.f + 2 * font.getLineSpacing(14));
+ texts["Threshold"].value.setPosition(80.f, 5.f + 2 * font.getLineSpacing(14));
+
+ texts["Threshold"].label.setString("Threshold:");
+ texts["Threshold"].value.setString(sstr.str());
+
+ // Set up our label-value sf::Text objects
+ for (unsigned int i = 0; i < sf::Joystick::AxisCount; ++i)
+ {
+ JoystickObject& object = texts[axislabels[i]];
+
+ object.label.setPosition(5.f, 5.f + ((i + 4) * font.getLineSpacing(14)));
+ object.label.setString(std::string(axislabels[i]) + ":");
+
+ object.value.setPosition(80.f, 5.f + ((i + 4) * font.getLineSpacing(14)));
+ object.value.setString("N/A");
+ }
+
+ for (unsigned int i = 0; i < sf::Joystick::ButtonCount; ++i)
+ {
+ sstr.str("");
+ sstr << "Button " << i;
+ JoystickObject& object = texts[sstr.str()];
+
+ object.label.setPosition(5.f, 5.f + ((sf::Joystick::AxisCount + i + 4) * font.getLineSpacing(14)));
+ object.label.setString(sstr.str() + ":");
+
+ object.value.setPosition(80.f, 5.f + ((sf::Joystick::AxisCount + i + 4) * font.getLineSpacing(14)));
+ object.value.setString("N/A");
+ }
+
+ for (Texts::iterator it = texts.begin(); it != texts.end(); ++it)
+ {
+ it->second.label.setFont(font);
+ it->second.label.setCharacterSize(14);
+ it->second.label.setFillColor(sf::Color::White);
+
+ it->second.value.setFont(font);
+ it->second.value.setCharacterSize(14);
+ it->second.value.setFillColor(sf::Color::White);
+ }
+
+ // Update initially displayed joystick values if a joystick is already connected on startup
+ for (unsigned int i = 0; i < sf::Joystick::Count; ++i)
+ {
+ if (sf::Joystick::isConnected(i))
+ {
+ updateValues(i);
+ break;
+ }
+ }
+
+ while (window.isOpen())
+ {
+ // Handle events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Window closed or escape key pressed: exit
+ if ((event.type == sf::Event::Closed) ||
+ ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
+ {
+ window.close();
+ break;
+ }
+ else if ((event.type == sf::Event::JoystickButtonPressed) ||
+ (event.type == sf::Event::JoystickButtonReleased) ||
+ (event.type == sf::Event::JoystickMoved) ||
+ (event.type == sf::Event::JoystickConnected))
+ {
+ // Update displayed joystick values
+ updateValues(event.joystickConnect.joystickId);
+ }
+ else if (event.type == sf::Event::JoystickDisconnected)
+ {
+ // Reset displayed joystick values to empty
+ for (Texts::iterator it = texts.begin(); it != texts.end(); ++it)
+ it->second.value.setString("N/A");
+
+ texts["ID"].label.setString("<Not Connected>");
+ texts["ID"].value.setString("");
+
+ sstr.str("");
+ sstr << threshold << " (Change with up/down arrow keys)";
+
+ texts["Threshold"].value.setString(sstr.str());
+ }
+ }
+
+ // Update threshold if the user wants to change it
+ float newThreshold = threshold;
+
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
+ newThreshold += 0.1f;
+
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
+ newThreshold -= 0.1f;
+
+ newThreshold = std::min(std::max(newThreshold, 0.1f), 100.0f);
+
+ if (newThreshold != threshold)
+ {
+ threshold = newThreshold;
+ window.setJoystickThreshold(threshold);
+
+ sstr.str("");
+ sstr << threshold << " (Change with up/down arrow keys)";
+
+ texts["Threshold"].value.setString(sstr.str());
+ }
+
+ // Clear the window
+ window.clear();
+
+ // Draw the label-value sf::Text objects
+ for (Texts::const_iterator it = texts.begin(); it != texts.end(); ++it)
+ {
+ window.draw(it->second.label);
+ window.draw(it->second.value);
+ }
+
+ // Display things on screen
+ window.display();
+ }
+}
diff --git a/examples/joystick/resources/sansation.ttf b/examples/joystick/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/joystick/resources/sansation.ttf
Binary files differ
diff --git a/examples/opengl/CMakeLists.txt b/examples/opengl/CMakeLists.txt
new file mode 100644
index 0000000..9b8ad49
--- /dev/null
+++ b/examples/opengl/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/opengl)
+
+# all source files
+set(SRC ${SRCROOT}/OpenGL.cpp)
+
+# define the opengl target
+sfml_add_example(opengl GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-graphics OpenGL
+ RESOURCES_DIR resources)
diff --git a/examples/opengl/OpenGL.cpp b/examples/opengl/OpenGL.cpp
new file mode 100644
index 0000000..f2260d6
--- /dev/null
+++ b/examples/opengl/OpenGL.cpp
@@ -0,0 +1,258 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <SFML/OpenGL.hpp>
+
+#ifndef GL_SRGB8_ALPHA8
+#define GL_SRGB8_ALPHA8 0x8C43
+#endif
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ bool exit = false;
+ bool sRgb = false;
+
+ while (!exit)
+ {
+ // Request a 24-bits depth buffer when creating the window
+ sf::ContextSettings contextSettings;
+ contextSettings.depthBits = 24;
+ contextSettings.sRgbCapable = sRgb;
+
+ // Create the main window
+ sf::RenderWindow window(sf::VideoMode(800, 600), "SFML graphics with OpenGL", sf::Style::Default, contextSettings);
+ window.setVerticalSyncEnabled(true);
+
+ // Create a sprite for the background
+ sf::Texture backgroundTexture;
+ backgroundTexture.setSrgb(sRgb);
+ if (!backgroundTexture.loadFromFile("resources/background.jpg"))
+ return EXIT_FAILURE;
+ sf::Sprite background(backgroundTexture);
+
+ // Create some text to draw on top of our OpenGL object
+ sf::Font font;
+ if (!font.loadFromFile("resources/sansation.ttf"))
+ return EXIT_FAILURE;
+ sf::Text text("SFML / OpenGL demo", font);
+ sf::Text sRgbInstructions("Press space to toggle sRGB conversion", font);
+ sf::Text mipmapInstructions("Press return to toggle mipmapping", font);
+ text.setFillColor(sf::Color(255, 255, 255, 170));
+ sRgbInstructions.setFillColor(sf::Color(255, 255, 255, 170));
+ mipmapInstructions.setFillColor(sf::Color(255, 255, 255, 170));
+ text.setPosition(250.f, 450.f);
+ sRgbInstructions.setPosition(150.f, 500.f);
+ mipmapInstructions.setPosition(180.f, 550.f);
+
+ // Load a texture to apply to our 3D cube
+ sf::Texture texture;
+ if (!texture.loadFromFile("resources/texture.jpg"))
+ return EXIT_FAILURE;
+
+ // Attempt to generate a mipmap for our cube texture
+ // We don't check the return value here since
+ // mipmapping is purely optional in this example
+ texture.generateMipmap();
+
+ // Make the window the active window for OpenGL calls
+ window.setActive(true);
+
+ // Enable Z-buffer read and write
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glClearDepth(1.f);
+
+ // Disable lighting
+ glDisable(GL_LIGHTING);
+
+ // Configure the viewport (the same size as the window)
+ glViewport(0, 0, window.getSize().x, window.getSize().y);
+
+ // Setup a perspective projection
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
+ glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
+
+ // Bind the texture
+ glEnable(GL_TEXTURE_2D);
+ sf::Texture::bind(&texture);
+
+ // Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
+ static const GLfloat cube[] =
+ {
+ // positions // texture coordinates
+ -20, -20, -20, 0, 0,
+ -20, 20, -20, 1, 0,
+ -20, -20, 20, 0, 1,
+ -20, -20, 20, 0, 1,
+ -20, 20, -20, 1, 0,
+ -20, 20, 20, 1, 1,
+
+ 20, -20, -20, 0, 0,
+ 20, 20, -20, 1, 0,
+ 20, -20, 20, 0, 1,
+ 20, -20, 20, 0, 1,
+ 20, 20, -20, 1, 0,
+ 20, 20, 20, 1, 1,
+
+ -20, -20, -20, 0, 0,
+ 20, -20, -20, 1, 0,
+ -20, -20, 20, 0, 1,
+ -20, -20, 20, 0, 1,
+ 20, -20, -20, 1, 0,
+ 20, -20, 20, 1, 1,
+
+ -20, 20, -20, 0, 0,
+ 20, 20, -20, 1, 0,
+ -20, 20, 20, 0, 1,
+ -20, 20, 20, 0, 1,
+ 20, 20, -20, 1, 0,
+ 20, 20, 20, 1, 1,
+
+ -20, -20, -20, 0, 0,
+ 20, -20, -20, 1, 0,
+ -20, 20, -20, 0, 1,
+ -20, 20, -20, 0, 1,
+ 20, -20, -20, 1, 0,
+ 20, 20, -20, 1, 1,
+
+ -20, -20, 20, 0, 0,
+ 20, -20, 20, 1, 0,
+ -20, 20, 20, 0, 1,
+ -20, 20, 20, 0, 1,
+ 20, -20, 20, 1, 0,
+ 20, 20, 20, 1, 1
+ };
+
+ // Enable position and texture coordinates vertex components
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), cube);
+ glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), cube + 3);
+
+ // Disable normal and color vertex components
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ // Make the window no longer the active window for OpenGL calls
+ window.setActive(false);
+
+ // Create a clock for measuring the time elapsed
+ sf::Clock clock;
+
+ // Flag to track whether mipmapping is currently enabled
+ bool mipmapEnabled = true;
+
+ // Start game loop
+ while (window.isOpen())
+ {
+ // Process events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Close window: exit
+ if (event.type == sf::Event::Closed)
+ {
+ exit = true;
+ window.close();
+ }
+
+ // Escape key: exit
+ if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
+ {
+ exit = true;
+ window.close();
+ }
+
+ // Return key: toggle mipmapping
+ if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Enter))
+ {
+ if (mipmapEnabled)
+ {
+ // We simply reload the texture to disable mipmapping
+ if (!texture.loadFromFile("resources/texture.jpg"))
+ return EXIT_FAILURE;
+
+ mipmapEnabled = false;
+ }
+ else
+ {
+ texture.generateMipmap();
+
+ mipmapEnabled = true;
+ }
+ }
+
+ // Space key: toggle sRGB conversion
+ if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
+ {
+ sRgb = !sRgb;
+ window.close();
+ }
+
+ // Adjust the viewport when the window is resized
+ if (event.type == sf::Event::Resized)
+ {
+ // Make the window the active window for OpenGL calls
+ window.setActive(true);
+
+ glViewport(0, 0, event.size.width, event.size.height);
+
+ // Make the window no longer the active window for OpenGL calls
+ window.setActive(false);
+ }
+ }
+
+ // Draw the background
+ window.pushGLStates();
+ window.draw(background);
+ window.popGLStates();
+
+ // Make the window the active window for OpenGL calls
+ window.setActive(true);
+
+ // Clear the depth buffer
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // We get the position of the mouse cursor, so that we can move the box accordingly
+ float x = sf::Mouse::getPosition(window).x * 200.f / window.getSize().x - 100.f;
+ float y = -sf::Mouse::getPosition(window).y * 200.f / window.getSize().y + 100.f;
+
+ // Apply some transformations
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(x, y, -100.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+
+ // Make the window no longer the active window for OpenGL calls
+ window.setActive(false);
+
+ // Draw some text on top of our OpenGL object
+ window.pushGLStates();
+ window.draw(text);
+ window.draw(sRgbInstructions);
+ window.draw(mipmapInstructions);
+ window.popGLStates();
+
+ // Finally, display the rendered frame on screen
+ window.display();
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/opengl/resources/sansation.ttf b/examples/opengl/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/opengl/resources/sansation.ttf
Binary files differ
diff --git a/examples/pong/CMakeLists.txt b/examples/pong/CMakeLists.txt
new file mode 100644
index 0000000..a20f3b1
--- /dev/null
+++ b/examples/pong/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/pong)
+
+# all source files
+set(SRC ${SRCROOT}/Pong.cpp)
+
+# define the pong target
+sfml_add_example(pong GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-audio sfml-graphics
+ RESOURCES_DIR resources)
diff --git a/examples/pong/Pong.cpp b/examples/pong/Pong.cpp
new file mode 100644
index 0000000..58c9fd7
--- /dev/null
+++ b/examples/pong/Pong.cpp
@@ -0,0 +1,242 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <SFML/Audio.hpp>
+#include <cmath>
+#include <ctime>
+#include <cstdlib>
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ std::srand(static_cast<unsigned int>(std::time(NULL)));
+
+ // Define some constants
+ const float pi = 3.14159f;
+ const int gameWidth = 800;
+ const int gameHeight = 600;
+ sf::Vector2f paddleSize(25, 100);
+ float ballRadius = 10.f;
+
+ // Create the window of the application
+ sf::RenderWindow window(sf::VideoMode(gameWidth, gameHeight, 32), "SFML Pong",
+ sf::Style::Titlebar | sf::Style::Close);
+ window.setVerticalSyncEnabled(true);
+
+ // Load the sounds used in the game
+ sf::SoundBuffer ballSoundBuffer;
+ if (!ballSoundBuffer.loadFromFile("resources/ball.wav"))
+ return EXIT_FAILURE;
+ sf::Sound ballSound(ballSoundBuffer);
+
+ // Create the left paddle
+ sf::RectangleShape leftPaddle;
+ leftPaddle.setSize(paddleSize - sf::Vector2f(3, 3));
+ leftPaddle.setOutlineThickness(3);
+ leftPaddle.setOutlineColor(sf::Color::Black);
+ leftPaddle.setFillColor(sf::Color(100, 100, 200));
+ leftPaddle.setOrigin(paddleSize / 2.f);
+
+ // Create the right paddle
+ sf::RectangleShape rightPaddle;
+ rightPaddle.setSize(paddleSize - sf::Vector2f(3, 3));
+ rightPaddle.setOutlineThickness(3);
+ rightPaddle.setOutlineColor(sf::Color::Black);
+ rightPaddle.setFillColor(sf::Color(200, 100, 100));
+ rightPaddle.setOrigin(paddleSize / 2.f);
+
+ // Create the ball
+ sf::CircleShape ball;
+ ball.setRadius(ballRadius - 3);
+ ball.setOutlineThickness(3);
+ ball.setOutlineColor(sf::Color::Black);
+ ball.setFillColor(sf::Color::White);
+ ball.setOrigin(ballRadius / 2, ballRadius / 2);
+
+ // Load the text font
+ sf::Font font;
+ if (!font.loadFromFile("resources/sansation.ttf"))
+ return EXIT_FAILURE;
+
+ // Initialize the pause message
+ sf::Text pauseMessage;
+ pauseMessage.setFont(font);
+ pauseMessage.setCharacterSize(40);
+ pauseMessage.setPosition(170.f, 150.f);
+ pauseMessage.setFillColor(sf::Color::White);
+ pauseMessage.setString("Welcome to SFML pong!\nPress space to start the game");
+
+ // Define the paddles properties
+ sf::Clock AITimer;
+ const sf::Time AITime = sf::seconds(0.1f);
+ const float paddleSpeed = 400.f;
+ float rightPaddleSpeed = 0.f;
+ const float ballSpeed = 400.f;
+ float ballAngle = 0.f; // to be changed later
+
+ sf::Clock clock;
+ bool isPlaying = false;
+ while (window.isOpen())
+ {
+ // Handle events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Window closed or escape key pressed: exit
+ if ((event.type == sf::Event::Closed) ||
+ ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
+ {
+ window.close();
+ break;
+ }
+
+ // Space key pressed: play
+ if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
+ {
+ if (!isPlaying)
+ {
+ // (re)start the game
+ isPlaying = true;
+ clock.restart();
+
+ // Reset the position of the paddles and ball
+ leftPaddle.setPosition(10 + paddleSize.x / 2, gameHeight / 2);
+ rightPaddle.setPosition(gameWidth - 10 - paddleSize.x / 2, gameHeight / 2);
+ ball.setPosition(gameWidth / 2, gameHeight / 2);
+
+ // Reset the ball angle
+ do
+ {
+ // Make sure the ball initial angle is not too much vertical
+ ballAngle = (std::rand() % 360) * 2 * pi / 360;
+ }
+ while (std::abs(std::cos(ballAngle)) < 0.7f);
+ }
+ }
+ }
+
+ if (isPlaying)
+ {
+ float deltaTime = clock.restart().asSeconds();
+
+ // Move the player's paddle
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) &&
+ (leftPaddle.getPosition().y - paddleSize.y / 2 > 5.f))
+ {
+ leftPaddle.move(0.f, -paddleSpeed * deltaTime);
+ }
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) &&
+ (leftPaddle.getPosition().y + paddleSize.y / 2 < gameHeight - 5.f))
+ {
+ leftPaddle.move(0.f, paddleSpeed * deltaTime);
+ }
+
+ // Move the computer's paddle
+ if (((rightPaddleSpeed < 0.f) && (rightPaddle.getPosition().y - paddleSize.y / 2 > 5.f)) ||
+ ((rightPaddleSpeed > 0.f) && (rightPaddle.getPosition().y + paddleSize.y / 2 < gameHeight - 5.f)))
+ {
+ rightPaddle.move(0.f, rightPaddleSpeed * deltaTime);
+ }
+
+ // Update the computer's paddle direction according to the ball position
+ if (AITimer.getElapsedTime() > AITime)
+ {
+ AITimer.restart();
+ if (ball.getPosition().y + ballRadius > rightPaddle.getPosition().y + paddleSize.y / 2)
+ rightPaddleSpeed = paddleSpeed;
+ else if (ball.getPosition().y - ballRadius < rightPaddle.getPosition().y - paddleSize.y / 2)
+ rightPaddleSpeed = -paddleSpeed;
+ else
+ rightPaddleSpeed = 0.f;
+ }
+
+ // Move the ball
+ float factor = ballSpeed * deltaTime;
+ ball.move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor);
+
+ // Check collisions between the ball and the screen
+ if (ball.getPosition().x - ballRadius < 0.f)
+ {
+ isPlaying = false;
+ pauseMessage.setString("You lost!\nPress space to restart or\nescape to exit");
+ }
+ if (ball.getPosition().x + ballRadius > gameWidth)
+ {
+ isPlaying = false;
+ pauseMessage.setString("You won!\nPress space to restart or\nescape to exit");
+ }
+ if (ball.getPosition().y - ballRadius < 0.f)
+ {
+ ballSound.play();
+ ballAngle = -ballAngle;
+ ball.setPosition(ball.getPosition().x, ballRadius + 0.1f);
+ }
+ if (ball.getPosition().y + ballRadius > gameHeight)
+ {
+ ballSound.play();
+ ballAngle = -ballAngle;
+ ball.setPosition(ball.getPosition().x, gameHeight - ballRadius - 0.1f);
+ }
+
+ // Check the collisions between the ball and the paddles
+ // Left Paddle
+ if (ball.getPosition().x - ballRadius < leftPaddle.getPosition().x + paddleSize.x / 2 &&
+ ball.getPosition().x - ballRadius > leftPaddle.getPosition().x &&
+ ball.getPosition().y + ballRadius >= leftPaddle.getPosition().y - paddleSize.y / 2 &&
+ ball.getPosition().y - ballRadius <= leftPaddle.getPosition().y + paddleSize.y / 2)
+ {
+ if (ball.getPosition().y > leftPaddle.getPosition().y)
+ ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180;
+ else
+ ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180;
+
+ ballSound.play();
+ ball.setPosition(leftPaddle.getPosition().x + ballRadius + paddleSize.x / 2 + 0.1f, ball.getPosition().y);
+ }
+
+ // Right Paddle
+ if (ball.getPosition().x + ballRadius > rightPaddle.getPosition().x - paddleSize.x / 2 &&
+ ball.getPosition().x + ballRadius < rightPaddle.getPosition().x &&
+ ball.getPosition().y + ballRadius >= rightPaddle.getPosition().y - paddleSize.y / 2 &&
+ ball.getPosition().y - ballRadius <= rightPaddle.getPosition().y + paddleSize.y / 2)
+ {
+ if (ball.getPosition().y > rightPaddle.getPosition().y)
+ ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180;
+ else
+ ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180;
+
+ ballSound.play();
+ ball.setPosition(rightPaddle.getPosition().x - ballRadius - paddleSize.x / 2 - 0.1f, ball.getPosition().y);
+ }
+ }
+
+ // Clear the window
+ window.clear(sf::Color(50, 200, 50));
+
+ if (isPlaying)
+ {
+ // Draw the paddles and the ball
+ window.draw(leftPaddle);
+ window.draw(rightPaddle);
+ window.draw(ball);
+ }
+ else
+ {
+ // Draw the pause message
+ window.draw(pauseMessage);
+ }
+
+ // Display things on screen
+ window.display();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/pong/resources/ball.wav b/examples/pong/resources/ball.wav
new file mode 100644
index 0000000..8b3cfba
--- /dev/null
+++ b/examples/pong/resources/ball.wav
Binary files differ
diff --git a/examples/pong/resources/sansation.ttf b/examples/pong/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/pong/resources/sansation.ttf
Binary files differ
diff --git a/examples/shader/CMakeLists.txt b/examples/shader/CMakeLists.txt
new file mode 100644
index 0000000..600cb4d
--- /dev/null
+++ b/examples/shader/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/shader)
+
+# all source files
+set(SRC
+ ${SRCROOT}/Effect.hpp
+ ${SRCROOT}/Shader.cpp)
+
+# define the shader target
+sfml_add_example(shader GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-graphics
+ RESOURCES_DIR resources)
diff --git a/examples/shader/Effect.hpp b/examples/shader/Effect.hpp
new file mode 100644
index 0000000..0ff65b4
--- /dev/null
+++ b/examples/shader/Effect.hpp
@@ -0,0 +1,88 @@
+#ifndef EFFECT_HPP
+#define EFFECT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <cassert>
+#include <string>
+
+
+////////////////////////////////////////////////////////////
+// Base class for effects
+////////////////////////////////////////////////////////////
+class Effect : public sf::Drawable
+{
+public:
+
+ virtual ~Effect()
+ {
+ }
+
+ static void setFont(const sf::Font& font)
+ {
+ s_font = &font;
+ }
+
+ const std::string& getName() const
+ {
+ return m_name;
+ }
+
+ void load()
+ {
+ m_isLoaded = sf::Shader::isAvailable() && onLoad();
+ }
+
+ void update(float time, float x, float y)
+ {
+ if (m_isLoaded)
+ onUpdate(time, x, y);
+ }
+
+ void draw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ if (m_isLoaded)
+ {
+ onDraw(target, states);
+ }
+ else
+ {
+ sf::Text error("Shader not\nsupported", getFont());
+ error.setPosition(320.f, 200.f);
+ error.setCharacterSize(36);
+ target.draw(error, states);
+ }
+ }
+
+protected:
+
+ Effect(const std::string& name) :
+ m_name(name),
+ m_isLoaded(false)
+ {
+ }
+
+ static const sf::Font& getFont()
+ {
+ assert(s_font != NULL);
+ return *s_font;
+ }
+
+private:
+
+ // Virtual functions to be implemented in derived effects
+ virtual bool onLoad() = 0;
+ virtual void onUpdate(float time, float x, float y) = 0;
+ virtual void onDraw(sf::RenderTarget& target, sf::RenderStates states) const = 0;
+
+private:
+
+ std::string m_name;
+ bool m_isLoaded;
+
+ static const sf::Font* s_font;
+};
+
+#endif // EFFECT_HPP
diff --git a/examples/shader/Shader.cpp b/examples/shader/Shader.cpp
new file mode 100644
index 0000000..8a81fde
--- /dev/null
+++ b/examples/shader/Shader.cpp
@@ -0,0 +1,460 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include "Effect.hpp"
+#include <vector>
+#include <cmath>
+
+
+const sf::Font* Effect::s_font = NULL;
+
+////////////////////////////////////////////////////////////
+// "Pixelate" fragment shader
+////////////////////////////////////////////////////////////
+class Pixelate : public Effect
+{
+public:
+
+ Pixelate() :
+ Effect("pixelate")
+ {
+ }
+
+ bool onLoad()
+ {
+ // Load the texture and initialize the sprite
+ if (!m_texture.loadFromFile("resources/background.jpg"))
+ return false;
+ m_sprite.setTexture(m_texture);
+
+ // Load the shader
+ if (!m_shader.loadFromFile("resources/pixelate.frag", sf::Shader::Fragment))
+ return false;
+ m_shader.setUniform("texture", sf::Shader::CurrentTexture);
+
+ return true;
+ }
+
+ void onUpdate(float, float x, float y)
+ {
+ m_shader.setUniform("pixel_threshold", (x + y) / 30);
+ }
+
+ void onDraw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ states.shader = &m_shader;
+ target.draw(m_sprite, states);
+ }
+
+private:
+
+ sf::Texture m_texture;
+ sf::Sprite m_sprite;
+ sf::Shader m_shader;
+};
+
+
+////////////////////////////////////////////////////////////
+// "Wave" vertex shader + "blur" fragment shader
+////////////////////////////////////////////////////////////
+class WaveBlur : public Effect
+{
+public:
+
+ WaveBlur() :
+ Effect("wave + blur")
+ {
+ }
+
+ bool onLoad()
+ {
+ // Create the text
+ m_text.setString("Praesent suscipit augue in velit pulvinar hendrerit varius purus aliquam.\n"
+ "Mauris mi odio, bibendum quis fringilla a, laoreet vel orci. Proin vitae vulputate tortor.\n"
+ "Praesent cursus ultrices justo, ut feugiat ante vehicula quis.\n"
+ "Donec fringilla scelerisque mauris et viverra.\n"
+ "Maecenas adipiscing ornare scelerisque. Nullam at libero elit.\n"
+ "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n"
+ "Nullam leo urna, tincidunt id semper eget, ultricies sed mi.\n"
+ "Morbi mauris massa, commodo id dignissim vel, lobortis et elit.\n"
+ "Fusce vel libero sed neque scelerisque venenatis.\n"
+ "Integer mattis tincidunt quam vitae iaculis.\n"
+ "Vivamus fringilla sem non velit venenatis fermentum.\n"
+ "Vivamus varius tincidunt nisi id vehicula.\n"
+ "Integer ullamcorper, enim vitae euismod rutrum, massa nisl semper ipsum,\n"
+ "vestibulum sodales sem ante in massa.\n"
+ "Vestibulum in augue non felis convallis viverra.\n"
+ "Mauris ultricies dolor sed massa convallis sed aliquet augue fringilla.\n"
+ "Duis erat eros, porta in accumsan in, blandit quis sem.\n"
+ "In hac habitasse platea dictumst. Etiam fringilla est id odio dapibus sit amet semper dui laoreet.\n");
+ m_text.setFont(getFont());
+ m_text.setCharacterSize(22);
+ m_text.setPosition(30, 20);
+
+ // Load the shader
+ if (!m_shader.loadFromFile("resources/wave.vert", "resources/blur.frag"))
+ return false;
+
+ return true;
+ }
+
+ void onUpdate(float time, float x, float y)
+ {
+ m_shader.setUniform("wave_phase", time);
+ m_shader.setUniform("wave_amplitude", sf::Vector2f(x * 40, y * 40));
+ m_shader.setUniform("blur_radius", (x + y) * 0.008f);
+ }
+
+ void onDraw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ states.shader = &m_shader;
+ target.draw(m_text, states);
+ }
+
+private:
+
+ sf::Text m_text;
+ sf::Shader m_shader;
+};
+
+
+////////////////////////////////////////////////////////////
+// "Storm" vertex shader + "blink" fragment shader
+////////////////////////////////////////////////////////////
+class StormBlink : public Effect
+{
+public:
+
+ StormBlink() :
+ Effect("storm + blink")
+ {
+ }
+
+ bool onLoad()
+ {
+ // Create the points
+ m_points.setPrimitiveType(sf::Points);
+ for (int i = 0; i < 40000; ++i)
+ {
+ float x = static_cast<float>(std::rand() % 800);
+ float y = static_cast<float>(std::rand() % 600);
+ sf::Uint8 r = std::rand() % 255;
+ sf::Uint8 g = std::rand() % 255;
+ sf::Uint8 b = std::rand() % 255;
+ m_points.append(sf::Vertex(sf::Vector2f(x, y), sf::Color(r, g, b)));
+ }
+
+ // Load the shader
+ if (!m_shader.loadFromFile("resources/storm.vert", "resources/blink.frag"))
+ return false;
+
+ return true;
+ }
+
+ void onUpdate(float time, float x, float y)
+ {
+ float radius = 200 + std::cos(time) * 150;
+ m_shader.setUniform("storm_position", sf::Vector2f(x * 800, y * 600));
+ m_shader.setUniform("storm_inner_radius", radius / 3);
+ m_shader.setUniform("storm_total_radius", radius);
+ m_shader.setUniform("blink_alpha", 0.5f + std::cos(time * 3) * 0.25f);
+ }
+
+ void onDraw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ states.shader = &m_shader;
+ target.draw(m_points, states);
+ }
+
+private:
+
+ sf::VertexArray m_points;
+ sf::Shader m_shader;
+};
+
+
+////////////////////////////////////////////////////////////
+// "Edge" post-effect fragment shader
+////////////////////////////////////////////////////////////
+class Edge : public Effect
+{
+public:
+
+ Edge() :
+ Effect("edge post-effect")
+ {
+ }
+
+ bool onLoad()
+ {
+ // Create the off-screen surface
+ if (!m_surface.create(800, 600))
+ return false;
+ m_surface.setSmooth(true);
+
+ // Load the textures
+ if (!m_backgroundTexture.loadFromFile("resources/sfml.png"))
+ return false;
+ m_backgroundTexture.setSmooth(true);
+ if (!m_entityTexture.loadFromFile("resources/devices.png"))
+ return false;
+ m_entityTexture.setSmooth(true);
+
+ // Initialize the background sprite
+ m_backgroundSprite.setTexture(m_backgroundTexture);
+ m_backgroundSprite.setPosition(135, 100);
+
+ // Load the moving entities
+ for (int i = 0; i < 6; ++i)
+ {
+ sf::Sprite entity(m_entityTexture, sf::IntRect(96 * i, 0, 96, 96));
+ m_entities.push_back(entity);
+ }
+
+ // Load the shader
+ if (!m_shader.loadFromFile("resources/edge.frag", sf::Shader::Fragment))
+ return false;
+ m_shader.setUniform("texture", sf::Shader::CurrentTexture);
+
+ return true;
+ }
+
+ void onUpdate(float time, float x, float y)
+ {
+ m_shader.setUniform("edge_threshold", 1 - (x + y) / 2);
+
+ // Update the position of the moving entities
+ for (std::size_t i = 0; i < m_entities.size(); ++i)
+ {
+ sf::Vector2f position;
+ position.x = std::cos(0.25f * (time * i + (m_entities.size() - i))) * 300 + 350;
+ position.y = std::sin(0.25f * (time * (m_entities.size() - i) + i)) * 200 + 250;
+ m_entities[i].setPosition(position);
+ }
+
+ // Render the updated scene to the off-screen surface
+ m_surface.clear(sf::Color::White);
+ m_surface.draw(m_backgroundSprite);
+ for (std::size_t i = 0; i < m_entities.size(); ++i)
+ m_surface.draw(m_entities[i]);
+ m_surface.display();
+ }
+
+ void onDraw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ states.shader = &m_shader;
+ target.draw(sf::Sprite(m_surface.getTexture()), states);
+ }
+
+private:
+
+ sf::RenderTexture m_surface;
+ sf::Texture m_backgroundTexture;
+ sf::Texture m_entityTexture;
+ sf::Sprite m_backgroundSprite;
+ std::vector<sf::Sprite> m_entities;
+ sf::Shader m_shader;
+};
+
+
+////////////////////////////////////////////////////////////
+// "Geometry" geometry shader example
+////////////////////////////////////////////////////////////
+class Geometry : public Effect
+{
+public:
+
+ Geometry() :
+ Effect("geometry shader billboards"),
+ m_pointCloud(sf::Points, 10000)
+ {
+ }
+
+ bool onLoad()
+ {
+ // Check if geometry shaders are supported
+ if (!sf::Shader::isGeometryAvailable())
+ return false;
+
+ // Move the points in the point cloud to random positions
+ for (std::size_t i = 0; i < 10000; i++)
+ {
+ // Spread the coordinates from -480 to +480
+ // So they'll always fill the viewport at 800x600
+ m_pointCloud[i].position.x = rand() % 960 - 480.f;
+ m_pointCloud[i].position.y = rand() % 960 - 480.f;
+ }
+
+ // Load the texture
+ if (!m_logoTexture.loadFromFile("resources/logo.png"))
+ return false;
+
+ // Load the shader
+ if (!m_shader.loadFromFile("resources/billboard.vert", "resources/billboard.geom", "resources/billboard.frag"))
+ return false;
+ m_shader.setUniform("texture", sf::Shader::CurrentTexture);
+
+ // Set the render resolution (used for proper scaling)
+ m_shader.setUniform("resolution", sf::Vector2f(800, 600));
+
+ return true;
+ }
+
+ void onUpdate(float time, float x, float y)
+ {
+ // Reset our transformation matrix
+ m_transform = sf::Transform::Identity;
+ // Move to the center of the window
+ m_transform.translate(400, 300);
+ // Rotate everything based on cursor position
+ m_transform.rotate(x * 360.f);
+
+ // Adjust billboard size to scale between 25 and 75
+ float size = 25 + std::abs(y) * 50;
+
+ // Update the shader parameter
+ m_shader.setUniform("size", sf::Vector2f(size, size));
+ }
+
+ void onDraw(sf::RenderTarget& target, sf::RenderStates states) const
+ {
+ // Prepare the render state
+ states.shader = &m_shader;
+ states.texture = &m_logoTexture;
+ states.transform = m_transform;
+
+ // Draw the point cloud
+ target.draw(m_pointCloud, states);
+ }
+
+private:
+
+ sf::Texture m_logoTexture;
+ sf::Transform m_transform;
+ sf::Shader m_shader;
+ sf::VertexArray m_pointCloud;
+};
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Create the main window
+ sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Shader",
+ sf::Style::Titlebar | sf::Style::Close);
+ window.setVerticalSyncEnabled(true);
+
+ // Load the application font and pass it to the Effect class
+ sf::Font font;
+ if (!font.loadFromFile("resources/sansation.ttf"))
+ return EXIT_FAILURE;
+ Effect::setFont(font);
+
+ // Create the effects
+ std::vector<Effect*> effects;
+ effects.push_back(new Pixelate);
+ effects.push_back(new WaveBlur);
+ effects.push_back(new StormBlink);
+ effects.push_back(new Edge);
+ effects.push_back(new Geometry);
+ std::size_t current = 0;
+
+ // Initialize them
+ for (std::size_t i = 0; i < effects.size(); ++i)
+ effects[i]->load();
+
+ // Create the messages background
+ sf::Texture textBackgroundTexture;
+ if (!textBackgroundTexture.loadFromFile("resources/text-background.png"))
+ return EXIT_FAILURE;
+ sf::Sprite textBackground(textBackgroundTexture);
+ textBackground.setPosition(0, 520);
+ textBackground.setColor(sf::Color(255, 255, 255, 200));
+
+ // Create the description text
+ sf::Text description("Current effect: " + effects[current]->getName(), font, 20);
+ description.setPosition(10, 530);
+ description.setFillColor(sf::Color(80, 80, 80));
+
+ // Create the instructions text
+ sf::Text instructions("Press left and right arrows to change the current shader", font, 20);
+ instructions.setPosition(280, 555);
+ instructions.setFillColor(sf::Color(80, 80, 80));
+
+ // Start the game loop
+ sf::Clock clock;
+ while (window.isOpen())
+ {
+ // Process events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Close window: exit
+ if (event.type == sf::Event::Closed)
+ window.close();
+
+ if (event.type == sf::Event::KeyPressed)
+ {
+ switch (event.key.code)
+ {
+ // Escape key: exit
+ case sf::Keyboard::Escape:
+ window.close();
+ break;
+
+ // Left arrow key: previous shader
+ case sf::Keyboard::Left:
+ if (current == 0)
+ current = effects.size() - 1;
+ else
+ current--;
+ description.setString("Current effect: " + effects[current]->getName());
+ break;
+
+ // Right arrow key: next shader
+ case sf::Keyboard::Right:
+ if (current == effects.size() - 1)
+ current = 0;
+ else
+ current++;
+ description.setString("Current effect: " + effects[current]->getName());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // Update the current example
+ float x = static_cast<float>(sf::Mouse::getPosition(window).x) / window.getSize().x;
+ float y = static_cast<float>(sf::Mouse::getPosition(window).y) / window.getSize().y;
+ effects[current]->update(clock.getElapsedTime().asSeconds(), x, y);
+
+ // Clear the window
+ window.clear(sf::Color(255, 128, 0));
+
+ // Draw the current example
+ window.draw(*effects[current]);
+
+ // Draw the text
+ window.draw(textBackground);
+ window.draw(instructions);
+ window.draw(description);
+
+ // Finally, display the rendered frame on screen
+ window.display();
+ }
+
+ // delete the effects
+ for (std::size_t i = 0; i < effects.size(); ++i)
+ delete effects[i];
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/shader/resources/billboard.frag b/examples/shader/resources/billboard.frag
new file mode 100644
index 0000000..3057f64
--- /dev/null
+++ b/examples/shader/resources/billboard.frag
@@ -0,0 +1,11 @@
+#version 150
+
+uniform sampler2D texture;
+
+in vec2 tex_coord;
+
+void main()
+{
+ // Read and apply a color from the texture
+ gl_FragColor = texture2D(texture, tex_coord);
+}
diff --git a/examples/shader/resources/billboard.geom b/examples/shader/resources/billboard.geom
new file mode 100644
index 0000000..2f47a1f
--- /dev/null
+++ b/examples/shader/resources/billboard.geom
@@ -0,0 +1,56 @@
+#version 150
+
+// The render target's resolution (used for scaling)
+uniform vec2 resolution;
+
+// The billboards' size
+uniform vec2 size;
+
+// Input is the passed point cloud
+layout (points) in;
+
+// The output will consist of triangle strips with four vertices each
+layout (triangle_strip, max_vertices = 4) out;
+
+// Output texture coordinates
+out vec2 tex_coord;
+
+// Main entry point
+void main()
+{
+ // Caculate the half width/height of the billboards
+ vec2 half_size = size / 2.f;
+
+ // Scale the size based on resolution (1 would be full width/height)
+ half_size /= resolution;
+
+ // Iterate over all vertices
+ for (int i = 0; i < gl_in.length(); i++)
+ {
+ // Retrieve the passed vertex position
+ vec2 pos = gl_in[i].gl_Position.xy;
+
+ // Bottom left vertex
+ gl_Position = vec4(pos - half_size, 0.f, 1.f);
+ tex_coord = vec2(1.f, 1.f);
+ EmitVertex();
+
+ // Bottom right vertex
+ gl_Position = vec4(pos.x + half_size.x, pos.y - half_size.y, 0.f, 1.f);
+ tex_coord = vec2(0.f, 1.f);
+ EmitVertex();
+
+ // Top left vertex
+ gl_Position = vec4(pos.x - half_size.x, pos.y + half_size.y, 0.f, 1.f);
+ tex_coord = vec2(1.f, 0.f);
+ EmitVertex();
+
+ // Top right vertex
+ gl_Position = vec4(pos + half_size, 0.f, 1.f);
+ tex_coord = vec2(0.f, 0.f);
+ EmitVertex();
+
+ // And finalize the primitive
+ EndPrimitive();
+ }
+}
diff --git a/examples/shader/resources/billboard.vert b/examples/shader/resources/billboard.vert
new file mode 100644
index 0000000..3a89905
--- /dev/null
+++ b/examples/shader/resources/billboard.vert
@@ -0,0 +1,5 @@
+void main()
+{
+ // Transform the vertex position
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+}
diff --git a/examples/shader/resources/blink.frag b/examples/shader/resources/blink.frag
new file mode 100644
index 0000000..50a04a5
--- /dev/null
+++ b/examples/shader/resources/blink.frag
@@ -0,0 +1,9 @@
+uniform sampler2D texture;
+uniform float blink_alpha;
+
+void main()
+{
+ vec4 pixel = gl_Color;
+ pixel.a = blink_alpha;
+ gl_FragColor = pixel;
+}
diff --git a/examples/shader/resources/blur.frag b/examples/shader/resources/blur.frag
new file mode 100644
index 0000000..b8aba38
--- /dev/null
+++ b/examples/shader/resources/blur.frag
@@ -0,0 +1,20 @@
+uniform sampler2D texture;
+uniform float blur_radius;
+
+void main()
+{
+ vec2 offx = vec2(blur_radius, 0.0);
+ vec2 offy = vec2(0.0, blur_radius);
+
+ vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
+
+ gl_FragColor = gl_Color * (pixel / 16.0);
+}
diff --git a/examples/shader/resources/devices.png b/examples/shader/resources/devices.png
new file mode 100644
index 0000000..6b1cbc8
--- /dev/null
+++ b/examples/shader/resources/devices.png
Binary files differ
diff --git a/examples/shader/resources/edge.frag b/examples/shader/resources/edge.frag
new file mode 100644
index 0000000..7f869f5
--- /dev/null
+++ b/examples/shader/resources/edge.frag
@@ -0,0 +1,32 @@
+uniform sampler2D texture;
+uniform float edge_threshold;
+
+void main()
+{
+ const float offset = 1.0 / 512.0;
+ vec2 offx = vec2(offset, 0.0);
+ vec2 offy = vec2(0.0, offset);
+
+ vec4 hEdge = texture2D(texture, gl_TexCoord[0].xy - offy) * -2.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx - offy) * -1.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx - offy) * -1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
+
+ vec4 vEdge = texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx) * -2.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy - offx + offy) * -1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
+ texture2D(texture, gl_TexCoord[0].xy + offx + offy) * -1.0;
+
+ vec3 result = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
+ float edge = length(result);
+ vec4 pixel = gl_Color * texture2D(texture, gl_TexCoord[0].xy);
+ if (edge > (edge_threshold * 8.0))
+ pixel.rgb = vec3(0.0, 0.0, 0.0);
+ else
+ pixel.a = edge_threshold;
+ gl_FragColor = pixel;
+}
diff --git a/examples/shader/resources/logo.png b/examples/shader/resources/logo.png
new file mode 100644
index 0000000..29ba010
--- /dev/null
+++ b/examples/shader/resources/logo.png
Binary files differ
diff --git a/examples/shader/resources/pixelate.frag b/examples/shader/resources/pixelate.frag
new file mode 100644
index 0000000..79f8868
--- /dev/null
+++ b/examples/shader/resources/pixelate.frag
@@ -0,0 +1,9 @@
+uniform sampler2D texture;
+uniform float pixel_threshold;
+
+void main()
+{
+ float factor = 1.0 / (pixel_threshold + 0.001);
+ vec2 pos = floor(gl_TexCoord[0].xy * factor + 0.5) / factor;
+ gl_FragColor = texture2D(texture, pos) * gl_Color;
+}
diff --git a/examples/shader/resources/sansation.ttf b/examples/shader/resources/sansation.ttf
new file mode 100644
index 0000000..d85fbc8
--- /dev/null
+++ b/examples/shader/resources/sansation.ttf
Binary files differ
diff --git a/examples/shader/resources/sfml.png b/examples/shader/resources/sfml.png
new file mode 100644
index 0000000..1da719f
--- /dev/null
+++ b/examples/shader/resources/sfml.png
Binary files differ
diff --git a/examples/shader/resources/storm.vert b/examples/shader/resources/storm.vert
new file mode 100644
index 0000000..fab9da4
--- /dev/null
+++ b/examples/shader/resources/storm.vert
@@ -0,0 +1,19 @@
+uniform vec2 storm_position;
+uniform float storm_total_radius;
+uniform float storm_inner_radius;
+
+void main()
+{
+ vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
+ vec2 offset = vertex.xy - storm_position;
+ float len = length(offset);
+ if (len < storm_total_radius)
+ {
+ float push_distance = storm_inner_radius + len / storm_total_radius * (storm_total_radius - storm_inner_radius);
+ vertex.xy = storm_position + normalize(offset) * push_distance;
+ }
+
+ gl_Position = gl_ProjectionMatrix * vertex;
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+ gl_FrontColor = gl_Color;
+}
diff --git a/examples/shader/resources/text-background.png b/examples/shader/resources/text-background.png
new file mode 100644
index 0000000..c86e9b6
--- /dev/null
+++ b/examples/shader/resources/text-background.png
Binary files differ
diff --git a/examples/shader/resources/wave.vert b/examples/shader/resources/wave.vert
new file mode 100644
index 0000000..278a53b
--- /dev/null
+++ b/examples/shader/resources/wave.vert
@@ -0,0 +1,15 @@
+uniform float wave_phase;
+uniform vec2 wave_amplitude;
+
+void main()
+{
+ vec4 vertex = gl_Vertex;
+ vertex.x += cos(gl_Vertex.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x
+ + sin(gl_Vertex.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3;
+ vertex.y += sin(gl_Vertex.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y
+ + cos(gl_Vertex.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3;
+
+ gl_Position = gl_ModelViewProjectionMatrix * vertex;
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+ gl_FrontColor = gl_Color;
+}
diff --git a/examples/sockets/CMakeLists.txt b/examples/sockets/CMakeLists.txt
new file mode 100644
index 0000000..eebc91d
--- /dev/null
+++ b/examples/sockets/CMakeLists.txt
@@ -0,0 +1,12 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/sockets)
+
+# all source files
+set(SRC ${SRCROOT}/Sockets.cpp
+ ${SRCROOT}/TCP.cpp
+ ${SRCROOT}/UDP.cpp)
+
+# define the sockets target
+sfml_add_example(sockets
+ SOURCES ${SRC}
+ DEPENDS sfml-network)
diff --git a/examples/sockets/Sockets.cpp b/examples/sockets/Sockets.cpp
new file mode 100644
index 0000000..6bdd44b
--- /dev/null
+++ b/examples/sockets/Sockets.cpp
@@ -0,0 +1,59 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <iostream>
+#include <cstdlib>
+
+
+void runTcpServer(unsigned short port);
+void runTcpClient(unsigned short port);
+void runUdpServer(unsigned short port);
+void runUdpClient(unsigned short port);
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Choose an arbitrary port for opening sockets
+ const unsigned short port = 50001;
+
+ // TCP, UDP or connected UDP ?
+ char protocol;
+ std::cout << "Do you want to use TCP (t) or UDP (u)? ";
+ std::cin >> protocol;
+
+ // Client or server ?
+ char who;
+ std::cout << "Do you want to be a server (s) or a client (c)? ";
+ std::cin >> who;
+
+ if (protocol == 't')
+ {
+ // Test the TCP protocol
+ if (who == 's')
+ runTcpServer(port);
+ else
+ runTcpClient(port);
+ }
+ else
+ {
+ // Test the unconnected UDP protocol
+ if (who == 's')
+ runUdpServer(port);
+ else
+ runUdpClient(port);
+ }
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to exit..." << std::endl;
+ std::cin.ignore(10000, '\n');
+ std::cin.ignore(10000, '\n');
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/sockets/TCP.cpp b/examples/sockets/TCP.cpp
new file mode 100644
index 0000000..64fb7f9
--- /dev/null
+++ b/examples/sockets/TCP.cpp
@@ -0,0 +1,81 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network.hpp>
+#include <iostream>
+
+
+////////////////////////////////////////////////////////////
+/// Launch a server, wait for an incoming connection,
+/// send a message and wait for the answer.
+///
+////////////////////////////////////////////////////////////
+void runTcpServer(unsigned short port)
+{
+ // Create a server socket to accept new connections
+ sf::TcpListener listener;
+
+ // Listen to the given port for incoming connections
+ if (listener.listen(port) != sf::Socket::Done)
+ return;
+ std::cout << "Server is listening to port " << port << ", waiting for connections... " << std::endl;
+
+ // Wait for a connection
+ sf::TcpSocket socket;
+ if (listener.accept(socket) != sf::Socket::Done)
+ return;
+ std::cout << "Client connected: " << socket.getRemoteAddress() << std::endl;
+
+ // Send a message to the connected client
+ const char out[] = "Hi, I'm the server";
+ if (socket.send(out, sizeof(out)) != sf::Socket::Done)
+ return;
+ std::cout << "Message sent to the client: \"" << out << "\"" << std::endl;
+
+ // Receive a message back from the client
+ char in[128];
+ std::size_t received;
+ if (socket.receive(in, sizeof(in), received) != sf::Socket::Done)
+ return;
+ std::cout << "Answer received from the client: \"" << in << "\"" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create a client, connect it to a server, display the
+/// welcome message and send an answer.
+///
+////////////////////////////////////////////////////////////
+void runTcpClient(unsigned short port)
+{
+ // Ask for the server address
+ sf::IpAddress server;
+ do
+ {
+ std::cout << "Type the address or name of the server to connect to: ";
+ std::cin >> server;
+ }
+ while (server == sf::IpAddress::None);
+
+ // Create a socket for communicating with the server
+ sf::TcpSocket socket;
+
+ // Connect to the server
+ if (socket.connect(server, port) != sf::Socket::Done)
+ return;
+ std::cout << "Connected to server " << server << std::endl;
+
+ // Receive a message from the server
+ char in[128];
+ std::size_t received;
+ if (socket.receive(in, sizeof(in), received) != sf::Socket::Done)
+ return;
+ std::cout << "Message received from the server: \"" << in << "\"" << std::endl;
+
+ // Send an answer to the server
+ const char out[] = "Hi, I'm a client";
+ if (socket.send(out, sizeof(out)) != sf::Socket::Done)
+ return;
+ std::cout << "Message sent to the server: \"" << out << "\"" << std::endl;
+}
diff --git a/examples/sockets/UDP.cpp b/examples/sockets/UDP.cpp
new file mode 100644
index 0000000..37a07c5
--- /dev/null
+++ b/examples/sockets/UDP.cpp
@@ -0,0 +1,72 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network.hpp>
+#include <iostream>
+
+
+////////////////////////////////////////////////////////////
+/// Launch a server, wait for a message, send an answer.
+///
+////////////////////////////////////////////////////////////
+void runUdpServer(unsigned short port)
+{
+ // Create a socket to receive a message from anyone
+ sf::UdpSocket socket;
+
+ // Listen to messages on the specified port
+ if (socket.bind(port) != sf::Socket::Done)
+ return;
+ std::cout << "Server is listening to port " << port << ", waiting for a message... " << std::endl;
+
+ // Wait for a message
+ char in[128];
+ std::size_t received;
+ sf::IpAddress sender;
+ unsigned short senderPort;
+ if (socket.receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
+ return;
+ std::cout << "Message received from client " << sender << ": \"" << in << "\"" << std::endl;
+
+ // Send an answer to the client
+ const char out[] = "Hi, I'm the server";
+ if (socket.send(out, sizeof(out), sender, senderPort) != sf::Socket::Done)
+ return;
+ std::cout << "Message sent to the client: \"" << out << "\"" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a message to the server, wait for the answer
+///
+////////////////////////////////////////////////////////////
+void runUdpClient(unsigned short port)
+{
+ // Ask for the server address
+ sf::IpAddress server;
+ do
+ {
+ std::cout << "Type the address or name of the server to connect to: ";
+ std::cin >> server;
+ }
+ while (server == sf::IpAddress::None);
+
+ // Create a socket for communicating with the server
+ sf::UdpSocket socket;
+
+ // Send a message to the server
+ const char out[] = "Hi, I'm a client";
+ if (socket.send(out, sizeof(out), server, port) != sf::Socket::Done)
+ return;
+ std::cout << "Message sent to the server: \"" << out << "\"" << std::endl;
+
+ // Receive an answer from anyone (but most likely from the server)
+ char in[128];
+ std::size_t received;
+ sf::IpAddress sender;
+ unsigned short senderPort;
+ if (socket.receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
+ return;
+ std::cout << "Message received from " << sender << ": \"" << in << "\"" << std::endl;
+}
diff --git a/examples/sound/CMakeLists.txt b/examples/sound/CMakeLists.txt
new file mode 100644
index 0000000..d3875a6
--- /dev/null
+++ b/examples/sound/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/sound)
+
+# all source files
+set(SRC ${SRCROOT}/Sound.cpp)
+
+# define the sound target
+sfml_add_example(sound
+ SOURCES ${SRC}
+ DEPENDS sfml-audio
+ RESOURCES_DIR resources)
diff --git a/examples/sound/Sound.cpp b/examples/sound/Sound.cpp
new file mode 100644
index 0000000..e71aa0d
--- /dev/null
+++ b/examples/sound/Sound.cpp
@@ -0,0 +1,101 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio.hpp>
+#include <iostream>
+#include <string>
+
+
+////////////////////////////////////////////////////////////
+/// Play a sound
+///
+////////////////////////////////////////////////////////////
+void playSound()
+{
+ // Load a sound buffer from a wav file
+ sf::SoundBuffer buffer;
+ if (!buffer.loadFromFile("resources/canary.wav"))
+ return;
+
+ // Display sound informations
+ std::cout << "canary.wav:" << std::endl;
+ std::cout << " " << buffer.getDuration().asSeconds() << " seconds" << std::endl;
+ std::cout << " " << buffer.getSampleRate() << " samples / sec" << std::endl;
+ std::cout << " " << buffer.getChannelCount() << " channels" << std::endl;
+
+ // Create a sound instance and play it
+ sf::Sound sound(buffer);
+ sound.play();
+
+ // Loop while the sound is playing
+ while (sound.getStatus() == sf::Sound::Playing)
+ {
+ // Leave some CPU time for other processes
+ sf::sleep(sf::milliseconds(100));
+
+ // Display the playing position
+ std::cout << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec ";
+ std::cout << std::flush;
+ }
+ std::cout << std::endl << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Play a music
+///
+////////////////////////////////////////////////////////////
+void playMusic(const std::string& filename)
+{
+ // Load an ogg music file
+ sf::Music music;
+ if (!music.openFromFile("resources/" + filename))
+ return;
+
+ // Display music informations
+ std::cout << filename << ":" << std::endl;
+ std::cout << " " << music.getDuration().asSeconds() << " seconds" << std::endl;
+ std::cout << " " << music.getSampleRate() << " samples / sec" << std::endl;
+ std::cout << " " << music.getChannelCount() << " channels" << std::endl;
+
+ // Play it
+ music.play();
+
+ // Loop while the music is playing
+ while (music.getStatus() == sf::Music::Playing)
+ {
+ // Leave some CPU time for other processes
+ sf::sleep(sf::milliseconds(100));
+
+ // Display the playing position
+ std::cout << "\rPlaying... " << music.getPlayingOffset().asSeconds() << " sec ";
+ std::cout << std::flush;
+ }
+ std::cout << std::endl << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Play a sound
+ playSound();
+
+ // Play music from an ogg file
+ playMusic("orchestral.ogg");
+
+ // Play music from a flac file
+ playMusic("ding.flac");
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to exit..." << std::endl;
+ std::cin.ignore(10000, '\n');
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/sound/resources/ding.flac b/examples/sound/resources/ding.flac
new file mode 100644
index 0000000..4e62c78
--- /dev/null
+++ b/examples/sound/resources/ding.flac
Binary files differ
diff --git a/examples/sound_capture/CMakeLists.txt b/examples/sound_capture/CMakeLists.txt
new file mode 100644
index 0000000..e2c457f
--- /dev/null
+++ b/examples/sound_capture/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/sound_capture)
+
+# all source files
+set(SRC ${SRCROOT}/SoundCapture.cpp)
+
+# define the sound-capture target
+sfml_add_example(sound-capture
+ SOURCES ${SRC}
+ DEPENDS sfml-audio)
diff --git a/examples/sound_capture/SoundCapture.cpp b/examples/sound_capture/SoundCapture.cpp
new file mode 100644
index 0000000..19f114b
--- /dev/null
+++ b/examples/sound_capture/SoundCapture.cpp
@@ -0,0 +1,94 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio.hpp>
+#include <iostream>
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Check that the device can capture audio
+ if (sf::SoundRecorder::isAvailable() == false)
+ {
+ std::cout << "Sorry, audio capture is not supported by your system" << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ // Choose the sample rate
+ unsigned int sampleRate;
+ std::cout << "Please choose the sample rate for sound capture (44100 is CD quality): ";
+ std::cin >> sampleRate;
+ std::cin.ignore(10000, '\n');
+
+ // Wait for user input...
+ std::cout << "Press enter to start recording audio";
+ std::cin.ignore(10000, '\n');
+
+ // Here we'll use an integrated custom recorder, which saves the captured data into a SoundBuffer
+ sf::SoundBufferRecorder recorder;
+
+ // Audio capture is done in a separate thread, so we can block the main thread while it is capturing
+ recorder.start(sampleRate);
+ std::cout << "Recording... press enter to stop";
+ std::cin.ignore(10000, '\n');
+ recorder.stop();
+
+ // Get the buffer containing the captured data
+ const sf::SoundBuffer& buffer = recorder.getBuffer();
+
+ // Display captured sound informations
+ std::cout << "Sound information:" << std::endl;
+ std::cout << " " << buffer.getDuration().asSeconds() << " seconds" << std::endl;
+ std::cout << " " << buffer.getSampleRate() << " samples / seconds" << std::endl;
+ std::cout << " " << buffer.getChannelCount() << " channels" << std::endl;
+
+ // Choose what to do with the recorded sound data
+ char choice;
+ std::cout << "What do you want to do with captured sound (p = play, s = save) ? ";
+ std::cin >> choice;
+ std::cin.ignore(10000, '\n');
+
+ if (choice == 's')
+ {
+ // Choose the filename
+ std::string filename;
+ std::cout << "Choose the file to create: ";
+ std::getline(std::cin, filename);
+
+ // Save the buffer
+ buffer.saveToFile(filename);
+ }
+ else
+ {
+ // Create a sound instance and play it
+ sf::Sound sound(buffer);
+ sound.play();
+
+ // Wait until finished
+ while (sound.getStatus() == sf::Sound::Playing)
+ {
+ // Display the playing position
+ std::cout << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec ";
+ std::cout << std::flush;
+
+ // Leave some CPU time for other threads
+ sf::sleep(sf::milliseconds(100));
+ }
+ }
+
+ // Finished!
+ std::cout << std::endl << "Done!" << std::endl;
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to exit..." << std::endl;
+ std::cin.ignore(10000, '\n');
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/voip/CMakeLists.txt b/examples/voip/CMakeLists.txt
new file mode 100644
index 0000000..66bc074
--- /dev/null
+++ b/examples/voip/CMakeLists.txt
@@ -0,0 +1,12 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/voip)
+
+# all source files
+set(SRC ${SRCROOT}/VoIP.cpp
+ ${SRCROOT}/Client.cpp
+ ${SRCROOT}/Server.cpp)
+
+# define the voip target
+sfml_add_example(voip
+ SOURCES ${SRC}
+ DEPENDS sfml-audio sfml-network)
diff --git a/examples/voip/Client.cpp b/examples/voip/Client.cpp
new file mode 100644
index 0000000..d66e0e2
--- /dev/null
+++ b/examples/voip/Client.cpp
@@ -0,0 +1,141 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio.hpp>
+#include <SFML/Network.hpp>
+#include <iostream>
+
+
+const sf::Uint8 audioData = 1;
+const sf::Uint8 endOfStream = 2;
+
+
+////////////////////////////////////////////////////////////
+/// Specialization of audio recorder for sending recorded audio
+/// data through the network
+////////////////////////////////////////////////////////////
+class NetworkRecorder : public sf::SoundRecorder
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// Constructor
+ ///
+ /// \param host Remote host to which send the recording data
+ /// \param port Port of the remote host
+ ///
+ ////////////////////////////////////////////////////////////
+ NetworkRecorder(const sf::IpAddress& host, unsigned short port) :
+ m_host(host),
+ m_port(port)
+ {
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// Destructor
+ ///
+ /// \see SoundRecorder::~SoundRecorder()
+ ///
+ ////////////////////////////////////////////////////////////
+ ~NetworkRecorder()
+ {
+ // Make sure to stop the recording thread
+ stop();
+ }
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \see SoundRecorder::onStart
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool onStart()
+ {
+ if (m_socket.connect(m_host, m_port) == sf::Socket::Done)
+ {
+ std::cout << "Connected to server " << m_host << std::endl;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \see SoundRecorder::onProcessSamples
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool onProcessSamples(const sf::Int16* samples, std::size_t sampleCount)
+ {
+ // Pack the audio samples into a network packet
+ sf::Packet packet;
+ packet << audioData;
+ packet.append(samples, sampleCount * sizeof(sf::Int16));
+
+ // Send the audio packet to the server
+ return m_socket.send(packet) == sf::Socket::Done;
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \see SoundRecorder::onStop
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void onStop()
+ {
+ // Send a "end-of-stream" packet
+ sf::Packet packet;
+ packet << endOfStream;
+ m_socket.send(packet);
+
+ // Close the socket
+ m_socket.disconnect();
+ }
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ sf::IpAddress m_host; ///< Address of the remote host
+ unsigned short m_port; ///< Remote port
+ sf::TcpSocket m_socket; ///< Socket used to communicate with the server
+};
+
+
+////////////////////////////////////////////////////////////
+/// Create a client, connect it to a running server and
+/// start sending him audio data
+///
+////////////////////////////////////////////////////////////
+void doClient(unsigned short port)
+{
+ // Check that the device can capture audio
+ if (!sf::SoundRecorder::isAvailable())
+ {
+ std::cout << "Sorry, audio capture is not supported by your system" << std::endl;
+ return;
+ }
+
+ // Ask for server address
+ sf::IpAddress server;
+ do
+ {
+ std::cout << "Type address or name of the server to connect to: ";
+ std::cin >> server;
+ }
+ while (server == sf::IpAddress::None);
+
+ // Create an instance of our custom recorder
+ NetworkRecorder recorder(server, port);
+
+ // Wait for user input...
+ std::cin.ignore(10000, '\n');
+ std::cout << "Press enter to start recording audio";
+ std::cin.ignore(10000, '\n');
+
+ // Start capturing audio data
+ recorder.start(44100);
+ std::cout << "Recording... press enter to stop";
+ std::cin.ignore(10000, '\n');
+ recorder.stop();
+}
diff --git a/examples/voip/Server.cpp b/examples/voip/Server.cpp
new file mode 100644
index 0000000..0875bf9
--- /dev/null
+++ b/examples/voip/Server.cpp
@@ -0,0 +1,200 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio.hpp>
+#include <SFML/Network.hpp>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+
+
+const sf::Uint8 audioData = 1;
+const sf::Uint8 endOfStream = 2;
+
+
+////////////////////////////////////////////////////////////
+/// Customized sound stream for acquiring audio data
+/// from the network
+////////////////////////////////////////////////////////////
+class NetworkAudioStream : public sf::SoundStream
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ NetworkAudioStream() :
+ m_offset (0),
+ m_hasFinished(false)
+ {
+ // Set the sound parameters
+ initialize(1, 44100);
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// Run the server, stream audio data from the client
+ ///
+ ////////////////////////////////////////////////////////////
+ void start(unsigned short port)
+ {
+ if (!m_hasFinished)
+ {
+ // Listen to the given port for incoming connections
+ if (m_listener.listen(port) != sf::Socket::Done)
+ return;
+ std::cout << "Server is listening to port " << port << ", waiting for connections... " << std::endl;
+
+ // Wait for a connection
+ if (m_listener.accept(m_client) != sf::Socket::Done)
+ return;
+ std::cout << "Client connected: " << m_client.getRemoteAddress() << std::endl;
+
+ // Start playback
+ play();
+
+ // Start receiving audio data
+ receiveLoop();
+ }
+ else
+ {
+ // Start playback
+ play();
+ }
+ }
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// /see SoundStream::OnGetData
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool onGetData(sf::SoundStream::Chunk& data)
+ {
+ // We have reached the end of the buffer and all audio data have been played: we can stop playback
+ if ((m_offset >= m_samples.size()) && m_hasFinished)
+ return false;
+
+ // No new data has arrived since last update: wait until we get some
+ while ((m_offset >= m_samples.size()) && !m_hasFinished)
+ sf::sleep(sf::milliseconds(10));
+
+ // Copy samples into a local buffer to avoid synchronization problems
+ // (don't forget that we run in two separate threads)
+ {
+ sf::Lock lock(m_mutex);
+ m_tempBuffer.assign(m_samples.begin() + m_offset, m_samples.end());
+ }
+
+ // Fill audio data to pass to the stream
+ data.samples = &m_tempBuffer[0];
+ data.sampleCount = m_tempBuffer.size();
+
+ // Update the playing offset
+ m_offset += m_tempBuffer.size();
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// /see SoundStream::OnSeek
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void onSeek(sf::Time timeOffset)
+ {
+ m_offset = timeOffset.asMilliseconds() * getSampleRate() * getChannelCount() / 1000;
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// Get audio data from the client until playback is stopped
+ ///
+ ////////////////////////////////////////////////////////////
+ void receiveLoop()
+ {
+ while (!m_hasFinished)
+ {
+ // Get waiting audio data from the network
+ sf::Packet packet;
+ if (m_client.receive(packet) != sf::Socket::Done)
+ break;
+
+ // Extract the message ID
+ sf::Uint8 id;
+ packet >> id;
+
+ if (id == audioData)
+ {
+ // Extract audio samples from the packet, and append it to our samples buffer
+ const sf::Int16* samples = reinterpret_cast<const sf::Int16*>(static_cast<const char*>(packet.getData()) + 1);
+ std::size_t sampleCount = (packet.getDataSize() - 1) / sizeof(sf::Int16);
+
+ // Don't forget that the other thread can access the sample array at any time
+ // (so we protect any operation on it with the mutex)
+ {
+ sf::Lock lock(m_mutex);
+ std::copy(samples, samples + sampleCount, std::back_inserter(m_samples));
+ }
+ }
+ else if (id == endOfStream)
+ {
+ // End of stream reached: we stop receiving audio data
+ std::cout << "Audio data has been 100% received!" << std::endl;
+ m_hasFinished = true;
+ }
+ else
+ {
+ // Something's wrong...
+ std::cout << "Invalid packet received..." << std::endl;
+ m_hasFinished = true;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ sf::TcpListener m_listener;
+ sf::TcpSocket m_client;
+ sf::Mutex m_mutex;
+ std::vector<sf::Int16> m_samples;
+ std::vector<sf::Int16> m_tempBuffer;
+ std::size_t m_offset;
+ bool m_hasFinished;
+};
+
+
+////////////////////////////////////////////////////////////
+/// Launch a server and wait for incoming audio data from
+/// a connected client
+///
+////////////////////////////////////////////////////////////
+void doServer(unsigned short port)
+{
+ // Build an audio stream to play sound data as it is received through the network
+ NetworkAudioStream audioStream;
+ audioStream.start(port);
+
+ // Loop until the sound playback is finished
+ while (audioStream.getStatus() != sf::SoundStream::Stopped)
+ {
+ // Leave some CPU time for other threads
+ sf::sleep(sf::milliseconds(100));
+ }
+
+ std::cin.ignore(10000, '\n');
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to replay the sound..." << std::endl;
+ std::cin.ignore(10000, '\n');
+
+ // Replay the sound (just to make sure replaying the received data is OK)
+ audioStream.play();
+
+ // Loop until the sound playback is finished
+ while (audioStream.getStatus() != sf::SoundStream::Stopped)
+ {
+ // Leave some CPU time for other threads
+ sf::sleep(sf::milliseconds(100));
+ }
+}
diff --git a/examples/voip/VoIP.cpp b/examples/voip/VoIP.cpp
new file mode 100644
index 0000000..06c37b7
--- /dev/null
+++ b/examples/voip/VoIP.cpp
@@ -0,0 +1,50 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <iomanip>
+#include <iostream>
+#include <cstdlib>
+
+
+////////////////////////////////////////////////////////////
+// Function prototypes
+// (I'm too lazy to put them into separate headers...)
+////////////////////////////////////////////////////////////
+void doClient(unsigned short port);
+void doServer(unsigned short port);
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Choose a random port for opening sockets (ports < 1024 are reserved)
+ const unsigned short port = 2435;
+
+ // Client or server ?
+ char who;
+ std::cout << "Do you want to be a server ('s') or a client ('c')? ";
+ std::cin >> who;
+
+ if (who == 's')
+ {
+ // Run as a server
+ doServer(port);
+ }
+ else
+ {
+ // Run as a client
+ doClient(port);
+ }
+
+ // Wait until the user presses 'enter' key
+ std::cout << "Press enter to exit..." << std::endl;
+ std::cin.ignore(10000, '\n');
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/win32/CMakeLists.txt b/examples/win32/CMakeLists.txt
new file mode 100644
index 0000000..bd952c5
--- /dev/null
+++ b/examples/win32/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/win32)
+
+# all source files
+set(SRC ${SRCROOT}/Win32.cpp)
+
+# define the win32 target
+sfml_add_example(win32 GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-graphics
+ RESOURCES_DIR resources)
diff --git a/examples/win32/Win32.cpp b/examples/win32/Win32.cpp
new file mode 100644
index 0000000..aedfc76
--- /dev/null
+++ b/examples/win32/Win32.cpp
@@ -0,0 +1,132 @@
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics.hpp>
+#include <windows.h>
+#include <cmath>
+
+HWND button;
+
+
+////////////////////////////////////////////////////////////
+/// Function called whenever one of our windows receives a message
+///
+////////////////////////////////////////////////////////////
+LRESULT CALLBACK onEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ // Quit when we close the main window
+ case WM_CLOSE:
+ {
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ // Quit when we click the "quit" button
+ case WM_COMMAND:
+ {
+ if (reinterpret_cast<HWND>(lParam) == button)
+ {
+ PostQuitMessage(0);
+ return 0;
+ }
+ }
+ }
+
+ return DefWindowProc(handle, message, wParam, lParam);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \param Instance: Instance of the application
+///
+/// \return Error code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ HINSTANCE instance = GetModuleHandle(NULL);
+
+ // Define a class for our main window
+ WNDCLASS windowClass;
+ windowClass.style = 0;
+ windowClass.lpfnWndProc = &onEvent;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = 0;
+ windowClass.hInstance = instance;
+ windowClass.hIcon = NULL;
+ windowClass.hCursor = 0;
+ windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = TEXT("SFML App");
+ RegisterClass(&windowClass);
+
+ // Let's create the main window
+ HWND window = CreateWindow(TEXT("SFML App"), TEXT("SFML Win32"), WS_SYSMENU | WS_VISIBLE, 200, 200, 660, 520, NULL, NULL, instance, NULL);
+
+ // Add a button for exiting
+ button = CreateWindow(TEXT("BUTTON"), TEXT("Quit"), WS_CHILD | WS_VISIBLE, 560, 440, 80, 40, window, NULL, instance, NULL);
+
+ // Let's create two SFML views
+ HWND view1 = CreateWindow(TEXT("STATIC"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 20, 20, 300, 400, window, NULL, instance, NULL);
+ HWND view2 = CreateWindow(TEXT("STATIC"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 340, 20, 300, 400, window, NULL, instance, NULL);
+ sf::RenderWindow SFMLView1(view1);
+ sf::RenderWindow SFMLView2(view2);
+
+ // Load some textures to display
+ sf::Texture texture1, texture2;
+ if (!texture1.loadFromFile("resources/image1.jpg") || !texture2.loadFromFile("resources/image2.jpg"))
+ return EXIT_FAILURE;
+ sf::Sprite sprite1(texture1);
+ sf::Sprite sprite2(texture2);
+ sprite1.setOrigin(sf::Vector2f(texture1.getSize()) / 2.f);
+ sprite1.setPosition(sprite1.getOrigin());
+
+ // Create a clock for measuring elapsed time
+ sf::Clock clock;
+
+ // Loop until a WM_QUIT message is received
+ MSG message;
+ message.message = static_cast<UINT>(~WM_QUIT);
+ while (message.message != WM_QUIT)
+ {
+ if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
+ {
+ // If a message was waiting in the message queue, process it
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ else
+ {
+ float time = clock.getElapsedTime().asSeconds();
+
+ // Clear views
+ SFMLView1.clear();
+ SFMLView2.clear();
+
+ // Draw sprite 1 on view 1
+ sprite1.setRotation(time * 100);
+ SFMLView1.draw(sprite1);
+
+ // Draw sprite 2 on view 2
+ sprite2.setPosition(std::cos(time) * 100.f, 0.f);
+ SFMLView2.draw(sprite2);
+
+ // Display each view on screen
+ SFMLView1.display();
+ SFMLView2.display();
+ }
+ }
+
+ // Destroy the main window (all its child controls will be destroyed)
+ DestroyWindow(window);
+
+ // Don't forget to unregister the window class
+ UnregisterClass(TEXT("SFML App"), instance);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/window/CMakeLists.txt b/examples/window/CMakeLists.txt
new file mode 100644
index 0000000..b106c04
--- /dev/null
+++ b/examples/window/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/window)
+
+# all source files
+set(SRC ${SRCROOT}/Window.cpp)
+
+# define the window target
+sfml_add_example(window GUI_APP
+ SOURCES ${SRC}
+ DEPENDS sfml-window OpenGL)
diff --git a/examples/window/Window.cpp b/examples/window/Window.cpp
new file mode 100644
index 0000000..3fcea52
--- /dev/null
+++ b/examples/window/Window.cpp
@@ -0,0 +1,146 @@
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window.hpp>
+#include <SFML/OpenGL.hpp>
+
+
+////////////////////////////////////////////////////////////
+/// Entry point of application
+///
+/// \return Application exit code
+///
+////////////////////////////////////////////////////////////
+int main()
+{
+ // Request a 24-bits depth buffer when creating the window
+ sf::ContextSettings contextSettings;
+ contextSettings.depthBits = 24;
+
+ // Create the main window
+ sf::Window window(sf::VideoMode(640, 480), "SFML window with OpenGL", sf::Style::Default, contextSettings);
+
+ // Make it the active window for OpenGL calls
+ window.setActive();
+
+ // Set the color and depth clear values
+ glClearDepth(1.f);
+ glClearColor(0.f, 0.f, 0.f, 1.f);
+
+ // Enable Z-buffer read and write
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+
+ // Disable lighting and texturing
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+
+ // Configure the viewport (the same size as the window)
+ glViewport(0, 0, window.getSize().x, window.getSize().y);
+
+ // Setup a perspective projection
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
+ glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
+
+ // Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
+ GLfloat cube[] =
+ {
+ // positions // colors (r, g, b, a)
+ -50, -50, -50, 0, 0, 1, 1,
+ -50, 50, -50, 0, 0, 1, 1,
+ -50, -50, 50, 0, 0, 1, 1,
+ -50, -50, 50, 0, 0, 1, 1,
+ -50, 50, -50, 0, 0, 1, 1,
+ -50, 50, 50, 0, 0, 1, 1,
+
+ 50, -50, -50, 0, 1, 0, 1,
+ 50, 50, -50, 0, 1, 0, 1,
+ 50, -50, 50, 0, 1, 0, 1,
+ 50, -50, 50, 0, 1, 0, 1,
+ 50, 50, -50, 0, 1, 0, 1,
+ 50, 50, 50, 0, 1, 0, 1,
+
+ -50, -50, -50, 1, 0, 0, 1,
+ 50, -50, -50, 1, 0, 0, 1,
+ -50, -50, 50, 1, 0, 0, 1,
+ -50, -50, 50, 1, 0, 0, 1,
+ 50, -50, -50, 1, 0, 0, 1,
+ 50, -50, 50, 1, 0, 0, 1,
+
+ -50, 50, -50, 0, 1, 1, 1,
+ 50, 50, -50, 0, 1, 1, 1,
+ -50, 50, 50, 0, 1, 1, 1,
+ -50, 50, 50, 0, 1, 1, 1,
+ 50, 50, -50, 0, 1, 1, 1,
+ 50, 50, 50, 0, 1, 1, 1,
+
+ -50, -50, -50, 1, 0, 1, 1,
+ 50, -50, -50, 1, 0, 1, 1,
+ -50, 50, -50, 1, 0, 1, 1,
+ -50, 50, -50, 1, 0, 1, 1,
+ 50, -50, -50, 1, 0, 1, 1,
+ 50, 50, -50, 1, 0, 1, 1,
+
+ -50, -50, 50, 1, 1, 0, 1,
+ 50, -50, 50, 1, 1, 0, 1,
+ -50, 50, 50, 1, 1, 0, 1,
+ -50, 50, 50, 1, 1, 0, 1,
+ 50, -50, 50, 1, 1, 0, 1,
+ 50, 50, 50, 1, 1, 0, 1,
+ };
+
+ // Enable position and color vertex components
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 7 * sizeof(GLfloat), cube);
+ glColorPointer(4, GL_FLOAT, 7 * sizeof(GLfloat), cube + 3);
+
+ // Disable normal and texture coordinates vertex components
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ // Create a clock for measuring the time elapsed
+ sf::Clock clock;
+
+ // Start the game loop
+ while (window.isOpen())
+ {
+ // Process events
+ sf::Event event;
+ while (window.pollEvent(event))
+ {
+ // Close window: exit
+ if (event.type == sf::Event::Closed)
+ window.close();
+
+ // Escape key: exit
+ if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
+ window.close();
+
+ // Resize event: adjust the viewport
+ if (event.type == sf::Event::Resized)
+ glViewport(0, 0, event.size.width, event.size.height);
+ }
+
+ // Clear the color and depth buffers
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Apply some transformations to rotate the cube
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.f, 0.f, -200.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 50, 1.f, 0.f, 0.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 30, 0.f, 1.f, 0.f);
+ glRotatef(clock.getElapsedTime().asSeconds() * 90, 0.f, 0.f, 1.f);
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+
+ // Finally, display the rendered frame on screen
+ window.display();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/extlibs/Android.mk b/extlibs/Android.mk
new file mode 100644
index 0000000..26d966b
--- /dev/null
+++ b/extlibs/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := freetype
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libfreetype.a
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := openal
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libopenal.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+include $(PREBUILT_SHARED_LIBRARY)
diff --git a/extlibs/headers/stb_image/stb_image.h b/extlibs/headers/stb_image/stb_image.h
new file mode 100644
index 0000000..a056138
--- /dev/null
+++ b/extlibs/headers/stb_image/stb_image.h
@@ -0,0 +1,7187 @@
+/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h
+ no warranty implied; use at your own risk
+
+ Do this:
+ #define STB_IMAGE_IMPLEMENTATION
+ before you include this file in *one* C or C++ file to create the implementation.
+
+ // i.e. it should look like this:
+ #include ...
+ #include ...
+ #include ...
+ #define STB_IMAGE_IMPLEMENTATION
+ #include "stb_image.h"
+
+ You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+ And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+ QUICK NOTES:
+ Primarily of interest to game developers and other people who can
+ avoid problematic images and only need the trivial interface
+
+ JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+ PNG 1/2/4/8/16-bit-per-channel
+
+ TGA (not sure what subset, if a subset)
+ BMP non-1bpp, non-RLE
+ PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+ GIF (*comp always reports as 4-channel)
+ HDR (radiance rgbE format)
+ PIC (Softimage PIC)
+ PNM (PPM and PGM binary only)
+
+ Animated GIF still needs a proper API, but here's one way to do it:
+ http://gist.github.com/urraka/685d9a6340b26b830d49
+
+ - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+ - decode from arbitrary I/O callbacks
+ - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+ Full documentation under "DOCUMENTATION" below.
+
+
+LICENSE
+
+ See end of file for license information.
+
+RECENT REVISION HISTORY:
+
+ 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
+ 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
+ 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+ 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+ RGB-format JPEG; remove white matting in PSD;
+ allocate large structures on the stack;
+ correct channel count for PNG & BMP
+ 2.10 (2016-01-22) avoid warning introduced in 2.09
+ 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+
+ See end of file for full revision history.
+
+
+ ============================ Contributors =========================
+
+ Image formats Extensions, features
+ Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
+ Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
+ Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
+ Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
+ Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
+ Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
+ Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
+ github:urraka (animated gif) Junggon Kim (PNM comments)
+ Daniel Gibson (16-bit TGA)
+ socks-the-fox (16-bit PNG)
+ Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes
+ Fabian "ryg" Giesen
+ Arseny Kapoulkine
+ John-Mark Allen
+
+ Bug & warning fixes
+ Marc LeBlanc David Woo Guillaume George Martins Mozeiko
+ Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
+ Dave Moore Roy Eltham Hayaki Saito Nathan Reed
+ Won Chun Luke Graham Johan Duparc Nick Verigakis
+ the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson
+ Janez Zemva John Bartholomew Michal Cichon github:rlyeh
+ Jonathan Blow Ken Hamada Tero Hanninen github:romigrou
+ Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk
+ Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar
+ Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex
+ Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
+ Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
+ Blazej Dariusz Roszkowski Gregory Mullen github:phprus
+ Christian Floisand Kevin Schmidt github:poppolopoppo
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+// - no 16-bit-per-channel PNG
+// - no 12-bit-per-channel JPEG
+// - no JPEGs with arithmetic coding
+// - no 1-bit BMP
+// - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+// int x,y,n;
+// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+// // ... process data if not NULL ...
+// // ... x = width, y = height, n = # 8-bit components per pixel ...
+// // ... replace '0' with '1'..'4' to force that many components per pixel
+// // ... but 'n' will always be the number that it would have been if you said 0
+// stbi_image_free(data)
+//
+// Standard parameters:
+// int *x -- outputs image width in pixels
+// int *y -- outputs image height in pixels
+// int *channels_in_file -- outputs # of image components in image file
+// int desired_channels -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file to see if it's trivially
+// opaque because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+// N=#comp components
+// 1 grey
+// 2 grey, alpha
+// 3 red, green, blue
+// 4 red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+// 1. easy to use
+// 2. easy to maintain
+// 3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+// - Portable ("ease of use")
+// - Small source code footprint ("easy to maintain")
+// - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+// stbi_hdr_to_ldr_gamma(2.2f);
+// stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+// float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+// stbi_ldr_to_hdr_scale(1.0f);
+// stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+// stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+// ===========================================================================
+//
+// ADDITIONAL CONFIGURATION
+//
+// - You can suppress implementation of any of the decoders to reduce
+// your code footprint by #defining one or more of the following
+// symbols before creating the implementation.
+//
+// STBI_NO_JPEG
+// STBI_NO_PNG
+// STBI_NO_BMP
+// STBI_NO_PSD
+// STBI_NO_TGA
+// STBI_NO_GIF
+// STBI_NO_HDR
+// STBI_NO_PIC
+// STBI_NO_PNM (.ppm and .pgm)
+//
+// - You can request *only* certain decoders and suppress all other ones
+// (this will be more forward-compatible, as addition of new decoders
+// doesn't require you to disable them explicitly):
+//
+// STBI_ONLY_JPEG
+// STBI_ONLY_PNG
+// STBI_ONLY_BMP
+// STBI_ONLY_PSD
+// STBI_ONLY_TGA
+// STBI_ONLY_GIF
+// STBI_ONLY_HDR
+// STBI_ONLY_PIC
+// STBI_ONLY_PNM (.ppm and .pgm)
+//
+// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+ STBI_default = 0, // only used for desired_channels
+
+ STBI_grey = 1,
+ STBI_grey_alpha = 2,
+ STBI_rgb = 3,
+ STBI_rgb_alpha = 4
+};
+
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+ int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
+ void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+ int (*eof) (void *user); // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+ STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+ #ifndef STBI_NO_STDIO
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+ #endif
+#endif
+
+#ifndef STBI_NO_HDR
+ STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
+ STBIDEF void stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+ STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
+ STBIDEF void stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename);
+STBIDEF int stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void stbi_image_free (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+ || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+ || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+ || defined(STBI_ONLY_ZLIB)
+ #ifndef STBI_ONLY_JPEG
+ #define STBI_NO_JPEG
+ #endif
+ #ifndef STBI_ONLY_PNG
+ #define STBI_NO_PNG
+ #endif
+ #ifndef STBI_ONLY_BMP
+ #define STBI_NO_BMP
+ #endif
+ #ifndef STBI_ONLY_PSD
+ #define STBI_NO_PSD
+ #endif
+ #ifndef STBI_ONLY_TGA
+ #define STBI_NO_TGA
+ #endif
+ #ifndef STBI_ONLY_GIF
+ #define STBI_NO_GIF
+ #endif
+ #ifndef STBI_ONLY_HDR
+ #define STBI_NO_HDR
+ #endif
+ #ifndef STBI_ONLY_PIC
+ #define STBI_NO_PIC
+ #endif
+ #ifndef STBI_ONLY_PNM
+ #define STBI_NO_PNM
+ #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h> // ldexp
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+
+#ifndef _MSC_VER
+ #ifdef __cplusplus
+ #define stbi_inline inline
+ #else
+ #define stbi_inline
+ #endif
+#else
+ #define stbi_inline __forceinline
+#endif
+
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef signed short stbi__int16;
+typedef unsigned int stbi__uint32;
+typedef signed int stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v) (void)(v)
+#else
+#define STBI_NOTUSED(v) (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+ #define stbi_lrot(x,y) _lrotl(x,y)
+#else
+ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz) malloc(sz)
+#define STBI_REALLOC(p,newsz) realloc(p,newsz)
+#define STBI_FREE(p) free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
+// but previous attempts to provide the SSE2 functions with runtime
+// detection caused numerous issues. The way architecture extensions are
+// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
+// New behavior: if compiled with -msse2, we use SSE2 without any
+// detection; if not, we don't use it at all.
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400 // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+ int info[4];
+ __cpuid(info,1);
+ return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+ int res;
+ __asm {
+ mov eax,1
+ cpuid
+ mov res,edx
+ }
+ return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+static int stbi__sse2_available(void)
+{
+ int info3 = stbi__cpuid3();
+ return ((info3 >> 26) & 1) != 0;
+}
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+static int stbi__sse2_available(void)
+{
+ // If we're even attempting to compile this on GCC/Clang, that means
+ // -msse2 is on, which means the compiler is allowed to use SSE2
+ // instructions at will, and so are we.
+ return 1;
+}
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+///////////////////////////////////////////////
+//
+// stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+ stbi__uint32 img_x, img_y;
+ int img_n, img_out_n;
+
+ stbi_io_callbacks io;
+ void *io_user_data;
+
+ int read_from_callbacks;
+ int buflen;
+ stbi_uc buffer_start[128];
+
+ stbi_uc *img_buffer, *img_buffer_end;
+ stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+ s->io.read = NULL;
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+ s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+ s->io = *c;
+ s->io_user_data = user;
+ s->buflen = sizeof(s->buffer_start);
+ s->read_from_callbacks = 1;
+ s->img_buffer_original = s->buffer_start;
+ stbi__refill_buffer(s);
+ s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+ return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+ fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stbi__stdio_eof(void *user)
+{
+ return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+ stbi__stdio_read,
+ stbi__stdio_skip,
+ stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+ stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+ // conceptually rewind SHOULD rewind to the beginning of the stream,
+ // but we just rewind to the beginning of the initial buffer, because
+ // we only use it after doing 'test', which only ever looks at at most 92 bytes
+ s->img_buffer = s->img_buffer_original;
+ s->img_buffer_end = s->img_buffer_original_end;
+}
+
+enum
+{
+ STBI_ORDER_RGB,
+ STBI_ORDER_BGR
+};
+
+typedef struct
+{
+ int bits_per_channel;
+ int num_channels;
+ int channel_order;
+} stbi__result_info;
+
+#ifndef STBI_NO_JPEG
+static int stbi__jpeg_test(stbi__context *s);
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int stbi__png_test(stbi__context *s);
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test(stbi__context *s);
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int stbi__tga_test(stbi__context *s);
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s);
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test(stbi__context *s);
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_test(stbi__context *s);
+static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int stbi__gif_test(stbi__context *s);
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int stbi__pnm_test(stbi__context *s);
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+// this is not threadsafe
+static const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+ return stbi__g_failure_reason;
+}
+
+static int stbi__err(const char *str)
+{
+ stbi__g_failure_reason = str;
+ return 0;
+}
+
+static void *stbi__malloc(size_t size)
+{
+ return STBI_MALLOC(size);
+}
+
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+ if (b < 0) return 0;
+ // now 0 <= b <= INT_MAX, hence also
+ // 0 <= INT_MAX - b <= INTMAX.
+ // And "a + b <= INT_MAX" (which might overflow) is the
+ // same as a <= INT_MAX - b (no overflow)
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+ if (a < 0 || b < 0) return 0;
+ if (b == 0) return 1; // mul-by-0 is always safe
+ // portable way to check for no overflows in a*b
+ return a <= INT_MAX/b;
+}
+
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+ if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+ return stbi__malloc(a*b + add);
+}
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+ if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+ return stbi__malloc(a*b*c + add);
+}
+
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+ if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+ return stbi__malloc(a*b*c*d + add);
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+ #define stbi__err(x,y) 0
+#elif defined(STBI_FAILURE_USERMSG)
+ #define stbi__err(x,y) stbi__err(y)
+#else
+ #define stbi__err(x,y) stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+ STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load = flag_true_if_should_flip;
+}
+
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+ ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+ ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+ ri->num_channels = 0;
+
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PNG
+ if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+ #endif
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
+ return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+ }
+ #endif
+
+ #ifndef STBI_NO_TGA
+ // test tga last because it's a crappy test!
+ if (stbi__tga_test(s))
+ return stbi__tga_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi_uc *reduced;
+
+ reduced = (stbi_uc *) stbi__malloc(img_len);
+ if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+ STBI_FREE(orig);
+ return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi__uint16 *enlarged;
+
+ enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+ if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+ STBI_FREE(orig);
+ return enlarged;
+}
+
+static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
+{
+ int row;
+ size_t bytes_per_row = (size_t)w * bytes_per_pixel;
+ stbi_uc temp[2048];
+ stbi_uc *bytes = (stbi_uc *)image;
+
+ for (row = 0; row < (h>>1); row++) {
+ stbi_uc *row0 = bytes + row*bytes_per_row;
+ stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
+ // swap row0 with row1
+ size_t bytes_left = bytes_per_row;
+ while (bytes_left) {
+ size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
+ memcpy(temp, row0, bytes_copy);
+ memcpy(row0, row1, bytes_copy);
+ memcpy(row1, temp, bytes_copy);
+ row0 += bytes_copy;
+ row1 += bytes_copy;
+ bytes_left -= bytes_copy;
+ }
+ }
+}
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 8) {
+ STBI_ASSERT(ri.bits_per_channel == 16);
+ result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 8;
+ }
+
+ // @TODO: move stbi__convert_format to here
+
+ if (stbi__vertically_flip_on_load) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
+ }
+
+ return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 16) {
+ STBI_ASSERT(ri.bits_per_channel == 8);
+ result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 16;
+ }
+
+ // @TODO: move stbi__convert_format16 to here
+ // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+ if (stbi__vertically_flip_on_load) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
+ }
+
+ return (stbi__uint16 *) result;
+}
+
+#ifndef STBI_NO_HDR
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+ if (stbi__vertically_flip_on_load && result != NULL) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
+ }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+ FILE *f;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != fopen_s(&f, filename, mode))
+ f=0;
+#else
+ f = fopen(filename, mode);
+#endif
+ return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ unsigned char *result;
+ if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__uint16 *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ stbi__uint16 *result;
+ if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *data;
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ stbi__result_info ri;
+ float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
+ if (hdr_data)
+ stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+ return hdr_data;
+ }
+ #endif
+ data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
+ if (data)
+ return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+ return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ float *result;
+ FILE *f = stbi__fopen(filename, "rb");
+ if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+ result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(buffer);
+ STBI_NOTUSED(len);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result=0;
+ if (f) {
+ result = stbi_is_hdr_from_file(f);
+ fclose(f);
+ }
+ return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(f);
+ return 0;
+ #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(clbk);
+ STBI_NOTUSED(user);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+ STBI__SCAN_load=0,
+ STBI__SCAN_type,
+ STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+ int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+ if (n == 0) {
+ // at end of file, treat same as if from memory, but need to handle case
+ // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start+1;
+ *s->img_buffer = 0;
+ } else {
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start + n;
+ }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+ if (s->img_buffer < s->img_buffer_end)
+ return *s->img_buffer++;
+ if (s->read_from_callbacks) {
+ stbi__refill_buffer(s);
+ return *s->img_buffer++;
+ }
+ return 0;
+}
+
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+ if (s->io.read) {
+ if (!(s->io.eof)(s->io_user_data)) return 0;
+ // if feof() is true, check if buffer = end
+ // special case: we've only got the special 0 character at the end
+ if (s->read_from_callbacks == 0) return 1;
+ }
+
+ return s->img_buffer >= s->img_buffer_end;
+}
+
+static void stbi__skip(stbi__context *s, int n)
+{
+ if (n < 0) {
+ s->img_buffer = s->img_buffer_end;
+ return;
+ }
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ s->img_buffer = s->img_buffer_end;
+ (s->io.skip)(s->io_user_data, n - blen);
+ return;
+ }
+ }
+ s->img_buffer += n;
+}
+
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ int res, count;
+
+ memcpy(buffer, s->img_buffer, blen);
+
+ count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+ res = (count == (n-blen));
+ s->img_buffer = s->img_buffer_end;
+ return res;
+ }
+ }
+
+ if (s->img_buffer+n <= s->img_buffer_end) {
+ memcpy(buffer, s->img_buffer, n);
+ s->img_buffer += n;
+ return 1;
+ } else
+ return 0;
+}
+
+static int stbi__get16be(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return (z << 8) + stbi__get8(s);
+}
+
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16be(s);
+ return (z << 16) + stbi__get16be(s);
+}
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16le(s);
+ return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// generic converter from built-in img_n to req_comp
+// individual types do this automatically as much as possible (e.g. jpeg
+// does all cases internally since it needs to colorspace convert anyway,
+// and it never has alpha, so very few cases ). png can automatically
+// interleave an alpha=255 channel, but falls back to this for other cases
+//
+// assume data buffer is malloced, so malloc a new one and free that one
+// only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+ return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ unsigned char *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ unsigned char *src = data + j * x * img_n ;
+ unsigned char *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0);
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+ return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ stbi__uint16 *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ stbi__uint16 *src = data + j * x * img_n ;
+ stbi__uint16 *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0);
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+ int i,k,n;
+ float *output;
+ if (!data) return NULL;
+ output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+ }
+ if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x) ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
+{
+ int i,k,n;
+ stbi_uc *output;
+ if (!data) return NULL;
+ output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ if (k < comp) {
+ float z = data[i*comp+k] * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// "baseline" JPEG/JFIF decoder
+//
+// simple implementation
+// - doesn't support delayed output of y-dimension
+// - simple interface (only one output format: 8-bit interleaved RGB)
+// - doesn't try to recover corrupt jpegs
+// - doesn't allow partial loading, loading multiple at once
+// - still fast on x86 (copying globals into locals doesn't help x86)
+// - allocates lots of intermediate memory (full size of all components)
+// - non-interleaved case requires this anyway
+// - allows good upsampling (see next)
+// high-quality
+// - upsampled channels are bilinearly interpolated, even across blocks
+// - quality integer IDCT derived from IJG's 'slow'
+// performance
+// - fast huffman; reasonable integer IDCT
+// - some SIMD kernels for common paths on targets with SSE2/NEON
+// - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+ stbi_uc fast[1 << FAST_BITS];
+ // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+ stbi__uint16 code[256];
+ stbi_uc values[256];
+ stbi_uc size[257];
+ unsigned int maxcode[18];
+ int delta[17]; // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+ stbi__context *s;
+ stbi__huffman huff_dc[4];
+ stbi__huffman huff_ac[4];
+ stbi__uint16 dequant[4][64];
+ stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+ int img_h_max, img_v_max;
+ int img_mcu_x, img_mcu_y;
+ int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+ struct
+ {
+ int id;
+ int h,v;
+ int tq;
+ int hd,ha;
+ int dc_pred;
+
+ int x,y,w2,h2;
+ stbi_uc *data;
+ void *raw_data, *raw_coeff;
+ stbi_uc *linebuf;
+ short *coeff; // progressive only
+ int coeff_w, coeff_h; // number of 8x8 coefficient blocks
+ } img_comp[4];
+
+ stbi__uint32 code_buffer; // jpeg entropy-coded buffer
+ int code_bits; // number of valid bits
+ unsigned char marker; // marker seen while filling entropy buffer
+ int nomore; // flag if we saw a marker so must stop
+
+ int progressive;
+ int spec_start;
+ int spec_end;
+ int succ_high;
+ int succ_low;
+ int eob_run;
+ int jfif;
+ int app14_color_transform; // Adobe APP14 tag
+ int rgb;
+
+ int scan_n, order[4];
+ int restart_interval, todo;
+
+// kernels
+ void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+ void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+ stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+ int i,j,k=0,code;
+ // build size list for each symbol (from JPEG spec)
+ for (i=0; i < 16; ++i)
+ for (j=0; j < count[i]; ++j)
+ h->size[k++] = (stbi_uc) (i+1);
+ h->size[k] = 0;
+
+ // compute actual symbols (from jpeg spec)
+ code = 0;
+ k = 0;
+ for(j=1; j <= 16; ++j) {
+ // compute delta to add to code to compute symbol id
+ h->delta[j] = k - code;
+ if (h->size[k] == j) {
+ while (h->size[k] == j)
+ h->code[k++] = (stbi__uint16) (code++);
+ if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+ }
+ // compute largest code + 1 for this size, preshifted as needed later
+ h->maxcode[j] = code << (16-j);
+ code <<= 1;
+ }
+ h->maxcode[j] = 0xffffffff;
+
+ // build non-spec acceleration table; 255 is flag for not-accelerated
+ memset(h->fast, 255, 1 << FAST_BITS);
+ for (i=0; i < k; ++i) {
+ int s = h->size[i];
+ if (s <= FAST_BITS) {
+ int c = h->code[i] << (FAST_BITS-s);
+ int m = 1 << (FAST_BITS-s);
+ for (j=0; j < m; ++j) {
+ h->fast[c+j] = (stbi_uc) i;
+ }
+ }
+ }
+ return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+ int i;
+ for (i=0; i < (1 << FAST_BITS); ++i) {
+ stbi_uc fast = h->fast[i];
+ fast_ac[i] = 0;
+ if (fast < 255) {
+ int rs = h->values[fast];
+ int run = (rs >> 4) & 15;
+ int magbits = rs & 15;
+ int len = h->size[fast];
+
+ if (magbits && len + magbits <= FAST_BITS) {
+ // magnitude code followed by receive_extend code
+ int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+ int m = 1 << (magbits - 1);
+ if (k < m) k += (~0U << magbits) + 1;
+ // if the result is small enough, we can fit it in fast_ac table
+ if (k >= -128 && k <= 127)
+ fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+ }
+ }
+ }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+ do {
+ int b = j->nomore ? 0 : stbi__get8(j->s);
+ if (b == 0xff) {
+ int c = stbi__get8(j->s);
+ while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
+ if (c != 0) {
+ j->marker = (unsigned char) c;
+ j->nomore = 1;
+ return;
+ }
+ }
+ j->code_buffer |= b << (24 - j->code_bits);
+ j->code_bits += 8;
+ } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+ unsigned int temp;
+ int c,k;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ // look at the top FAST_BITS and determine what symbol ID it is,
+ // if the code is <= FAST_BITS
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ k = h->fast[c];
+ if (k < 255) {
+ int s = h->size[k];
+ if (s > j->code_bits)
+ return -1;
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ return h->values[k];
+ }
+
+ // naive test is to shift the code_buffer down so k bits are
+ // valid, then test against maxcode. To speed this up, we've
+ // preshifted maxcode left so that it has (16-k) 0s at the
+ // end; in other words, regardless of the number of bits, it
+ // wants to be compared against something shifted to have 16;
+ // that way we don't need to shift inside the loop.
+ temp = j->code_buffer >> 16;
+ for (k=FAST_BITS+1 ; ; ++k)
+ if (temp < h->maxcode[k])
+ break;
+ if (k == 17) {
+ // error! code not found
+ j->code_bits -= 16;
+ return -1;
+ }
+
+ if (k > j->code_bits)
+ return -1;
+
+ // convert the huffman code to the symbol id
+ c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+ STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+ // convert the id to a symbol
+ j->code_bits -= k;
+ j->code_buffer <<= k;
+ return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ int sgn;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+ sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+ k = stbi_lrot(j->code_buffer, n);
+ STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+ k = stbi_lrot(j->code_buffer, n);
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+ unsigned int k;
+ if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+ k = j->code_buffer;
+ j->code_buffer <<= 1;
+ --j->code_bits;
+ return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ // let corrupt input sample past end
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
+{
+ int diff,dc,k;
+ int t;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ t = stbi__jpeg_huff_decode(j, hdc);
+ if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+ // 0 all the ac values now so we can do it 32-bits at a time
+ memset(data,0,64*sizeof(data[0]));
+
+ diff = t ? stbi__extend_receive(j, t) : 0;
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc * dequant[0]);
+
+ // decode AC components, see JPEG spec
+ k = 1;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) * dequant[zig]);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (rs != 0xf0) break; // end block
+ k += 16;
+ } else {
+ k += r;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+ }
+ }
+ } while (k < 64);
+ return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+ int diff,dc;
+ int t;
+ if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ if (j->succ_high == 0) {
+ // first scan for DC coefficient, must be first
+ memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+ t = stbi__jpeg_huff_decode(j, hdc);
+ diff = t ? stbi__extend_receive(j, t) : 0;
+
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc << j->succ_low);
+ } else {
+ // refinement scan for DC coefficient
+ if (stbi__jpeg_get_bit(j))
+ data[0] += (short) (1 << j->succ_low);
+ }
+ return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+ int k;
+ if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->succ_high == 0) {
+ int shift = j->succ_low;
+
+ if (j->eob_run) {
+ --j->eob_run;
+ return 1;
+ }
+
+ k = j->spec_start;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) << shift);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r);
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ --j->eob_run;
+ break;
+ }
+ k += 16;
+ } else {
+ k += r;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+ }
+ }
+ } while (k <= j->spec_end);
+ } else {
+ // refinement scan for these AC coefficients
+
+ short bit = (short) (1 << j->succ_low);
+
+ if (j->eob_run) {
+ --j->eob_run;
+ for (k = j->spec_start; k <= j->spec_end; ++k) {
+ short *p = &data[stbi__jpeg_dezigzag[k]];
+ if (*p != 0)
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ }
+ } else {
+ k = j->spec_start;
+ do {
+ int r,s;
+ int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r) - 1;
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ r = 64; // force end of block
+ } else {
+ // r=15 s=0 should write 16 0s, so we just do
+ // a run of 15 0s and then write s (which is 0),
+ // so we don't have to do anything special here
+ }
+ } else {
+ if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+ // sign bit
+ if (stbi__jpeg_get_bit(j))
+ s = bit;
+ else
+ s = -bit;
+ }
+
+ // advance by r
+ while (k <= j->spec_end) {
+ short *p = &data[stbi__jpeg_dezigzag[k++]];
+ if (*p != 0) {
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ } else {
+ if (r == 0) {
+ *p = (short) s;
+ break;
+ }
+ --r;
+ }
+ }
+ } while (k <= j->spec_end);
+ }
+ }
+ return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+ // trick to use a single test to catch both cases
+ if ((unsigned int) x > 255) {
+ if (x < 0) return 0;
+ if (x > 255) return 255;
+ }
+ return (stbi_uc) x;
+}
+
+#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x) ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+ p2 = s2; \
+ p3 = s6; \
+ p1 = (p2+p3) * stbi__f2f(0.5411961f); \
+ t2 = p1 + p3*stbi__f2f(-1.847759065f); \
+ t3 = p1 + p2*stbi__f2f( 0.765366865f); \
+ p2 = s0; \
+ p3 = s4; \
+ t0 = stbi__fsh(p2+p3); \
+ t1 = stbi__fsh(p2-p3); \
+ x0 = t0+t3; \
+ x3 = t0-t3; \
+ x1 = t1+t2; \
+ x2 = t1-t2; \
+ t0 = s7; \
+ t1 = s5; \
+ t2 = s3; \
+ t3 = s1; \
+ p3 = t0+t2; \
+ p4 = t1+t3; \
+ p1 = t0+t3; \
+ p2 = t1+t2; \
+ p5 = (p3+p4)*stbi__f2f( 1.175875602f); \
+ t0 = t0*stbi__f2f( 0.298631336f); \
+ t1 = t1*stbi__f2f( 2.053119869f); \
+ t2 = t2*stbi__f2f( 3.072711026f); \
+ t3 = t3*stbi__f2f( 1.501321110f); \
+ p1 = p5 + p1*stbi__f2f(-0.899976223f); \
+ p2 = p5 + p2*stbi__f2f(-2.562915447f); \
+ p3 = p3*stbi__f2f(-1.961570560f); \
+ p4 = p4*stbi__f2f(-0.390180644f); \
+ t3 += p1+p4; \
+ t2 += p2+p3; \
+ t1 += p2+p4; \
+ t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+ int i,val[64],*v=val;
+ stbi_uc *o;
+ short *d = data;
+
+ // columns
+ for (i=0; i < 8; ++i,++d, ++v) {
+ // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+ if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+ && d[40]==0 && d[48]==0 && d[56]==0) {
+ // no shortcut 0 seconds
+ // (1|2|3|4|5|6|7)==0 0 seconds
+ // all separate -0.047 seconds
+ // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
+ int dcterm = d[0] << 2;
+ v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+ } else {
+ STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+ // constants scaled things up by 1<<12; let's bring them back
+ // down, but keep 2 extra bits of precision
+ x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+ v[ 0] = (x0+t3) >> 10;
+ v[56] = (x0-t3) >> 10;
+ v[ 8] = (x1+t2) >> 10;
+ v[48] = (x1-t2) >> 10;
+ v[16] = (x2+t1) >> 10;
+ v[40] = (x2-t1) >> 10;
+ v[24] = (x3+t0) >> 10;
+ v[32] = (x3-t0) >> 10;
+ }
+ }
+
+ for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+ // no fast case since the first 1D IDCT spread components out
+ STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+ // constants scaled things up by 1<<12, plus we had 1<<2 from first
+ // loop, plus horizontal and vertical each scale by sqrt(8) so together
+ // we've got an extra 1<<3, so 1<<17 total we need to remove.
+ // so we want to round that, which means adding 0.5 * 1<<17,
+ // aka 65536. Also, we'll end up with -128 to 127 that we want
+ // to encode as 0..255 by adding 128, so we'll add that before the shift
+ x0 += 65536 + (128<<17);
+ x1 += 65536 + (128<<17);
+ x2 += 65536 + (128<<17);
+ x3 += 65536 + (128<<17);
+ // tried computing the shifts into temps, or'ing the temps to see
+ // if any were out of range, but that was slower
+ o[0] = stbi__clamp((x0+t3) >> 17);
+ o[7] = stbi__clamp((x0-t3) >> 17);
+ o[1] = stbi__clamp((x1+t2) >> 17);
+ o[6] = stbi__clamp((x1-t2) >> 17);
+ o[2] = stbi__clamp((x2+t1) >> 17);
+ o[5] = stbi__clamp((x2-t1) >> 17);
+ o[3] = stbi__clamp((x3+t0) >> 17);
+ o[4] = stbi__clamp((x3-t0) >> 17);
+ }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ // This is constructed to match our regular (generic) integer IDCT exactly.
+ __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+ __m128i tmp;
+
+ // dot product constant: even elems=x, odd elems=y
+ #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+ // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit)
+ // out(1) = c1[even]*x + c1[odd]*y
+ #define dct_rot(out0,out1, x,y,c0,c1) \
+ __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+ __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+ __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+ __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+ __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+ __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+ // out = in << 12 (in 16-bit, out 32-bit)
+ #define dct_widen(out, in) \
+ __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+ __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+ // wide add
+ #define dct_wadd(out, a, b) \
+ __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+ // wide sub
+ #define dct_wsub(out, a, b) \
+ __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+ // butterfly a/b, add bias, then shift by "s" and pack
+ #define dct_bfly32o(out0, out1, a,b,bias,s) \
+ { \
+ __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+ __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+ dct_wadd(sum, abiased, b); \
+ dct_wsub(dif, abiased, b); \
+ out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+ out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+ }
+
+ // 8-bit interleave step (for transposes)
+ #define dct_interleave8(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi8(a, b); \
+ b = _mm_unpackhi_epi8(tmp, b)
+
+ // 16-bit interleave step (for transposes)
+ #define dct_interleave16(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi16(a, b); \
+ b = _mm_unpackhi_epi16(tmp, b)
+
+ #define dct_pass(bias,shift) \
+ { \
+ /* even part */ \
+ dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+ __m128i sum04 = _mm_add_epi16(row0, row4); \
+ __m128i dif04 = _mm_sub_epi16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+ dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+ __m128i sum17 = _mm_add_epi16(row1, row7); \
+ __m128i sum35 = _mm_add_epi16(row3, row5); \
+ dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+ dct_wadd(x4, y0o, y4o); \
+ dct_wadd(x5, y1o, y5o); \
+ dct_wadd(x6, y2o, y5o); \
+ dct_wadd(x7, y3o, y4o); \
+ dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+ dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+ dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+ dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+ }
+
+ __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+ __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+ __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+ __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+ __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+ __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+ __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+ __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+ // rounding biases in column/row passes, see stbi__idct_block for explanation.
+ __m128i bias_0 = _mm_set1_epi32(512);
+ __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+ // load
+ row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+ row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+ row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+ row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+ row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+ row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+ row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+ row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+ // column pass
+ dct_pass(bias_0, 10);
+
+ {
+ // 16bit 8x8 transpose pass 1
+ dct_interleave16(row0, row4);
+ dct_interleave16(row1, row5);
+ dct_interleave16(row2, row6);
+ dct_interleave16(row3, row7);
+
+ // transpose pass 2
+ dct_interleave16(row0, row2);
+ dct_interleave16(row1, row3);
+ dct_interleave16(row4, row6);
+ dct_interleave16(row5, row7);
+
+ // transpose pass 3
+ dct_interleave16(row0, row1);
+ dct_interleave16(row2, row3);
+ dct_interleave16(row4, row5);
+ dct_interleave16(row6, row7);
+ }
+
+ // row pass
+ dct_pass(bias_1, 17);
+
+ {
+ // pack
+ __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+ __m128i p1 = _mm_packus_epi16(row2, row3);
+ __m128i p2 = _mm_packus_epi16(row4, row5);
+ __m128i p3 = _mm_packus_epi16(row6, row7);
+
+ // 8bit 8x8 transpose pass 1
+ dct_interleave8(p0, p2); // a0e0a1e1...
+ dct_interleave8(p1, p3); // c0g0c1g1...
+
+ // transpose pass 2
+ dct_interleave8(p0, p1); // a0c0e0g0...
+ dct_interleave8(p2, p3); // b0d0f0h0...
+
+ // transpose pass 3
+ dct_interleave8(p0, p2); // a0b0c0d0...
+ dct_interleave8(p1, p3); // a4b4c4d4...
+
+ // store
+ _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+ }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+ int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+ int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+ int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+ int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+ int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+ int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+ int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+ int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+ int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+ int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+ int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+ int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+ int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+ int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+ int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+ int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+ int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+ int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+ { \
+ dct_wadd(sum, a, b); \
+ dct_wsub(dif, a, b); \
+ out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+ out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+ }
+
+#define dct_pass(shiftop, shift) \
+ { \
+ /* even part */ \
+ int16x8_t sum26 = vaddq_s16(row2, row6); \
+ dct_long_mul(p1e, sum26, rot0_0); \
+ dct_long_mac(t2e, p1e, row6, rot0_1); \
+ dct_long_mac(t3e, p1e, row2, rot0_2); \
+ int16x8_t sum04 = vaddq_s16(row0, row4); \
+ int16x8_t dif04 = vsubq_s16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ int16x8_t sum15 = vaddq_s16(row1, row5); \
+ int16x8_t sum17 = vaddq_s16(row1, row7); \
+ int16x8_t sum35 = vaddq_s16(row3, row5); \
+ int16x8_t sum37 = vaddq_s16(row3, row7); \
+ int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+ dct_long_mul(p5o, sumodd, rot1_0); \
+ dct_long_mac(p1o, p5o, sum17, rot1_1); \
+ dct_long_mac(p2o, p5o, sum35, rot1_2); \
+ dct_long_mul(p3o, sum37, rot2_0); \
+ dct_long_mul(p4o, sum15, rot2_1); \
+ dct_wadd(sump13o, p1o, p3o); \
+ dct_wadd(sump24o, p2o, p4o); \
+ dct_wadd(sump23o, p2o, p3o); \
+ dct_wadd(sump14o, p1o, p4o); \
+ dct_long_mac(x4, sump13o, row7, rot3_0); \
+ dct_long_mac(x5, sump24o, row5, rot3_1); \
+ dct_long_mac(x6, sump23o, row3, rot3_2); \
+ dct_long_mac(x7, sump14o, row1, rot3_3); \
+ dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+ dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+ dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+ dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+ }
+
+ // load
+ row0 = vld1q_s16(data + 0*8);
+ row1 = vld1q_s16(data + 1*8);
+ row2 = vld1q_s16(data + 2*8);
+ row3 = vld1q_s16(data + 3*8);
+ row4 = vld1q_s16(data + 4*8);
+ row5 = vld1q_s16(data + 5*8);
+ row6 = vld1q_s16(data + 6*8);
+ row7 = vld1q_s16(data + 7*8);
+
+ // add DC bias
+ row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+ // column pass
+ dct_pass(vrshrn_n_s32, 10);
+
+ // 16bit 8x8 transpose
+ {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+ // pass 1
+ dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+ dct_trn16(row2, row3);
+ dct_trn16(row4, row5);
+ dct_trn16(row6, row7);
+
+ // pass 2
+ dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+ dct_trn32(row1, row3);
+ dct_trn32(row4, row6);
+ dct_trn32(row5, row7);
+
+ // pass 3
+ dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+ dct_trn64(row1, row5);
+ dct_trn64(row2, row6);
+ dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+ }
+
+ // row pass
+ // vrshrn_n_s32 only supports shifts up to 16, we need
+ // 17. so do a non-rounding shift of 16 first then follow
+ // up with a rounding shift by 1.
+ dct_pass(vshrn_n_s32, 16);
+
+ {
+ // pack and round
+ uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+ uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+ uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+ uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+ uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+ uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+ uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+ uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+ // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+ // sadly can't use interleaved stores here since we only write
+ // 8 bytes to each scan line!
+
+ // 8x8 8-bit transpose pass 1
+ dct_trn8_8(p0, p1);
+ dct_trn8_8(p2, p3);
+ dct_trn8_8(p4, p5);
+ dct_trn8_8(p6, p7);
+
+ // pass 2
+ dct_trn8_16(p0, p2);
+ dct_trn8_16(p1, p3);
+ dct_trn8_16(p4, p6);
+ dct_trn8_16(p5, p7);
+
+ // pass 3
+ dct_trn8_32(p0, p4);
+ dct_trn8_32(p1, p5);
+ dct_trn8_32(p2, p6);
+ dct_trn8_32(p3, p7);
+
+ // store
+ vst1_u8(out, p0); out += out_stride;
+ vst1_u8(out, p1); out += out_stride;
+ vst1_u8(out, p2); out += out_stride;
+ vst1_u8(out, p3); out += out_stride;
+ vst1_u8(out, p4); out += out_stride;
+ vst1_u8(out, p5); out += out_stride;
+ vst1_u8(out, p6); out += out_stride;
+ vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+ }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none 0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+ stbi_uc x;
+ if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+ x = stbi__get8(j->s);
+ if (x != 0xff) return STBI__MARKER_none;
+ while (x == 0xff)
+ x = stbi__get8(j->s); // consume repeated 0xff fill bytes
+ return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+ j->code_bits = 0;
+ j->code_buffer = 0;
+ j->nomore = 0;
+ j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
+ j->marker = STBI__MARKER_none;
+ j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+ j->eob_run = 0;
+ // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+ // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+ stbi__jpeg_reset(z);
+ if (!z->progressive) {
+ if (z->scan_n == 1) {
+ int i,j;
+ STBI_SIMD_ALIGN(short, data[64]);
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ // if it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ STBI_SIMD_ALIGN(short, data[64]);
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x)*8;
+ int y2 = (j*z->img_comp[n].v + y)*8;
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ } else {
+ if (z->scan_n == 1) {
+ int i,j;
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ if (z->spec_start == 0) {
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ } else {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+ return 0;
+ }
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x);
+ int y2 = (j*z->img_comp[n].v + y);
+ short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
+{
+ int i;
+ for (i=0; i < 64; ++i)
+ data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+ if (z->progressive) {
+ // dequantize and idct the data
+ int i,j,n;
+ for (n=0; n < z->s->img_n; ++n) {
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+ int L;
+ switch (m) {
+ case STBI__MARKER_none: // no marker found
+ return stbi__err("expected marker","Corrupt JPEG");
+
+ case 0xDD: // DRI - specify restart interval
+ if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+ z->restart_interval = stbi__get16be(z->s);
+ return 1;
+
+ case 0xDB: // DQT - define quantization table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ int q = stbi__get8(z->s);
+ int p = q >> 4, sixteen = (p != 0);
+ int t = q & 15,i;
+ if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
+ if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+
+ for (i=0; i < 64; ++i)
+ z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
+ L -= (sixteen ? 129 : 65);
+ }
+ return L==0;
+
+ case 0xC4: // DHT - define huffman table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ stbi_uc *v;
+ int sizes[16],i,n=0;
+ int q = stbi__get8(z->s);
+ int tc = q >> 4;
+ int th = q & 15;
+ if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+ for (i=0; i < 16; ++i) {
+ sizes[i] = stbi__get8(z->s);
+ n += sizes[i];
+ }
+ L -= 17;
+ if (tc == 0) {
+ if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+ v = z->huff_dc[th].values;
+ } else {
+ if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+ v = z->huff_ac[th].values;
+ }
+ for (i=0; i < n; ++i)
+ v[i] = stbi__get8(z->s);
+ if (tc != 0)
+ stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+ L -= n;
+ }
+ return L==0;
+ }
+
+ // check for comment block or APP blocks
+ if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+ L = stbi__get16be(z->s);
+ if (L < 2) {
+ if (m == 0xFE)
+ return stbi__err("bad COM len","Corrupt JPEG");
+ else
+ return stbi__err("bad APP len","Corrupt JPEG");
+ }
+ L -= 2;
+
+ if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
+ static const unsigned char tag[5] = {'J','F','I','F','\0'};
+ int ok = 1;
+ int i;
+ for (i=0; i < 5; ++i)
+ if (stbi__get8(z->s) != tag[i])
+ ok = 0;
+ L -= 5;
+ if (ok)
+ z->jfif = 1;
+ } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
+ static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
+ int ok = 1;
+ int i;
+ for (i=0; i < 6; ++i)
+ if (stbi__get8(z->s) != tag[i])
+ ok = 0;
+ L -= 6;
+ if (ok) {
+ stbi__get8(z->s); // version
+ stbi__get16be(z->s); // flags0
+ stbi__get16be(z->s); // flags1
+ z->app14_color_transform = stbi__get8(z->s); // color transform
+ L -= 6;
+ }
+ }
+
+ stbi__skip(z->s, L);
+ return 1;
+ }
+
+ return stbi__err("unknown marker","Corrupt JPEG");
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+ int i;
+ int Ls = stbi__get16be(z->s);
+ z->scan_n = stbi__get8(z->s);
+ if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+ if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+ for (i=0; i < z->scan_n; ++i) {
+ int id = stbi__get8(z->s), which;
+ int q = stbi__get8(z->s);
+ for (which = 0; which < z->s->img_n; ++which)
+ if (z->img_comp[which].id == id)
+ break;
+ if (which == z->s->img_n) return 0; // no match
+ z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+ z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+ z->order[i] = which;
+ }
+
+ {
+ int aa;
+ z->spec_start = stbi__get8(z->s);
+ z->spec_end = stbi__get8(z->s); // should be 63, but might be 0
+ aa = stbi__get8(z->s);
+ z->succ_high = (aa >> 4);
+ z->succ_low = (aa & 15);
+ if (z->progressive) {
+ if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+ return stbi__err("bad SOS", "Corrupt JPEG");
+ } else {
+ if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ z->spec_end = 63;
+ }
+ }
+
+ return 1;
+}
+
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+ int i;
+ for (i=0; i < ncomp; ++i) {
+ if (z->img_comp[i].raw_data) {
+ STBI_FREE(z->img_comp[i].raw_data);
+ z->img_comp[i].raw_data = NULL;
+ z->img_comp[i].data = NULL;
+ }
+ if (z->img_comp[i].raw_coeff) {
+ STBI_FREE(z->img_comp[i].raw_coeff);
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].coeff = 0;
+ }
+ if (z->img_comp[i].linebuf) {
+ STBI_FREE(z->img_comp[i].linebuf);
+ z->img_comp[i].linebuf = NULL;
+ }
+ }
+ return why;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+ stbi__context *s = z->s;
+ int Lf,p,i,q, h_max=1,v_max=1,c;
+ Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+ p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+ s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+ s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+ c = stbi__get8(s);
+ if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
+ s->img_n = c;
+ for (i=0; i < c; ++i) {
+ z->img_comp[i].data = NULL;
+ z->img_comp[i].linebuf = NULL;
+ }
+
+ if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+ z->rgb = 0;
+ for (i=0; i < s->img_n; ++i) {
+ static unsigned char rgb[3] = { 'R', 'G', 'B' };
+ z->img_comp[i].id = stbi__get8(s);
+ if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
+ ++z->rgb;
+ q = stbi__get8(s);
+ z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+ z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+ z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+ }
+
+ if (scan != STBI__SCAN_load) return 1;
+
+ if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
+
+ for (i=0; i < s->img_n; ++i) {
+ if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+ if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+ }
+
+ // compute interleaved mcu info
+ z->img_h_max = h_max;
+ z->img_v_max = v_max;
+ z->img_mcu_w = h_max * 8;
+ z->img_mcu_h = v_max * 8;
+ // these sizes can't be more than 17 bits
+ z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+ z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+ for (i=0; i < s->img_n; ++i) {
+ // number of effective pixels (e.g. for non-interleaved MCU)
+ z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+ z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+ // to simplify generation, we'll allocate enough memory to decode
+ // the bogus oversized data from using interleaved MCUs and their
+ // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+ // discard the extra data until colorspace conversion
+ //
+ // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+ // so these muls can't overflow with 32-bit ints (which we require)
+ z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+ z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+ z->img_comp[i].coeff = 0;
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].linebuf = NULL;
+ z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+ if (z->img_comp[i].raw_data == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ // align blocks for idct using mmx/sse
+ z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+ if (z->progressive) {
+ // w2, h2 are multiples of 8 (see above)
+ z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+ z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+ z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+ if (z->img_comp[i].raw_coeff == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+ }
+ }
+
+ return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x) ((x) == 0xdc)
+#define stbi__SOI(x) ((x) == 0xd8)
+#define stbi__EOI(x) ((x) == 0xd9)
+#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x) ((x) == 0xda)
+
+#define stbi__SOF_progressive(x) ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+ int m;
+ z->jfif = 0;
+ z->app14_color_transform = -1; // valid values are 0,1,2
+ z->marker = STBI__MARKER_none; // initialize cached marker to empty
+ m = stbi__get_marker(z);
+ if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+ if (scan == STBI__SCAN_type) return 1;
+ m = stbi__get_marker(z);
+ while (!stbi__SOF(m)) {
+ if (!stbi__process_marker(z,m)) return 0;
+ m = stbi__get_marker(z);
+ while (m == STBI__MARKER_none) {
+ // some files have extra padding after their blocks, so ok, we'll scan
+ if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+ m = stbi__get_marker(z);
+ }
+ }
+ z->progressive = stbi__SOF_progressive(m);
+ if (!stbi__process_frame_header(z, scan)) return 0;
+ return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+ int m;
+ for (m = 0; m < 4; m++) {
+ j->img_comp[m].raw_data = NULL;
+ j->img_comp[m].raw_coeff = NULL;
+ }
+ j->restart_interval = 0;
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+ m = stbi__get_marker(j);
+ while (!stbi__EOI(m)) {
+ if (stbi__SOS(m)) {
+ if (!stbi__process_scan_header(j)) return 0;
+ if (!stbi__parse_entropy_coded_data(j)) return 0;
+ if (j->marker == STBI__MARKER_none ) {
+ // handle 0s at the end of image data from IP Kamera 9060
+ while (!stbi__at_eof(j->s)) {
+ int x = stbi__get8(j->s);
+ if (x == 255) {
+ j->marker = stbi__get8(j->s);
+ break;
+ }
+ }
+ // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+ }
+ } else if (stbi__DNL(m)) {
+ int Ld = stbi__get16be(j->s);
+ stbi__uint32 NL = stbi__get16be(j->s);
+ if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG");
+ if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG");
+ } else {
+ if (!stbi__process_marker(j, m)) return 0;
+ }
+ m = stbi__get_marker(j);
+ }
+ if (j->progressive)
+ stbi__jpeg_finish(j);
+ return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+ int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ STBI_NOTUSED(out);
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(w);
+ STBI_NOTUSED(hs);
+ return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples vertically for every one in input
+ int i;
+ STBI_NOTUSED(hs);
+ for (i=0; i < w; ++i)
+ out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+ return out;
+}
+
+static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples horizontally for every one in input
+ int i;
+ stbi_uc *input = in_near;
+
+ if (w == 1) {
+ // if only one sample, can't do any interpolation
+ out[0] = out[1] = input[0];
+ return out;
+ }
+
+ out[0] = input[0];
+ out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+ for (i=1; i < w-1; ++i) {
+ int n = 3*input[i]+2;
+ out[i*2+0] = stbi__div4(n+input[i-1]);
+ out[i*2+1] = stbi__div4(n+input[i+1]);
+ }
+ out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+ out[i*2+1] = input[w-1];
+
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i,t0,t1;
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ out[0] = stbi__div4(t1+2);
+ for (i=1; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i=0,t0,t1;
+
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ // process groups of 8 pixels for as long as we can.
+ // note we can't handle the last pixel in a row in this loop
+ // because we need to handle the filter boundary conditions.
+ for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ __m128i zero = _mm_setzero_si128();
+ __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i));
+ __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+ __m128i farw = _mm_unpacklo_epi8(farb, zero);
+ __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+ __m128i diff = _mm_sub_epi16(farw, nearw);
+ __m128i nears = _mm_slli_epi16(nearw, 2);
+ __m128i curr = _mm_add_epi16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ __m128i prv0 = _mm_slli_si128(curr, 2);
+ __m128i nxt0 = _mm_srli_si128(curr, 2);
+ __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+ __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ __m128i bias = _mm_set1_epi16(8);
+ __m128i curs = _mm_slli_epi16(curr, 2);
+ __m128i prvd = _mm_sub_epi16(prev, curr);
+ __m128i nxtd = _mm_sub_epi16(next, curr);
+ __m128i curb = _mm_add_epi16(curs, bias);
+ __m128i even = _mm_add_epi16(prvd, curb);
+ __m128i odd = _mm_add_epi16(nxtd, curb);
+
+ // interleave even and odd pixels, then undo scaling.
+ __m128i int0 = _mm_unpacklo_epi16(even, odd);
+ __m128i int1 = _mm_unpackhi_epi16(even, odd);
+ __m128i de0 = _mm_srli_epi16(int0, 4);
+ __m128i de1 = _mm_srli_epi16(int1, 4);
+
+ // pack and write output
+ __m128i outv = _mm_packus_epi16(de0, de1);
+ _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ uint8x8_t farb = vld1_u8(in_far + i);
+ uint8x8_t nearb = vld1_u8(in_near + i);
+ int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+ int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+ int16x8_t curr = vaddq_s16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ int16x8_t prv0 = vextq_s16(curr, curr, 7);
+ int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+ int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+ int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ int16x8_t curs = vshlq_n_s16(curr, 2);
+ int16x8_t prvd = vsubq_s16(prev, curr);
+ int16x8_t nxtd = vsubq_s16(next, curr);
+ int16x8_t even = vaddq_s16(curs, prvd);
+ int16x8_t odd = vaddq_s16(curs, nxtd);
+
+ // undo scaling and round, then store with even/odd phases interleaved
+ uint8x8x2_t o;
+ o.val[0] = vqrshrun_n_s16(even, 4);
+ o.val[1] = vqrshrun_n_s16(odd, 4);
+ vst2_u8(out + i*2, o);
+#endif
+
+ // "previous" value for next iter
+ t1 = 3*in_near[i+7] + in_far[i+7];
+ }
+
+ t0 = t1;
+ t1 = 3*in_near[i] + in_far[i];
+ out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+ for (++i; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // resample with nearest-neighbor
+ int i,j;
+ STBI_NOTUSED(in_far);
+ for (i=0; i < w; ++i)
+ for (j=0; j < hs; ++j)
+ out[i*hs+j] = in_near[i];
+ return out;
+}
+
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+ int i;
+ for (i=0; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* stbi__float2fixed(1.40200f);
+ g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* stbi__float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+ int i = 0;
+
+#ifdef STBI_SSE2
+ // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+ // it's useful in practice (you wouldn't use it for textures, for example).
+ // so just accelerate step == 4 case.
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ __m128i signflip = _mm_set1_epi8(-0x80);
+ __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f));
+ __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+ __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+ __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
+ __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+ __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+ for (; i+7 < count; i += 8) {
+ // load
+ __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+ __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+ __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+ __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+ __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+ // unpack to short (and left-shift cr, cb by 8)
+ __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes);
+ __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+ __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+ // color transform
+ __m128i yws = _mm_srli_epi16(yw, 4);
+ __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+ __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+ __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+ __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+ __m128i rws = _mm_add_epi16(cr0, yws);
+ __m128i gwt = _mm_add_epi16(cb0, yws);
+ __m128i bws = _mm_add_epi16(yws, cb1);
+ __m128i gws = _mm_add_epi16(gwt, cr1);
+
+ // descale
+ __m128i rw = _mm_srai_epi16(rws, 4);
+ __m128i bw = _mm_srai_epi16(bws, 4);
+ __m128i gw = _mm_srai_epi16(gws, 4);
+
+ // back to byte, set up for transpose
+ __m128i brb = _mm_packus_epi16(rw, bw);
+ __m128i gxb = _mm_packus_epi16(gw, xw);
+
+ // transpose to interleave channels
+ __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+ __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+ __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+ __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+ // store
+ _mm_storeu_si128((__m128i *) (out + 0), o0);
+ _mm_storeu_si128((__m128i *) (out + 16), o1);
+ out += 32;
+ }
+ }
+#endif
+
+#ifdef STBI_NEON
+ // in this version, step=3 support would be easy to add. but is there demand?
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ uint8x8_t signflip = vdup_n_u8(0x80);
+ int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f));
+ int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+ int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+ int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f));
+
+ for (; i+7 < count; i += 8) {
+ // load
+ uint8x8_t y_bytes = vld1_u8(y + i);
+ uint8x8_t cr_bytes = vld1_u8(pcr + i);
+ uint8x8_t cb_bytes = vld1_u8(pcb + i);
+ int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+ int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+ // expand to s16
+ int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+ int16x8_t crw = vshll_n_s8(cr_biased, 7);
+ int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+ // color transform
+ int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+ int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+ int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+ int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+ int16x8_t rws = vaddq_s16(yws, cr0);
+ int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+ int16x8_t bws = vaddq_s16(yws, cb1);
+
+ // undo scaling, round, convert to byte
+ uint8x8x4_t o;
+ o.val[0] = vqrshrun_n_s16(rws, 4);
+ o.val[1] = vqrshrun_n_s16(gws, 4);
+ o.val[2] = vqrshrun_n_s16(bws, 4);
+ o.val[3] = vdup_n_u8(255);
+
+ // store, interleaving r/g/b/a
+ vst4_u8(out, o);
+ out += 8*4;
+ }
+ }
+#endif
+
+ for (; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* stbi__float2fixed(1.40200f);
+ g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* stbi__float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+ j->idct_block_kernel = stbi__idct_block;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+ if (stbi__sse2_available()) {
+ j->idct_block_kernel = stbi__idct_simd;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+ }
+#endif
+
+#ifdef STBI_NEON
+ j->idct_block_kernel = stbi__idct_simd;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+ stbi__free_jpeg_components(j, j->s->img_n, 0);
+}
+
+typedef struct
+{
+ resample_row_func resample;
+ stbi_uc *line0,*line1;
+ int hs,vs; // expansion factor in each axis
+ int w_lores; // horizontal pixels pre-expansion
+ int ystep; // how far through vertical expansion we are
+ int ypos; // which pre-expansion row we're on
+} stbi__resample;
+
+// fast 0..255 * 0..255 => 0..255 rounded multiplication
+static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
+{
+ unsigned int t = x*y + 128;
+ return (stbi_uc) ((t + (t >>8)) >> 8);
+}
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+ int n, decode_n, is_rgb;
+ z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+ // validate req_comp
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+ // load a jpeg image from whichever source, but leave in YCbCr format
+ if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+ // determine actual number of components to generate
+ n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
+
+ is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
+
+ if (z->s->img_n == 3 && n < 3 && !is_rgb)
+ decode_n = 1;
+ else
+ decode_n = z->s->img_n;
+
+ // resample and color-convert
+ {
+ int k;
+ unsigned int i,j;
+ stbi_uc *output;
+ stbi_uc *coutput[4];
+
+ stbi__resample res_comp[4];
+
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+
+ // allocate line buffer big enough for upsampling off the edges
+ // with upsample factor of 4
+ z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+ if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ r->hs = z->img_h_max / z->img_comp[k].h;
+ r->vs = z->img_v_max / z->img_comp[k].v;
+ r->ystep = r->vs >> 1;
+ r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+ r->ypos = 0;
+ r->line0 = r->line1 = z->img_comp[k].data;
+
+ if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+ else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+ else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+ else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+ else r->resample = stbi__resample_row_generic;
+ }
+
+ // can't error after this so, this is safe
+ output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
+ if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ // now go ahead and resample
+ for (j=0; j < z->s->img_y; ++j) {
+ stbi_uc *out = output + n * z->s->img_x * j;
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+ int y_bot = r->ystep >= (r->vs >> 1);
+ coutput[k] = r->resample(z->img_comp[k].linebuf,
+ y_bot ? r->line1 : r->line0,
+ y_bot ? r->line0 : r->line1,
+ r->w_lores, r->hs);
+ if (++r->ystep >= r->vs) {
+ r->ystep = 0;
+ r->line0 = r->line1;
+ if (++r->ypos < z->img_comp[k].y)
+ r->line1 += z->img_comp[k].w2;
+ }
+ }
+ if (n >= 3) {
+ stbi_uc *y = coutput[0];
+ if (z->s->img_n == 3) {
+ if (is_rgb) {
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = y[i];
+ out[1] = coutput[1][i];
+ out[2] = coutput[2][i];
+ out[3] = 255;
+ out += n;
+ }
+ } else {
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ }
+ } else if (z->s->img_n == 4) {
+ if (z->app14_color_transform == 0) { // CMYK
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(coutput[0][i], m);
+ out[1] = stbi__blinn_8x8(coutput[1][i], m);
+ out[2] = stbi__blinn_8x8(coutput[2][i], m);
+ out[3] = 255;
+ out += n;
+ }
+ } else if (z->app14_color_transform == 2) { // YCCK
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(255 - out[0], m);
+ out[1] = stbi__blinn_8x8(255 - out[1], m);
+ out[2] = stbi__blinn_8x8(255 - out[2], m);
+ out += n;
+ }
+ } else { // YCbCr + alpha? Ignore the fourth channel for now
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ }
+ } else
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = out[1] = out[2] = y[i];
+ out[3] = 255; // not used if n==3
+ out += n;
+ }
+ } else {
+ if (is_rgb) {
+ if (n == 1)
+ for (i=0; i < z->s->img_x; ++i)
+ *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+ else {
+ for (i=0; i < z->s->img_x; ++i, out += 2) {
+ out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+ out[1] = 255;
+ }
+ }
+ } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
+ stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
+ stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
+ out[0] = stbi__compute_y(r, g, b);
+ out[1] = 255;
+ out += n;
+ }
+ } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
+ out[1] = 255;
+ out += n;
+ }
+ } else {
+ stbi_uc *y = coutput[0];
+ if (n == 1)
+ for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+ else
+ for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+ }
+ }
+ }
+ stbi__cleanup_jpeg(z);
+ *out_x = z->s->img_x;
+ *out_y = z->s->img_y;
+ if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
+ return output;
+ }
+}
+
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ unsigned char* result;
+ stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+ STBI_NOTUSED(ri);
+ j->s = s;
+ stbi__setup_jpeg(j);
+ result = load_jpeg_image(j, x,y,comp,req_comp);
+ STBI_FREE(j);
+ return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+ int r;
+ stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
+ j->s = s;
+ stbi__setup_jpeg(j);
+ r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
+ stbi__rewind(s);
+ STBI_FREE(j);
+ return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+ stbi__rewind( j->s );
+ return 0;
+ }
+ if (x) *x = j->s->img_x;
+ if (y) *y = j->s->img_y;
+ if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
+ return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int result;
+ stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+ j->s = s;
+ result = stbi__jpeg_info_raw(j, x, y, comp);
+ STBI_FREE(j);
+ return result;
+}
+#endif
+
+// public domain zlib decode v0.2 Sean Barrett 2006-11-18
+// simple implementation
+// - all input must be provided in an upfront buffer
+// - all output is written to a single output buffer (can malloc/realloc)
+// performance
+// - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+ stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+ stbi__uint16 firstcode[16];
+ int maxcode[17];
+ stbi__uint16 firstsymbol[16];
+ stbi_uc size[288];
+ stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+ n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
+ n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
+ n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
+ n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
+ return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+ STBI_ASSERT(bits <= 16);
+ // to bit reverse n bits, reverse 16 and shift
+ // e.g. 11 bits, bit reverse and shift away 5
+ return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
+{
+ int i,k=0;
+ int code, next_code[16], sizes[17];
+
+ // DEFLATE spec for generating codes
+ memset(sizes, 0, sizeof(sizes));
+ memset(z->fast, 0, sizeof(z->fast));
+ for (i=0; i < num; ++i)
+ ++sizes[sizelist[i]];
+ sizes[0] = 0;
+ for (i=1; i < 16; ++i)
+ if (sizes[i] > (1 << i))
+ return stbi__err("bad sizes", "Corrupt PNG");
+ code = 0;
+ for (i=1; i < 16; ++i) {
+ next_code[i] = code;
+ z->firstcode[i] = (stbi__uint16) code;
+ z->firstsymbol[i] = (stbi__uint16) k;
+ code = (code + sizes[i]);
+ if (sizes[i])
+ if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+ z->maxcode[i] = code << (16-i); // preshift for inner loop
+ code <<= 1;
+ k += sizes[i];
+ }
+ z->maxcode[16] = 0x10000; // sentinel
+ for (i=0; i < num; ++i) {
+ int s = sizelist[i];
+ if (s) {
+ int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+ stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+ z->size [c] = (stbi_uc ) s;
+ z->value[c] = (stbi__uint16) i;
+ if (s <= STBI__ZFAST_BITS) {
+ int j = stbi__bit_reverse(next_code[s],s);
+ while (j < (1 << STBI__ZFAST_BITS)) {
+ z->fast[j] = fastv;
+ j += (1 << s);
+ }
+ }
+ ++next_code[s];
+ }
+ }
+ return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+// because PNG allows splitting the zlib stream arbitrarily,
+// and it's annoying structurally to have PNG call ZLIB call PNG,
+// we require PNG read all the IDATs and combine them into a single
+// memory buffer
+
+typedef struct
+{
+ stbi_uc *zbuffer, *zbuffer_end;
+ int num_bits;
+ stbi__uint32 code_buffer;
+
+ char *zout;
+ char *zout_start;
+ char *zout_end;
+ int z_expandable;
+
+ stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+ if (z->zbuffer >= z->zbuffer_end) return 0;
+ return *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+ do {
+ STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
+ z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+ z->num_bits += 8;
+ } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+ unsigned int k;
+ if (z->num_bits < n) stbi__fill_bits(z);
+ k = z->code_buffer & ((1 << n) - 1);
+ z->code_buffer >>= n;
+ z->num_bits -= n;
+ return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s,k;
+ // not resolved by fast table, so compute it the slow way
+ // use jpeg approach, which requires MSbits at top
+ k = stbi__bit_reverse(a->code_buffer, 16);
+ for (s=STBI__ZFAST_BITS+1; ; ++s)
+ if (k < z->maxcode[s])
+ break;
+ if (s == 16) return -1; // invalid code!
+ // code size is s, so:
+ b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+ STBI_ASSERT(z->size[b] == s);
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s;
+ if (a->num_bits < 16) stbi__fill_bits(a);
+ b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+ if (b) {
+ s = b >> 9;
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return b & 511;
+ }
+ return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
+{
+ char *q;
+ int cur, limit, old_limit;
+ z->zout = zout;
+ if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+ cur = (int) (z->zout - z->zout_start);
+ limit = old_limit = (int) (z->zout_end - z->zout_start);
+ while (cur + n > limit)
+ limit *= 2;
+ q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+ STBI_NOTUSED(old_limit);
+ if (q == NULL) return stbi__err("outofmem", "Out of memory");
+ z->zout_start = q;
+ z->zout = q + cur;
+ z->zout_end = q + limit;
+ return 1;
+}
+
+static int stbi__zlength_base[31] = {
+ 3,4,5,6,7,8,9,10,11,13,
+ 15,17,19,23,27,31,35,43,51,59,
+ 67,83,99,115,131,163,195,227,258,0,0 };
+
+static int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+ char *zout = a->zout;
+ for(;;) {
+ int z = stbi__zhuffman_decode(a, &a->z_length);
+ if (z < 256) {
+ if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+ if (zout >= a->zout_end) {
+ if (!stbi__zexpand(a, zout, 1)) return 0;
+ zout = a->zout;
+ }
+ *zout++ = (char) z;
+ } else {
+ stbi_uc *p;
+ int len,dist;
+ if (z == 256) {
+ a->zout = zout;
+ return 1;
+ }
+ z -= 257;
+ len = stbi__zlength_base[z];
+ if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+ z = stbi__zhuffman_decode(a, &a->z_distance);
+ if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+ dist = stbi__zdist_base[z];
+ if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+ if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+ if (zout + len > a->zout_end) {
+ if (!stbi__zexpand(a, zout, len)) return 0;
+ zout = a->zout;
+ }
+ p = (stbi_uc *) (zout - dist);
+ if (dist == 1) { // run of one byte; common in images.
+ stbi_uc v = *p;
+ if (len) { do *zout++ = v; while (--len); }
+ } else {
+ if (len) { do *zout++ = *p++; while (--len); }
+ }
+ }
+ }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+ static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ stbi__zhuffman z_codelength;
+ stbi_uc lencodes[286+32+137];//padding for maximum single op
+ stbi_uc codelength_sizes[19];
+ int i,n;
+
+ int hlit = stbi__zreceive(a,5) + 257;
+ int hdist = stbi__zreceive(a,5) + 1;
+ int hclen = stbi__zreceive(a,4) + 4;
+ int ntot = hlit + hdist;
+
+ memset(codelength_sizes, 0, sizeof(codelength_sizes));
+ for (i=0; i < hclen; ++i) {
+ int s = stbi__zreceive(a,3);
+ codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+ }
+ if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+ n = 0;
+ while (n < ntot) {
+ int c = stbi__zhuffman_decode(a, &z_codelength);
+ if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+ if (c < 16)
+ lencodes[n++] = (stbi_uc) c;
+ else {
+ stbi_uc fill = 0;
+ if (c == 16) {
+ c = stbi__zreceive(a,2)+3;
+ if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+ fill = lencodes[n-1];
+ } else if (c == 17)
+ c = stbi__zreceive(a,3)+3;
+ else {
+ STBI_ASSERT(c == 18);
+ c = stbi__zreceive(a,7)+11;
+ }
+ if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+ memset(lencodes+n, fill, c);
+ n += c;
+ }
+ }
+ if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
+ if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+ return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+ stbi_uc header[4];
+ int len,nlen,k;
+ if (a->num_bits & 7)
+ stbi__zreceive(a, a->num_bits & 7); // discard
+ // drain the bit-packed data into header
+ k = 0;
+ while (a->num_bits > 0) {
+ header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+ a->code_buffer >>= 8;
+ a->num_bits -= 8;
+ }
+ STBI_ASSERT(a->num_bits == 0);
+ // now fill header the normal way
+ while (k < 4)
+ header[k++] = stbi__zget8(a);
+ len = header[1] * 256 + header[0];
+ nlen = header[3] * 256 + header[2];
+ if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+ if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+ if (a->zout + len > a->zout_end)
+ if (!stbi__zexpand(a, a->zout, len)) return 0;
+ memcpy(a->zout, a->zbuffer, len);
+ a->zbuffer += len;
+ a->zout += len;
+ return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+ int cmf = stbi__zget8(a);
+ int cm = cmf & 15;
+ /* int cinfo = cmf >> 4; */
+ int flg = stbi__zget8(a);
+ if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+ if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+ if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+ // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+ return 1;
+}
+
+static const stbi_uc stbi__zdefault_length[288] =
+{
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
+};
+static const stbi_uc stbi__zdefault_distance[32] =
+{
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
+};
+/*
+Init algorithm:
+{
+ int i; // use <= to match clearly with spec
+ for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
+ for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9;
+ for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7;
+ for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8;
+
+ for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
+}
+*/
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+ int final, type;
+ if (parse_header)
+ if (!stbi__parse_zlib_header(a)) return 0;
+ a->num_bits = 0;
+ a->code_buffer = 0;
+ do {
+ final = stbi__zreceive(a,1);
+ type = stbi__zreceive(a,2);
+ if (type == 0) {
+ if (!stbi__parse_uncompressed_block(a)) return 0;
+ } else if (type == 3) {
+ return 0;
+ } else {
+ if (type == 1) {
+ // use fixed code lengths
+ if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
+ } else {
+ if (!stbi__compute_huffman_codes(a)) return 0;
+ }
+ if (!stbi__parse_huffman_block(a)) return 0;
+ }
+ } while (!final);
+ return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+ a->zout_start = obuf;
+ a->zout = obuf;
+ a->zout_end = obuf + olen;
+ a->z_expandable = exp;
+
+ return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+ return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(16384);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer+len;
+ if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18
+// simple implementation
+// - only 8-bit samples
+// - no CRC checking
+// - allocates lots of intermediate memory
+// - avoids problem of streaming data between subsystems
+// - avoids explicit window management
+// performance
+// - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+ stbi__uint32 length;
+ stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+ stbi__pngchunk c;
+ c.length = stbi__get32be(s);
+ c.type = stbi__get32be(s);
+ return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+ static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+ int i;
+ for (i=0; i < 8; ++i)
+ if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+ return 1;
+}
+
+typedef struct
+{
+ stbi__context *s;
+ stbi_uc *idata, *expanded, *out;
+ int depth;
+} stbi__png;
+
+
+enum {
+ STBI__F_none=0,
+ STBI__F_sub=1,
+ STBI__F_up=2,
+ STBI__F_avg=3,
+ STBI__F_paeth=4,
+ // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+ STBI__F_avg_first,
+ STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+ STBI__F_none,
+ STBI__F_sub,
+ STBI__F_none,
+ STBI__F_avg_first,
+ STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+ int p = a + b - c;
+ int pa = abs(p-a);
+ int pb = abs(p-b);
+ int pc = abs(p-c);
+ if (pa <= pb && pa <= pc) return a;
+ if (pb <= pc) return b;
+ return c;
+}
+
+static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+ int bytes = (depth == 16? 2 : 1);
+ stbi__context *s = a->s;
+ stbi__uint32 i,j,stride = x*out_n*bytes;
+ stbi__uint32 img_len, img_width_bytes;
+ int k;
+ int img_n = s->img_n; // copy it into a local for later
+
+ int output_bytes = out_n*bytes;
+ int filter_bytes = img_n*bytes;
+ int width = x;
+
+ STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+ a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
+ if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+ img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+ img_len = (img_width_bytes + 1) * y;
+ // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
+ // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
+ // so just check for raw_len < img_len always.
+ if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+
+ for (j=0; j < y; ++j) {
+ stbi_uc *cur = a->out + stride*j;
+ stbi_uc *prior;
+ int filter = *raw++;
+
+ if (filter > 4)
+ return stbi__err("invalid filter","Corrupt PNG");
+
+ if (depth < 8) {
+ STBI_ASSERT(img_width_bytes <= x);
+ cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+ filter_bytes = 1;
+ width = img_width_bytes;
+ }
+ prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
+
+ // if first row, use special filter that doesn't sample previous row
+ if (j == 0) filter = first_row_filter[filter];
+
+ // handle first byte explicitly
+ for (k=0; k < filter_bytes; ++k) {
+ switch (filter) {
+ case STBI__F_none : cur[k] = raw[k]; break;
+ case STBI__F_sub : cur[k] = raw[k]; break;
+ case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+ case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+ case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+ case STBI__F_avg_first : cur[k] = raw[k]; break;
+ case STBI__F_paeth_first: cur[k] = raw[k]; break;
+ }
+ }
+
+ if (depth == 8) {
+ if (img_n != out_n)
+ cur[img_n] = 255; // first pixel
+ raw += img_n;
+ cur += out_n;
+ prior += out_n;
+ } else if (depth == 16) {
+ if (img_n != out_n) {
+ cur[filter_bytes] = 255; // first pixel top byte
+ cur[filter_bytes+1] = 255; // first pixel bottom byte
+ }
+ raw += filter_bytes;
+ cur += output_bytes;
+ prior += output_bytes;
+ } else {
+ raw += 1;
+ cur += 1;
+ prior += 1;
+ }
+
+ // this is a little gross, so that we don't switch per-pixel or per-component
+ if (depth < 8 || img_n == out_n) {
+ int nk = (width - 1)*filter_bytes;
+ #define STBI__CASE(f) \
+ case f: \
+ for (k=0; k < nk; ++k)
+ switch (filter) {
+ // "none" filter turns into a memcpy here; make that explicit.
+ case STBI__F_none: memcpy(cur, raw, nk); break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+ }
+ #undef STBI__CASE
+ raw += nk;
+ } else {
+ STBI_ASSERT(img_n+1 == out_n);
+ #define STBI__CASE(f) \
+ case f: \
+ for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
+ for (k=0; k < filter_bytes; ++k)
+ switch (filter) {
+ STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+ }
+ #undef STBI__CASE
+
+ // the loop above sets the high byte of the pixels' alpha, but for
+ // 16 bit png files we also need the low byte set. we'll do that here.
+ if (depth == 16) {
+ cur = a->out + stride*j; // start at the beginning of the row again
+ for (i=0; i < x; ++i,cur+=output_bytes) {
+ cur[filter_bytes+1] = 255;
+ }
+ }
+ }
+ }
+
+ // we make a separate pass to expand bits to pixels; for performance,
+ // this could run two scanlines behind the above code, so it won't
+ // intefere with filtering but will still be in the cache.
+ if (depth < 8) {
+ for (j=0; j < y; ++j) {
+ stbi_uc *cur = a->out + stride*j;
+ stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
+ // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+ // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+ stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+ // note that the final byte might overshoot and write more data than desired.
+ // we can allocate enough data that this never writes out of memory, but it
+ // could also overwrite the next scanline. can it overwrite non-empty data
+ // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+ // so we need to explicitly clamp the final ones
+
+ if (depth == 4) {
+ for (k=x*img_n; k >= 2; k-=2, ++in) {
+ *cur++ = scale * ((*in >> 4) );
+ *cur++ = scale * ((*in ) & 0x0f);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 4) );
+ } else if (depth == 2) {
+ for (k=x*img_n; k >= 4; k-=4, ++in) {
+ *cur++ = scale * ((*in >> 6) );
+ *cur++ = scale * ((*in >> 4) & 0x03);
+ *cur++ = scale * ((*in >> 2) & 0x03);
+ *cur++ = scale * ((*in ) & 0x03);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 6) );
+ if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+ if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+ } else if (depth == 1) {
+ for (k=x*img_n; k >= 8; k-=8, ++in) {
+ *cur++ = scale * ((*in >> 7) );
+ *cur++ = scale * ((*in >> 6) & 0x01);
+ *cur++ = scale * ((*in >> 5) & 0x01);
+ *cur++ = scale * ((*in >> 4) & 0x01);
+ *cur++ = scale * ((*in >> 3) & 0x01);
+ *cur++ = scale * ((*in >> 2) & 0x01);
+ *cur++ = scale * ((*in >> 1) & 0x01);
+ *cur++ = scale * ((*in ) & 0x01);
+ }
+ if (k > 0) *cur++ = scale * ((*in >> 7) );
+ if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+ if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+ if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+ if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+ if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+ if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+ }
+ if (img_n != out_n) {
+ int q;
+ // insert alpha = 255
+ cur = a->out + stride*j;
+ if (img_n == 1) {
+ for (q=x-1; q >= 0; --q) {
+ cur[q*2+1] = 255;
+ cur[q*2+0] = cur[q];
+ }
+ } else {
+ STBI_ASSERT(img_n == 3);
+ for (q=x-1; q >= 0; --q) {
+ cur[q*4+3] = 255;
+ cur[q*4+2] = cur[q*3+2];
+ cur[q*4+1] = cur[q*3+1];
+ cur[q*4+0] = cur[q*3+0];
+ }
+ }
+ }
+ }
+ } else if (depth == 16) {
+ // force the image data from big-endian to platform-native.
+ // this is done in a separate pass due to the decoding relying
+ // on the data being untouched, but could probably be done
+ // per-line during decode if care is taken.
+ stbi_uc *cur = a->out;
+ stbi__uint16 *cur16 = (stbi__uint16*)cur;
+
+ for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
+ *cur16 = (cur[0] << 8) | cur[1];
+ }
+ }
+
+ return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+ int bytes = (depth == 16 ? 2 : 1);
+ int out_bytes = out_n * bytes;
+ stbi_uc *final;
+ int p;
+ if (!interlaced)
+ return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+ // de-interlacing
+ final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+ for (p=0; p < 7; ++p) {
+ int xorig[] = { 0,4,0,2,0,1,0 };
+ int yorig[] = { 0,0,4,0,2,0,1 };
+ int xspc[] = { 8,8,4,4,2,2,1 };
+ int yspc[] = { 8,8,8,4,4,2,2 };
+ int i,j,x,y;
+ // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+ x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+ y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+ if (x && y) {
+ stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+ if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+ STBI_FREE(final);
+ return 0;
+ }
+ for (j=0; j < y; ++j) {
+ for (i=0; i < x; ++i) {
+ int out_y = j*yspc[p]+yorig[p];
+ int out_x = i*xspc[p]+xorig[p];
+ memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+ a->out + (j*x+i)*out_bytes, out_bytes);
+ }
+ }
+ STBI_FREE(a->out);
+ image_data += img_len;
+ image_data_len -= img_len;
+ }
+ }
+ a->out = final;
+
+ return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 255 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i=0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 255);
+ p += 2;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi__uint16 *p = (stbi__uint16*) z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 65535 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i = 0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 65535);
+ p += 2;
+ }
+ } else {
+ for (i = 0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+ stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+ stbi_uc *p, *temp_out, *orig = a->out;
+
+ p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
+ if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+ // between here and free(out) below, exitting would leak
+ temp_out = p;
+
+ if (pal_img_n == 3) {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p += 3;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p[3] = palette[n+3];
+ p += 4;
+ }
+ }
+ STBI_FREE(a->out);
+ a->out = temp_out;
+
+ STBI_NOTUSED(len);
+
+ return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+ stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+ stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ if (s->img_out_n == 3) { // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 3;
+ }
+ } else {
+ STBI_ASSERT(s->img_out_n == 4);
+ if (stbi__unpremultiply_on_load) {
+ // convert bgr to rgb and unpremultiply
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc a = p[3];
+ stbi_uc t = p[0];
+ if (a) {
+ stbi_uc half = a / 2;
+ p[0] = (p[2] * 255 + half) / a;
+ p[1] = (p[1] * 255 + half) / a;
+ p[2] = ( t * 255 + half) / a;
+ } else {
+ p[0] = p[2];
+ p[2] = t;
+ }
+ p += 4;
+ }
+ } else {
+ // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 4;
+ }
+ }
+ }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+ stbi_uc palette[1024], pal_img_n=0;
+ stbi_uc has_trans=0, tc[3];
+ stbi__uint16 tc16[3];
+ stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+ int first=1,k,interlace=0, color=0, is_iphone=0;
+ stbi__context *s = z->s;
+
+ z->expanded = NULL;
+ z->idata = NULL;
+ z->out = NULL;
+
+ if (!stbi__check_png_header(s)) return 0;
+
+ if (scan == STBI__SCAN_type) return 1;
+
+ for (;;) {
+ stbi__pngchunk c = stbi__get_chunk_header(s);
+ switch (c.type) {
+ case STBI__PNG_TYPE('C','g','B','I'):
+ is_iphone = 1;
+ stbi__skip(s, c.length);
+ break;
+ case STBI__PNG_TYPE('I','H','D','R'): {
+ int comp,filter;
+ if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+ first = 0;
+ if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+ s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+ s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+ z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+ color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+ comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
+ filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
+ interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+ if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+ if (!pal_img_n) {
+ s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+ if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+ if (scan == STBI__SCAN_header) return 1;
+ } else {
+ // if paletted, then pal_n is our final components, and
+ // img_n is # components to decompress/filter.
+ s->img_n = 1;
+ if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+ // if SCAN_header, have to scan to see if we have a tRNS
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('P','L','T','E'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+ pal_len = c.length / 3;
+ if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+ for (i=0; i < pal_len; ++i) {
+ palette[i*4+0] = stbi__get8(s);
+ palette[i*4+1] = stbi__get8(s);
+ palette[i*4+2] = stbi__get8(s);
+ palette[i*4+3] = 255;
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('t','R','N','S'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+ if (pal_img_n) {
+ if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+ if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+ if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+ pal_img_n = 4;
+ for (i=0; i < c.length; ++i)
+ palette[i*4+3] = stbi__get8(s);
+ } else {
+ if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+ if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+ has_trans = 1;
+ if (z->depth == 16) {
+ for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
+ } else {
+ for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+ }
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','D','A','T'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+ if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+ if ((int)(ioff + c.length) < (int)ioff) return 0;
+ if (ioff + c.length > idata_limit) {
+ stbi__uint32 idata_limit_old = idata_limit;
+ stbi_uc *p;
+ if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+ while (ioff + c.length > idata_limit)
+ idata_limit *= 2;
+ STBI_NOTUSED(idata_limit_old);
+ p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+ z->idata = p;
+ }
+ if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+ ioff += c.length;
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','E','N','D'): {
+ stbi__uint32 raw_len, bpl;
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (scan != STBI__SCAN_load) return 1;
+ if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+ // initial guess for decoded data size to avoid unnecessary reallocs
+ bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+ raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+ z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+ if (z->expanded == NULL) return 0; // zlib should set error
+ STBI_FREE(z->idata); z->idata = NULL;
+ if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+ s->img_out_n = s->img_n+1;
+ else
+ s->img_out_n = s->img_n;
+ if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+ if (has_trans) {
+ if (z->depth == 16) {
+ if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+ } else {
+ if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+ }
+ }
+ if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+ stbi__de_iphone(z);
+ if (pal_img_n) {
+ // pal_img_n == 3 or 4
+ s->img_n = pal_img_n; // record the actual colors we had
+ s->img_out_n = pal_img_n;
+ if (req_comp >= 3) s->img_out_n = req_comp;
+ if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+ return 0;
+ } else if (has_trans) {
+ // non-paletted image with tRNS -> source image has (constant) alpha
+ ++s->img_n;
+ }
+ STBI_FREE(z->expanded); z->expanded = NULL;
+ return 1;
+ }
+
+ default:
+ // if critical, fail
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if ((c.type & (1 << 29)) == 0) {
+ #ifndef STBI_NO_FAILURE_STRINGS
+ // not threadsafe
+ static char invalid_chunk[] = "XXXX PNG chunk not known";
+ invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+ invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+ invalid_chunk[2] = STBI__BYTECAST(c.type >> 8);
+ invalid_chunk[3] = STBI__BYTECAST(c.type >> 0);
+ #endif
+ return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+ }
+ stbi__skip(s, c.length);
+ break;
+ }
+ // end of PNG chunk, read and skip CRC
+ stbi__get32be(s);
+ }
+}
+
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+{
+ void *result=NULL;
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+ if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+ if (p->depth < 8)
+ ri->bits_per_channel = 8;
+ else
+ ri->bits_per_channel = p->depth;
+ result = p->out;
+ p->out = NULL;
+ if (req_comp && req_comp != p->s->img_out_n) {
+ if (ri->bits_per_channel == 8)
+ result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ else
+ result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ p->s->img_out_n = req_comp;
+ if (result == NULL) return result;
+ }
+ *x = p->s->img_x;
+ *y = p->s->img_y;
+ if (n) *n = p->s->img_n;
+ }
+ STBI_FREE(p->out); p->out = NULL;
+ STBI_FREE(p->expanded); p->expanded = NULL;
+ STBI_FREE(p->idata); p->idata = NULL;
+
+ return result;
+}
+
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__do_png(&p, x,y,comp,req_comp, ri);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+ int r;
+ r = stbi__check_png_header(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+ if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+ stbi__rewind( p->s );
+ return 0;
+ }
+ if (x) *x = p->s->img_x;
+ if (y) *y = p->s->img_y;
+ if (comp) *comp = p->s->img_n;
+ return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__png_info_raw(&p, x, y, comp);
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+ int r;
+ int sz;
+ if (stbi__get8(s) != 'B') return 0;
+ if (stbi__get8(s) != 'M') return 0;
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ stbi__get32le(s); // discard data offset
+ sz = stbi__get32le(s);
+ r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+ return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+ int r = stbi__bmp_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+ int n=0;
+ if (z == 0) return -1;
+ if (z >= 0x10000) n += 16, z >>= 16;
+ if (z >= 0x00100) n += 8, z >>= 8;
+ if (z >= 0x00010) n += 4, z >>= 4;
+ if (z >= 0x00004) n += 2, z >>= 2;
+ if (z >= 0x00002) n += 1, z >>= 1;
+ return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+ a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2
+ a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4
+ a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+ a = (a + (a >> 8)); // max 16 per 8 bits
+ a = (a + (a >> 16)); // max 32 per 8 bits
+ return a & 0xff;
+}
+
+static int stbi__shiftsigned(int v, int shift, int bits)
+{
+ int result;
+ int z=0;
+
+ if (shift < 0) v <<= -shift;
+ else v >>= shift;
+ result = v;
+
+ z = bits;
+ while (z < 8) {
+ result += v >> z;
+ z += bits;
+ }
+ return result;
+}
+
+typedef struct
+{
+ int bpp, offset, hsz;
+ unsigned int mr,mg,mb,ma, all_a;
+} stbi__bmp_data;
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+ int hsz;
+ if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ info->offset = stbi__get32le(s);
+ info->hsz = hsz = stbi__get32le(s);
+ info->mr = info->mg = info->mb = info->ma = 0;
+
+ if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+ if (hsz == 12) {
+ s->img_x = stbi__get16le(s);
+ s->img_y = stbi__get16le(s);
+ } else {
+ s->img_x = stbi__get32le(s);
+ s->img_y = stbi__get32le(s);
+ }
+ if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+ info->bpp = stbi__get16le(s);
+ if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
+ if (hsz != 12) {
+ int compress = stbi__get32le(s);
+ if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+ stbi__get32le(s); // discard sizeof
+ stbi__get32le(s); // discard hres
+ stbi__get32le(s); // discard vres
+ stbi__get32le(s); // discard colorsused
+ stbi__get32le(s); // discard max important
+ if (hsz == 40 || hsz == 56) {
+ if (hsz == 56) {
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ }
+ if (info->bpp == 16 || info->bpp == 32) {
+ if (compress == 0) {
+ if (info->bpp == 32) {
+ info->mr = 0xffu << 16;
+ info->mg = 0xffu << 8;
+ info->mb = 0xffu << 0;
+ info->ma = 0xffu << 24;
+ info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+ } else {
+ info->mr = 31u << 10;
+ info->mg = 31u << 5;
+ info->mb = 31u << 0;
+ }
+ } else if (compress == 3) {
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ // not documented, but generated by photoshop and handled by mspaint
+ if (info->mr == info->mg && info->mg == info->mb) {
+ // ?!?!?
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else {
+ int i;
+ if (hsz != 108 && hsz != 124)
+ return stbi__errpuc("bad BMP", "bad BMP");
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ info->ma = stbi__get32le(s);
+ stbi__get32le(s); // discard color space
+ for (i=0; i < 12; ++i)
+ stbi__get32le(s); // discard color space parameters
+ if (hsz == 124) {
+ stbi__get32le(s); // discard rendering intent
+ stbi__get32le(s); // discard offset of profile data
+ stbi__get32le(s); // discard size of profile data
+ stbi__get32le(s); // discard reserved
+ }
+ }
+ }
+ return (void *) 1;
+}
+
+
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+ stbi_uc pal[256][4];
+ int psize=0,i,j,width;
+ int flip_vertically, pad, target;
+ stbi__bmp_data info;
+ STBI_NOTUSED(ri);
+
+ info.all_a = 255;
+ if (stbi__bmp_parse_header(s, &info) == NULL)
+ return NULL; // error code already set
+
+ flip_vertically = ((int) s->img_y) > 0;
+ s->img_y = abs((int) s->img_y);
+
+ mr = info.mr;
+ mg = info.mg;
+ mb = info.mb;
+ ma = info.ma;
+ all_a = info.all_a;
+
+ if (info.hsz == 12) {
+ if (info.bpp < 24)
+ psize = (info.offset - 14 - 24) / 3;
+ } else {
+ if (info.bpp < 16)
+ psize = (info.offset - 14 - info.hsz) >> 2;
+ }
+
+ s->img_n = ma ? 4 : 3;
+ if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+ target = req_comp;
+ else
+ target = s->img_n; // if they want monochrome, we'll post-convert
+
+ // sanity-check size
+ if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "Corrupt BMP");
+
+ out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ if (info.bpp < 16) {
+ int z=0;
+ if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+ for (i=0; i < psize; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ if (info.hsz != 12) stbi__get8(s);
+ pal[i][3] = 255;
+ }
+ stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+ if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+ else if (info.bpp == 8) width = s->img_x;
+ else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+ pad = (-width)&3;
+ for (j=0; j < (int) s->img_y; ++j) {
+ for (i=0; i < (int) s->img_x; i += 2) {
+ int v=stbi__get8(s),v2=0;
+ if (info.bpp == 4) {
+ v2 = v & 15;
+ v >>= 4;
+ }
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ v = (info.bpp == 8) ? stbi__get8(s) : v2;
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ }
+ stbi__skip(s, pad);
+ }
+ } else {
+ int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+ int z = 0;
+ int easy=0;
+ stbi__skip(s, info.offset - 14 - info.hsz);
+ if (info.bpp == 24) width = 3 * s->img_x;
+ else if (info.bpp == 16) width = 2*s->img_x;
+ else /* bpp = 32 and pad = 0 */ width=0;
+ pad = (-width) & 3;
+ if (info.bpp == 24) {
+ easy = 1;
+ } else if (info.bpp == 32) {
+ if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+ easy = 2;
+ }
+ if (!easy) {
+ if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+ // right shift amt to put high bit in position #7
+ rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+ gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+ bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+ ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+ }
+ for (j=0; j < (int) s->img_y; ++j) {
+ if (easy) {
+ for (i=0; i < (int) s->img_x; ++i) {
+ unsigned char a;
+ out[z+2] = stbi__get8(s);
+ out[z+1] = stbi__get8(s);
+ out[z+0] = stbi__get8(s);
+ z += 3;
+ a = (easy == 2 ? stbi__get8(s) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = a;
+ }
+ } else {
+ int bpp = info.bpp;
+ for (i=0; i < (int) s->img_x; ++i) {
+ stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+ int a;
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+ a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = STBI__BYTECAST(a);
+ }
+ }
+ stbi__skip(s, pad);
+ }
+ }
+
+ // if alpha channel is all 0s, replace with all 255s
+ if (target == 4 && all_a == 0)
+ for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+ out[i] = 255;
+
+ if (flip_vertically) {
+ stbi_uc t;
+ for (j=0; j < (int) s->img_y>>1; ++j) {
+ stbi_uc *p1 = out + j *s->img_x*target;
+ stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+ for (i=0; i < (int) s->img_x*target; ++i) {
+ t = p1[i], p1[i] = p2[i], p2[i] = t;
+ }
+ }
+ }
+
+ if (req_comp && req_comp != target) {
+ out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ *x = s->img_x;
+ *y = s->img_y;
+ if (comp) *comp = s->img_n;
+ return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+ // only RGB or RGBA (incl. 16bit) or grey allowed
+ if(is_rgb16) *is_rgb16 = 0;
+ switch(bits_per_pixel) {
+ case 8: return STBI_grey;
+ case 16: if(is_grey) return STBI_grey_alpha;
+ // else: fall-through
+ case 15: if(is_rgb16) *is_rgb16 = 1;
+ return STBI_rgb;
+ case 24: // fall-through
+ case 32: return bits_per_pixel/8;
+ default: return 0;
+ }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+ int sz, tga_colormap_type;
+ stbi__get8(s); // discard Offset
+ tga_colormap_type = stbi__get8(s); // colormap type
+ if( tga_colormap_type > 1 ) {
+ stbi__rewind(s);
+ return 0; // only RGB or indexed allowed
+ }
+ tga_image_type = stbi__get8(s); // image type
+ if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+ if (tga_image_type != 1 && tga_image_type != 9) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip image x and y origin
+ tga_colormap_bpp = sz;
+ } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+ if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+ stbi__rewind(s);
+ return 0; // only RGB or grey allowed, +/- RLE
+ }
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ tga_colormap_bpp = 0;
+ }
+ tga_w = stbi__get16le(s);
+ if( tga_w < 1 ) {
+ stbi__rewind(s);
+ return 0; // test width
+ }
+ tga_h = stbi__get16le(s);
+ if( tga_h < 1 ) {
+ stbi__rewind(s);
+ return 0; // test height
+ }
+ tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+ stbi__get8(s); // ignore alpha bits
+ if (tga_colormap_bpp != 0) {
+ if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+ // when using a colormap, tga_bits_per_pixel is the size of the indexes
+ // I don't think anything but 8 or 16bit indexes makes sense
+ stbi__rewind(s);
+ return 0;
+ }
+ tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+ } else {
+ tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+ }
+ if(!tga_comp) {
+ stbi__rewind(s);
+ return 0;
+ }
+ if (x) *x = tga_w;
+ if (y) *y = tga_h;
+ if (comp) *comp = tga_comp;
+ return 1; // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+ int res = 0;
+ int sz, tga_color_type;
+ stbi__get8(s); // discard Offset
+ tga_color_type = stbi__get8(s); // color type
+ if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
+ sz = stbi__get8(s); // image type
+ if ( tga_color_type == 1 ) { // colormapped (paletted) image
+ if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+ stbi__skip(s,4); // skip image x and y origin
+ } else { // "normal" image w/o colormap
+ if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ }
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height
+ sz = stbi__get8(s); // bits per pixel
+ if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+ res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+ stbi__rewind(s);
+ return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+ stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
+ stbi__uint16 fiveBitMask = 31;
+ // we have 3 channels with 5bits each
+ int r = (px >> 10) & fiveBitMask;
+ int g = (px >> 5) & fiveBitMask;
+ int b = px & fiveBitMask;
+ // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+ out[0] = (stbi_uc)((r * 255)/31);
+ out[1] = (stbi_uc)((g * 255)/31);
+ out[2] = (stbi_uc)((b * 255)/31);
+
+ // some people claim that the most significant bit might be used for alpha
+ // (possibly if an alpha-bit is set in the "image descriptor byte")
+ // but that only made 16bit test images completely translucent..
+ // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ // read in the TGA header stuff
+ int tga_offset = stbi__get8(s);
+ int tga_indexed = stbi__get8(s);
+ int tga_image_type = stbi__get8(s);
+ int tga_is_RLE = 0;
+ int tga_palette_start = stbi__get16le(s);
+ int tga_palette_len = stbi__get16le(s);
+ int tga_palette_bits = stbi__get8(s);
+ int tga_x_origin = stbi__get16le(s);
+ int tga_y_origin = stbi__get16le(s);
+ int tga_width = stbi__get16le(s);
+ int tga_height = stbi__get16le(s);
+ int tga_bits_per_pixel = stbi__get8(s);
+ int tga_comp, tga_rgb16=0;
+ int tga_inverted = stbi__get8(s);
+ // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+ // image data
+ unsigned char *tga_data;
+ unsigned char *tga_palette = NULL;
+ int i, j;
+ unsigned char raw_data[4] = {0};
+ int RLE_count = 0;
+ int RLE_repeating = 0;
+ int read_next_pixel = 1;
+ STBI_NOTUSED(ri);
+
+ // do a tiny bit of precessing
+ if ( tga_image_type >= 8 )
+ {
+ tga_image_type -= 8;
+ tga_is_RLE = 1;
+ }
+ tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+ // If I'm paletted, then I'll use the number of bits from the palette
+ if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+ else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+ if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+ return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+ // tga info
+ *x = tga_width;
+ *y = tga_height;
+ if (comp) *comp = tga_comp;
+
+ if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+ return stbi__errpuc("too large", "Corrupt TGA");
+
+ tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
+ if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+ // skip to the data's starting position (offset usually = 0)
+ stbi__skip(s, tga_offset );
+
+ if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+ for (i=0; i < tga_height; ++i) {
+ int row = tga_inverted ? tga_height -i - 1 : i;
+ stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+ stbi__getn(s, tga_row, tga_width * tga_comp);
+ }
+ } else {
+ // do I need to load a palette?
+ if ( tga_indexed)
+ {
+ // any data to skip? (offset usually = 0)
+ stbi__skip(s, tga_palette_start );
+ // load the palette
+ tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
+ if (!tga_palette) {
+ STBI_FREE(tga_data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+ if (tga_rgb16) {
+ stbi_uc *pal_entry = tga_palette;
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ for (i=0; i < tga_palette_len; ++i) {
+ stbi__tga_read_rgb16(s, pal_entry);
+ pal_entry += tga_comp;
+ }
+ } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+ STBI_FREE(tga_data);
+ STBI_FREE(tga_palette);
+ return stbi__errpuc("bad palette", "Corrupt TGA");
+ }
+ }
+ // load the data
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+ if ( tga_is_RLE )
+ {
+ if ( RLE_count == 0 )
+ {
+ // yep, get the next byte as a RLE command
+ int RLE_cmd = stbi__get8(s);
+ RLE_count = 1 + (RLE_cmd & 127);
+ RLE_repeating = RLE_cmd >> 7;
+ read_next_pixel = 1;
+ } else if ( !RLE_repeating )
+ {
+ read_next_pixel = 1;
+ }
+ } else
+ {
+ read_next_pixel = 1;
+ }
+ // OK, if I need to read a pixel, do it now
+ if ( read_next_pixel )
+ {
+ // load however much data we did have
+ if ( tga_indexed )
+ {
+ // read in index, then perform the lookup
+ int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+ if ( pal_idx >= tga_palette_len ) {
+ // invalid index
+ pal_idx = 0;
+ }
+ pal_idx *= tga_comp;
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = tga_palette[pal_idx+j];
+ }
+ } else if(tga_rgb16) {
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ stbi__tga_read_rgb16(s, raw_data);
+ } else {
+ // read in the data raw
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = stbi__get8(s);
+ }
+ }
+ // clear the reading flag for the next pixel
+ read_next_pixel = 0;
+ } // end of reading a pixel
+
+ // copy data
+ for (j = 0; j < tga_comp; ++j)
+ tga_data[i*tga_comp+j] = raw_data[j];
+
+ // in case we're in RLE mode, keep counting down
+ --RLE_count;
+ }
+ // do I need to invert the image?
+ if ( tga_inverted )
+ {
+ for (j = 0; j*2 < tga_height; ++j)
+ {
+ int index1 = j * tga_width * tga_comp;
+ int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+ for (i = tga_width * tga_comp; i > 0; --i)
+ {
+ unsigned char temp = tga_data[index1];
+ tga_data[index1] = tga_data[index2];
+ tga_data[index2] = temp;
+ ++index1;
+ ++index2;
+ }
+ }
+ }
+ // clear my palette, if I had one
+ if ( tga_palette != NULL )
+ {
+ STBI_FREE( tga_palette );
+ }
+ }
+
+ // swap RGB - if the source data was RGB16, it already is in the right order
+ if (tga_comp >= 3 && !tga_rgb16)
+ {
+ unsigned char* tga_pixel = tga_data;
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ unsigned char temp = tga_pixel[0];
+ tga_pixel[0] = tga_pixel[2];
+ tga_pixel[2] = temp;
+ tga_pixel += tga_comp;
+ }
+ }
+
+ // convert to target component count
+ if (req_comp && req_comp != tga_comp)
+ tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+ // the things I do to get rid of an error message, and yet keep
+ // Microsoft's C compilers happy... [8^(
+ tga_palette_start = tga_palette_len = tga_palette_bits =
+ tga_x_origin = tga_y_origin = 0;
+ // OK, done
+ return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+ int r = (stbi__get32be(s) == 0x38425053);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
+{
+ int count, nleft, len;
+
+ count = 0;
+ while ((nleft = pixelCount - count) > 0) {
+ len = stbi__get8(s);
+ if (len == 128) {
+ // No-op.
+ } else if (len < 128) {
+ // Copy next len+1 bytes literally.
+ len++;
+ if (len > nleft) return 0; // corrupt data
+ count += len;
+ while (len) {
+ *p = stbi__get8(s);
+ p += 4;
+ len--;
+ }
+ } else if (len > 128) {
+ stbi_uc val;
+ // Next -len+1 bytes in the dest are replicated from next source byte.
+ // (Interpret len as a negative 8-bit int.)
+ len = 257 - len;
+ if (len > nleft) return 0; // corrupt data
+ val = stbi__get8(s);
+ count += len;
+ while (len) {
+ *p = val;
+ p += 4;
+ len--;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ int pixelCount;
+ int channelCount, compression;
+ int channel, i;
+ int bitdepth;
+ int w,h;
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ if (stbi__get32be(s) != 0x38425053) // "8BPS"
+ return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+ // Check file type version.
+ if (stbi__get16be(s) != 1)
+ return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+ // Skip 6 reserved bytes.
+ stbi__skip(s, 6 );
+
+ // Read the number of channels (R, G, B, A, etc).
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16)
+ return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+ // Read the rows and columns of the image.
+ h = stbi__get32be(s);
+ w = stbi__get32be(s);
+
+ // Make sure the depth is 8 bits.
+ bitdepth = stbi__get16be(s);
+ if (bitdepth != 8 && bitdepth != 16)
+ return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+ // Make sure the color mode is RGB.
+ // Valid options are:
+ // 0: Bitmap
+ // 1: Grayscale
+ // 2: Indexed color
+ // 3: RGB color
+ // 4: CMYK color
+ // 7: Multichannel
+ // 8: Duotone
+ // 9: Lab color
+ if (stbi__get16be(s) != 3)
+ return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+ // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.)
+ stbi__skip(s,stbi__get32be(s) );
+
+ // Skip the image resources. (resolution, pen tool paths, etc)
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Skip the reserved data.
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Find out if the data is compressed.
+ // Known values:
+ // 0: no compression
+ // 1: RLE compressed
+ compression = stbi__get16be(s);
+ if (compression > 1)
+ return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+ // Check size
+ if (!stbi__mad3sizes_valid(4, w, h, 0))
+ return stbi__errpuc("too large", "Corrupt PSD");
+
+ // Create the destination image.
+
+ if (!compression && bitdepth == 16 && bpc == 16) {
+ out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+ ri->bits_per_channel = 16;
+ } else
+ out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ pixelCount = w*h;
+
+ // Initialize the data to zero.
+ //memset( out, 0, pixelCount * 4 );
+
+ // Finally, the image data.
+ if (compression) {
+ // RLE as used by .PSD and .TIFF
+ // Loop until you get the number of unpacked bytes you are expecting:
+ // Read the next source byte into n.
+ // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+ // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+ // Else if n is 128, noop.
+ // Endloop
+
+ // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+ // which we're going to just skip.
+ stbi__skip(s, h * channelCount * 2 );
+
+ // Read the RLE data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ stbi_uc *p;
+
+ p = out+channel;
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (channel == 3 ? 255 : 0);
+ } else {
+ // Read the RLE data.
+ if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+ STBI_FREE(out);
+ return stbi__errpuc("corrupt", "bad RLE data");
+ }
+ }
+ }
+
+ } else {
+ // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
+ // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
+
+ // Read the data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ if (bitdepth == 16 && bpc == 16) {
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ stbi__uint16 val = channel == 3 ? 65535 : 0;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = val;
+ } else {
+ stbi_uc *p = out+channel;
+ stbi_uc val = channel == 3 ? 255 : 0;
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = val;
+ }
+ } else {
+ if (ri->bits_per_channel == 16) { // output bpc
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = (stbi__uint16) stbi__get16be(s);
+ } else {
+ stbi_uc *p = out+channel;
+ if (bitdepth == 16) { // input bpc
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (stbi_uc) (stbi__get16be(s) >> 8);
+ } else {
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = stbi__get8(s);
+ }
+ }
+ }
+ }
+ }
+
+ // remove weird white matte from PSD
+ if (channelCount >= 4) {
+ if (ri->bits_per_channel == 16) {
+ for (i=0; i < w*h; ++i) {
+ stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 65535) {
+ float a = pixel[3] / 65535.0f;
+ float ra = 1.0f / a;
+ float inv_a = 65535.0f * (1 - ra);
+ pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+ pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+ pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+ }
+ }
+ } else {
+ for (i=0; i < w*h; ++i) {
+ unsigned char *pixel = out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 255) {
+ float a = pixel[3] / 255.0f;
+ float ra = 1.0f / a;
+ float inv_a = 255.0f * (1 - ra);
+ pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+ pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+ pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+ }
+ }
+ }
+ }
+
+ // convert to desired output format
+ if (req_comp && req_comp != 4) {
+ if (ri->bits_per_channel == 16)
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+ else
+ out = stbi__convert_format(out, 4, req_comp, w, h);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ if (comp) *comp = 4;
+ *y = h;
+ *x = w;
+
+ return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+ int i;
+ for (i=0; i<4; ++i)
+ if (stbi__get8(s) != (stbi_uc)str[i])
+ return 0;
+
+ return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+ int i;
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+ return 0;
+
+ for(i=0;i<84;++i)
+ stbi__get8(s);
+
+ if (!stbi__pic_is4(s,"PICT"))
+ return 0;
+
+ return 1;
+}
+
+typedef struct
+{
+ stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+ int mask=0x80, i;
+
+ for (i=0; i<4; ++i, mask>>=1) {
+ if (channel & mask) {
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+ dest[i]=stbi__get8(s);
+ }
+ }
+
+ return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+ int mask=0x80,i;
+
+ for (i=0;i<4; ++i, mask>>=1)
+ if (channel&mask)
+ dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+ int act_comp=0,num_packets=0,y,chained;
+ stbi__pic_packet packets[10];
+
+ // this will (should...) cater for even some bizarre stuff like having data
+ // for the same channel in multiple packets.
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return stbi__errpuc("bad format","too many packets");
+
+ packet = &packets[num_packets++];
+
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)");
+ if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp");
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+ for(y=0; y<height; ++y) {
+ int packet_idx;
+
+ for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+ stbi__pic_packet *packet = &packets[packet_idx];
+ stbi_uc *dest = result+y*width*4;
+
+ switch (packet->type) {
+ default:
+ return stbi__errpuc("bad format","packet has bad compression type");
+
+ case 0: {//uncompressed
+ int x;
+
+ for(x=0;x<width;++x, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ break;
+ }
+
+ case 1://Pure RLE
+ {
+ int left=width, i;
+
+ while (left>0) {
+ stbi_uc count,value[4];
+
+ count=stbi__get8(s);
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)");
+
+ if (count > left)
+ count = (stbi_uc) left;
+
+ if (!stbi__readval(s,packet->channel,value)) return 0;
+
+ for(i=0; i<count; ++i,dest+=4)
+ stbi__copyval(packet->channel,dest,value);
+ left -= count;
+ }
+ }
+ break;
+
+ case 2: {//Mixed RLE
+ int left=width;
+ while (left>0) {
+ int count = stbi__get8(s), i;
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)");
+
+ if (count >= 128) { // Repeated
+ stbi_uc value[4];
+
+ if (count==128)
+ count = stbi__get16be(s);
+ else
+ count -= 127;
+ if (count > left)
+ return stbi__errpuc("bad file","scanline overrun");
+
+ if (!stbi__readval(s,packet->channel,value))
+ return 0;
+
+ for(i=0;i<count;++i, dest += 4)
+ stbi__copyval(packet->channel,dest,value);
+ } else { // Raw
+ ++count;
+ if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+ for(i=0;i<count;++i, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ }
+ left-=count;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *result;
+ int i, x,y, internal_comp;
+ STBI_NOTUSED(ri);
+
+ if (!comp) comp = &internal_comp;
+
+ for (i=0; i<92; ++i)
+ stbi__get8(s);
+
+ x = stbi__get16be(s);
+ y = stbi__get16be(s);
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
+ if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
+
+ stbi__get32be(s); //skip `ratio'
+ stbi__get16be(s); //skip `fields'
+ stbi__get16be(s); //skip `pad'
+
+ // intermediate buffer is RGBA
+ result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+ memset(result, 0xff, x*y*4);
+
+ if (!stbi__pic_load_core(s,x,y,comp, result)) {
+ STBI_FREE(result);
+ result=0;
+ }
+ *px = x;
+ *py = y;
+ if (req_comp == 0) req_comp = *comp;
+ result=stbi__convert_format(result,4,req_comp,x,y);
+
+ return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+ int r = stbi__pic_test_core(s);
+ stbi__rewind(s);
+ return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+ stbi__int16 prefix;
+ stbi_uc first;
+ stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+ int w,h;
+ stbi_uc *out, *old_out; // output buffer (always 4 components)
+ int flags, bgindex, ratio, transparent, eflags, delay;
+ stbi_uc pal[256][4];
+ stbi_uc lpal[256][4];
+ stbi__gif_lzw codes[4096];
+ stbi_uc *color_table;
+ int parse, step;
+ int lflags;
+ int start_x, start_y;
+ int max_x, max_y;
+ int cur_x, cur_y;
+ int line_size;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+ int sz;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+ sz = stbi__get8(s);
+ if (sz != '9' && sz != '7') return 0;
+ if (stbi__get8(s) != 'a') return 0;
+ return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+ int r = stbi__gif_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+ int i;
+ for (i=0; i < num_entries; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ pal[i][3] = transp == i ? 0 : 255;
+ }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+ stbi_uc version;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+ return stbi__err("not GIF", "Corrupt GIF");
+
+ version = stbi__get8(s);
+ if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF");
+ if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF");
+
+ stbi__g_failure_reason = "";
+ g->w = stbi__get16le(s);
+ g->h = stbi__get16le(s);
+ g->flags = stbi__get8(s);
+ g->bgindex = stbi__get8(s);
+ g->ratio = stbi__get8(s);
+ g->transparent = -1;
+
+ if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments
+
+ if (is_info) return 1;
+
+ if (g->flags & 0x80)
+ stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+ return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+ if (!stbi__gif_header(s, g, comp, 1)) {
+ STBI_FREE(g);
+ stbi__rewind( s );
+ return 0;
+ }
+ if (x) *x = g->w;
+ if (y) *y = g->h;
+ STBI_FREE(g);
+ return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+ stbi_uc *p, *c;
+
+ // recurse to decode the prefixes, since the linked-list is backwards,
+ // and working backwards through an interleaved image would be nasty
+ if (g->codes[code].prefix >= 0)
+ stbi__out_gif_code(g, g->codes[code].prefix);
+
+ if (g->cur_y >= g->max_y) return;
+
+ p = &g->out[g->cur_x + g->cur_y];
+ c = &g->color_table[g->codes[code].suffix * 4];
+
+ if (c[3] >= 128) {
+ p[0] = c[2];
+ p[1] = c[1];
+ p[2] = c[0];
+ p[3] = c[3];
+ }
+ g->cur_x += 4;
+
+ if (g->cur_x >= g->max_x) {
+ g->cur_x = g->start_x;
+ g->cur_y += g->step;
+
+ while (g->cur_y >= g->max_y && g->parse > 0) {
+ g->step = (1 << g->parse) * g->line_size;
+ g->cur_y = g->start_y + (g->step >> 1);
+ --g->parse;
+ }
+ }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+ stbi_uc lzw_cs;
+ stbi__int32 len, init_code;
+ stbi__uint32 first;
+ stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+ stbi__gif_lzw *p;
+
+ lzw_cs = stbi__get8(s);
+ if (lzw_cs > 12) return NULL;
+ clear = 1 << lzw_cs;
+ first = 1;
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ bits = 0;
+ valid_bits = 0;
+ for (init_code = 0; init_code < clear; init_code++) {
+ g->codes[init_code].prefix = -1;
+ g->codes[init_code].first = (stbi_uc) init_code;
+ g->codes[init_code].suffix = (stbi_uc) init_code;
+ }
+
+ // support no starting clear code
+ avail = clear+2;
+ oldcode = -1;
+
+ len = 0;
+ for(;;) {
+ if (valid_bits < codesize) {
+ if (len == 0) {
+ len = stbi__get8(s); // start new block
+ if (len == 0)
+ return g->out;
+ }
+ --len;
+ bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+ valid_bits += 8;
+ } else {
+ stbi__int32 code = bits & codemask;
+ bits >>= codesize;
+ valid_bits -= codesize;
+ // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+ if (code == clear) { // clear code
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ avail = clear + 2;
+ oldcode = -1;
+ first = 0;
+ } else if (code == clear + 1) { // end of stream code
+ stbi__skip(s, len);
+ while ((len = stbi__get8(s)) > 0)
+ stbi__skip(s,len);
+ return g->out;
+ } else if (code <= avail) {
+ if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
+
+ if (oldcode >= 0) {
+ p = &g->codes[avail++];
+ if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF");
+ p->prefix = (stbi__int16) oldcode;
+ p->first = g->codes[oldcode].first;
+ p->suffix = (code == avail) ? p->first : g->codes[code].first;
+ } else if (code == avail)
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+ stbi__out_gif_code(g, (stbi__uint16) code);
+
+ if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+ codesize++;
+ codemask = (1 << codesize) - 1;
+ }
+
+ oldcode = code;
+ } else {
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+ }
+ }
+ }
+}
+
+static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
+{
+ int x, y;
+ stbi_uc *c = g->pal[g->bgindex];
+ for (y = y0; y < y1; y += 4 * g->w) {
+ for (x = x0; x < x1; x += 4) {
+ stbi_uc *p = &g->out[y + x];
+ p[0] = c[2];
+ p[1] = c[1];
+ p[2] = c[0];
+ p[3] = 0;
+ }
+ }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
+{
+ int i;
+ stbi_uc *prev_out = 0;
+
+ if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
+ return 0; // stbi__g_failure_reason set by stbi__gif_header
+
+ if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
+ return stbi__errpuc("too large", "GIF too large");
+
+ prev_out = g->out;
+ g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
+ if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
+
+ switch ((g->eflags & 0x1C) >> 2) {
+ case 0: // unspecified (also always used on 1st frame)
+ stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
+ break;
+ case 1: // do not dispose
+ if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+ g->old_out = prev_out;
+ break;
+ case 2: // dispose to background
+ if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+ stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
+ break;
+ case 3: // dispose to previous
+ if (g->old_out) {
+ for (i = g->start_y; i < g->max_y; i += 4 * g->w)
+ memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
+ }
+ break;
+ }
+
+ for (;;) {
+ switch (stbi__get8(s)) {
+ case 0x2C: /* Image Descriptor */
+ {
+ int prev_trans = -1;
+ stbi__int32 x, y, w, h;
+ stbi_uc *o;
+
+ x = stbi__get16le(s);
+ y = stbi__get16le(s);
+ w = stbi__get16le(s);
+ h = stbi__get16le(s);
+ if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+ return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+ g->line_size = g->w * 4;
+ g->start_x = x * 4;
+ g->start_y = y * g->line_size;
+ g->max_x = g->start_x + w * 4;
+ g->max_y = g->start_y + h * g->line_size;
+ g->cur_x = g->start_x;
+ g->cur_y = g->start_y;
+
+ g->lflags = stbi__get8(s);
+
+ if (g->lflags & 0x40) {
+ g->step = 8 * g->line_size; // first interlaced spacing
+ g->parse = 3;
+ } else {
+ g->step = g->line_size;
+ g->parse = 0;
+ }
+
+ if (g->lflags & 0x80) {
+ stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+ g->color_table = (stbi_uc *) g->lpal;
+ } else if (g->flags & 0x80) {
+ if (g->transparent >= 0 && (g->eflags & 0x01)) {
+ prev_trans = g->pal[g->transparent][3];
+ g->pal[g->transparent][3] = 0;
+ }
+ g->color_table = (stbi_uc *) g->pal;
+ } else
+ return stbi__errpuc("missing color table", "Corrupt GIF");
+
+ o = stbi__process_gif_raster(s, g);
+ if (o == NULL) return NULL;
+
+ if (prev_trans != -1)
+ g->pal[g->transparent][3] = (stbi_uc) prev_trans;
+
+ return o;
+ }
+
+ case 0x21: // Comment Extension.
+ {
+ int len;
+ if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
+ len = stbi__get8(s);
+ if (len == 4) {
+ g->eflags = stbi__get8(s);
+ g->delay = stbi__get16le(s);
+ g->transparent = stbi__get8(s);
+ } else {
+ stbi__skip(s, len);
+ break;
+ }
+ }
+ while ((len = stbi__get8(s)) != 0)
+ stbi__skip(s, len);
+ break;
+ }
+
+ case 0x3B: // gif stream termination code
+ return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+ default:
+ return stbi__errpuc("unknown code", "Corrupt GIF");
+ }
+ }
+
+ STBI_NOTUSED(req_comp);
+}
+
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *u = 0;
+ stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+ memset(g, 0, sizeof(*g));
+ STBI_NOTUSED(ri);
+
+ u = stbi__gif_load_next(s, g, comp, req_comp);
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
+ if (u) {
+ *x = g->w;
+ *y = g->h;
+ if (req_comp && req_comp != 4)
+ u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
+ }
+ else if (g->out)
+ STBI_FREE(g->out);
+ STBI_FREE(g);
+ return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
+{
+ int i;
+ for (i=0; signature[i]; ++i)
+ if (stbi__get8(s) != signature[i])
+ return 0;
+ stbi__rewind(s);
+ return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+ int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
+ stbi__rewind(s);
+ if(!r) {
+ r = stbi__hdr_test_core(s, "#?RGBE\n");
+ stbi__rewind(s);
+ }
+ return r;
+}
+
+#define STBI__HDR_BUFLEN 1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+ int len=0;
+ char c = '\0';
+
+ c = (char) stbi__get8(z);
+
+ while (!stbi__at_eof(z) && c != '\n') {
+ buffer[len++] = c;
+ if (len == STBI__HDR_BUFLEN-1) {
+ // flush to end of line
+ while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+ ;
+ break;
+ }
+ c = (char) stbi__get8(z);
+ }
+
+ buffer[len] = 0;
+ return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+ if ( input[3] != 0 ) {
+ float f1;
+ // Exponent
+ f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+ if (req_comp <= 2)
+ output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+ else {
+ output[0] = input[0] * f1;
+ output[1] = input[1] * f1;
+ output[2] = input[2] * f1;
+ }
+ if (req_comp == 2) output[1] = 1;
+ if (req_comp == 4) output[3] = 1;
+ } else {
+ switch (req_comp) {
+ case 4: output[3] = 1; /* fallthrough */
+ case 3: output[0] = output[1] = output[2] = 0;
+ break;
+ case 2: output[1] = 1; /* fallthrough */
+ case 1: output[0] = 0;
+ break;
+ }
+ }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+ int width, height;
+ stbi_uc *scanline;
+ float *hdr_data;
+ int len;
+ unsigned char count, value;
+ int i, j, k, c1,c2, z;
+ const char *headerToken;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ headerToken = stbi__hdr_gettoken(s,buffer);
+ if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
+ return stbi__errpf("not HDR", "Corrupt HDR image");
+
+ // Parse header
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+ // Parse width and height
+ // can't use sscanf() if we're not using stdio!
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ height = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ width = (int) strtol(token, NULL, 10);
+
+ *x = width;
+ *y = height;
+
+ if (comp) *comp = 3;
+ if (req_comp == 0) req_comp = 3;
+
+ if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+ return stbi__errpf("too large", "HDR image is too large");
+
+ // Read data
+ hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+ if (!hdr_data)
+ return stbi__errpf("outofmem", "Out of memory");
+
+ // Load image data
+ // image data is stored as some number of sca
+ if ( width < 8 || width >= 32768) {
+ // Read flat data
+ for (j=0; j < height; ++j) {
+ for (i=0; i < width; ++i) {
+ stbi_uc rgbe[4];
+ main_decode_loop:
+ stbi__getn(s, rgbe, 4);
+ stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+ }
+ }
+ } else {
+ // Read RLE-encoded data
+ scanline = NULL;
+
+ for (j = 0; j < height; ++j) {
+ c1 = stbi__get8(s);
+ c2 = stbi__get8(s);
+ len = stbi__get8(s);
+ if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+ // not run-length encoded, so we have to actually use THIS data as a decoded
+ // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+ stbi_uc rgbe[4];
+ rgbe[0] = (stbi_uc) c1;
+ rgbe[1] = (stbi_uc) c2;
+ rgbe[2] = (stbi_uc) len;
+ rgbe[3] = (stbi_uc) stbi__get8(s);
+ stbi__hdr_convert(hdr_data, rgbe, req_comp);
+ i = 1;
+ j = 0;
+ STBI_FREE(scanline);
+ goto main_decode_loop; // yes, this makes no sense
+ }
+ len <<= 8;
+ len |= stbi__get8(s);
+ if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+ if (scanline == NULL) {
+ scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+ if (!scanline) {
+ STBI_FREE(hdr_data);
+ return stbi__errpf("outofmem", "Out of memory");
+ }
+ }
+
+ for (k = 0; k < 4; ++k) {
+ int nleft;
+ i = 0;
+ while ((nleft = width - i) > 0) {
+ count = stbi__get8(s);
+ if (count > 128) {
+ // Run
+ value = stbi__get8(s);
+ count -= 128;
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = value;
+ } else {
+ // Dump
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = stbi__get8(s);
+ }
+ }
+ }
+ for (i=0; i < width; ++i)
+ stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+ }
+ if (scanline)
+ STBI_FREE(scanline);
+ }
+
+ return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+ int dummy;
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ if (stbi__hdr_test(s) == 0) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *y = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *x = (int) strtol(token, NULL, 10);
+ *comp = 3;
+ return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ void *p;
+ stbi__bmp_data info;
+
+ info.all_a = 255;
+ p = stbi__bmp_parse_header(s, &info);
+ stbi__rewind( s );
+ if (p == NULL)
+ return 0;
+ if (x) *x = s->img_x;
+ if (y) *y = s->img_y;
+ if (comp) *comp = info.ma ? 4 : 3;
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int channelCount, dummy;
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+ if (stbi__get32be(s) != 0x38425053) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 1) {
+ stbi__rewind( s );
+ return 0;
+ }
+ stbi__skip(s, 6);
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *y = stbi__get32be(s);
+ *x = stbi__get32be(s);
+ if (stbi__get16be(s) != 8) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 3) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *comp = 4;
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int act_comp=0,num_packets=0,chained,dummy;
+ stbi__pic_packet packets[10];
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+ stbi__rewind(s);
+ return 0;
+ }
+
+ stbi__skip(s, 88);
+
+ *x = stbi__get16be(s);
+ *y = stbi__get16be(s);
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s);
+ return 0;
+ }
+ if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ stbi__skip(s, 8);
+
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return 0;
+
+ packet = &packets[num_packets++];
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (packet->size != 8) {
+ stbi__rewind( s );
+ return 0;
+ }
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3);
+
+ return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+// Does not support comments in the header section
+// Does not support ASCII image data (formats P2 and P3)
+// Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int stbi__pnm_test(stbi__context *s)
+{
+ char p, t;
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind( s );
+ return 0;
+ }
+ return 1;
+}
+
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+ return 0;
+
+ *x = s->img_x;
+ *y = s->img_y;
+ if (comp) *comp = s->img_n;
+
+ if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "PNM too large");
+
+ out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+ if (req_comp && req_comp != s->img_n) {
+ out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+ return out;
+}
+
+static int stbi__pnm_isspace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+ for (;;) {
+ while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+ *c = (char) stbi__get8(s);
+
+ if (stbi__at_eof(s) || *c != '#')
+ break;
+
+ while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+ *c = (char) stbi__get8(s);
+ }
+}
+
+static int stbi__pnm_isdigit(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static int stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+ int value = 0;
+
+ while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+ value = value*10 + (*c - '0');
+ *c = (char) stbi__get8(s);
+ }
+
+ return value;
+}
+
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int maxv, dummy;
+ char c, p, t;
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ stbi__rewind(s);
+
+ // Get identifier
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind(s);
+ return 0;
+ }
+
+ *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+ c = (char) stbi__get8(s);
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *x = stbi__pnm_getinteger(s, &c); // read width
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *y = stbi__pnm_getinteger(s, &c); // read height
+ stbi__pnm_skip_whitespace(s, &c);
+
+ maxv = stbi__pnm_getinteger(s, &c); // read max value
+
+ if (maxv > 255)
+ return stbi__err("max value > 255", "PPM image not 8-bit");
+ else
+ return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNG
+ if (stbi__png_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_info(s, x, y, comp)) return 1;
+ #endif
+
+ // test tga last because it's a crappy test!
+ #ifndef STBI_NO_TGA
+ if (stbi__tga_info(s, x, y, comp))
+ return 1;
+ #endif
+ return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result;
+ if (!f) return stbi__err("can't fopen", "Unable to open file");
+ result = stbi_info_from_file(f, x, y, comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+ int r;
+ stbi__context s;
+ long pos = ftell(f);
+ stbi__start_file(&s, f);
+ r = stbi__info_main(&s,x,y,comp);
+ fseek(f,pos,SEEK_SET);
+ return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+ revision history:
+ 2.16 (2017-07-23) all functions have 16-bit variants;
+ STBI_NO_STDIO works again;
+ compilation fixes;
+ fix rounding in unpremultiply;
+ optimize vertical flip;
+ disable raw_len validation;
+ documentation fixes
+ 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
+ warning fixes; disable run-time SSE detection on gcc;
+ uniform handling of optional "return" values;
+ thread-safe initialization of zlib tables
+ 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+ 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) allocate large structures on the stack
+ remove white matting for transparent PSD
+ fix reported channel count for PNG & BMP
+ re-enable SSE2 in non-gcc 64-bit
+ support RGB-formatted JPEG
+ read 16-bit PNGs (only as 8-bit)
+ 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+ 2.09 (2016-01-16) allow comments in PNM files
+ 16-bit-per-pixel TGA (not bit-per-component)
+ info() for TGA could break due to .hdr handling
+ info() for BMP to shares code instead of sloppy parse
+ can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+ code cleanup
+ 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+ 2.07 (2015-09-13) fix compiler warnings
+ partial animated GIF support
+ limited 16-bpc PSD support
+ #ifdef unused functions
+ bug with < 92 byte PIC,PNM,HDR,TGA
+ 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
+ 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
+ 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+ 2.03 (2015-04-12) extra corruption checking (mmozeiko)
+ stbi_set_flip_vertically_on_load (nguillemot)
+ fix NEON support; fix mingw support
+ 2.02 (2015-01-19) fix incorrect assert, fix warning
+ 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+ 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+ 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+ progressive JPEG (stb)
+ PGM/PPM support (Ken Miller)
+ STBI_MALLOC,STBI_REALLOC,STBI_FREE
+ GIF bugfix -- seemingly never worked
+ STBI_NO_*, STBI_ONLY_*
+ 1.48 (2014-12-14) fix incorrectly-named assert()
+ 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+ optimize PNG (ryg)
+ fix bug in interlaced PNG with user-specified channel count (stb)
+ 1.46 (2014-08-26)
+ fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+ 1.45 (2014-08-16)
+ fix MSVC-ARM internal compiler error by wrapping malloc
+ 1.44 (2014-08-07)
+ various warning fixes from Ronny Chevalier
+ 1.43 (2014-07-15)
+ fix MSVC-only compiler problem in code changed in 1.42
+ 1.42 (2014-07-09)
+ don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+ fixes to stbi__cleanup_jpeg path
+ added STBI_ASSERT to avoid requiring assert.h
+ 1.41 (2014-06-25)
+ fix search&replace from 1.36 that messed up comments/error messages
+ 1.40 (2014-06-22)
+ fix gcc struct-initialization warning
+ 1.39 (2014-06-15)
+ fix to TGA optimization when req_comp != number of components in TGA;
+ fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+ add support for BMP version 5 (more ignored fields)
+ 1.38 (2014-06-06)
+ suppress MSVC warnings on integer casts truncating values
+ fix accidental rename of 'skip' field of I/O
+ 1.37 (2014-06-04)
+ remove duplicate typedef
+ 1.36 (2014-06-03)
+ convert to header file single-file library
+ if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+ 1.35 (2014-05-27)
+ various warnings
+ fix broken STBI_SIMD path
+ fix bug where stbi_load_from_file no longer left file pointer in correct place
+ fix broken non-easy path for 32-bit BMP (possibly never used)
+ TGA optimization by Arseny Kapoulkine
+ 1.34 (unknown)
+ use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+ 1.33 (2011-07-14)
+ make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+ 1.32 (2011-07-13)
+ support for "info" function for all supported filetypes (SpartanJ)
+ 1.31 (2011-06-20)
+ a few more leak fixes, bug in PNG handling (SpartanJ)
+ 1.30 (2011-06-11)
+ added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+ removed deprecated format-specific test/load functions
+ removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+ error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+ fix inefficiency in decoding 32-bit BMP (David Woo)
+ 1.29 (2010-08-16)
+ various warning fixes from Aurelien Pocheville
+ 1.28 (2010-08-01)
+ fix bug in GIF palette transparency (SpartanJ)
+ 1.27 (2010-08-01)
+ cast-to-stbi_uc to fix warnings
+ 1.26 (2010-07-24)
+ fix bug in file buffering for PNG reported by SpartanJ
+ 1.25 (2010-07-17)
+ refix trans_data warning (Won Chun)
+ 1.24 (2010-07-12)
+ perf improvements reading from files on platforms with lock-heavy fgetc()
+ minor perf improvements for jpeg
+ deprecated type-specific functions so we'll get feedback if they're needed
+ attempt to fix trans_data warning (Won Chun)
+ 1.23 fixed bug in iPhone support
+ 1.22 (2010-07-10)
+ removed image *writing* support
+ stbi_info support from Jetro Lauha
+ GIF support from Jean-Marc Lienher
+ iPhone PNG-extensions from James Brown
+ warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+ 1.21 fix use of 'stbi_uc' in header (reported by jon blow)
+ 1.20 added support for Softimage PIC, by Tom Seddon
+ 1.19 bug in interlaced PNG corruption check (found by ryg)
+ 1.18 (2008-08-02)
+ fix a threading bug (local mutable static)
+ 1.17 support interlaced PNG
+ 1.16 major bugfix - stbi__convert_format converted one too many pixels
+ 1.15 initialize some fields for thread safety
+ 1.14 fix threadsafe conversion bug
+ header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+ 1.13 threadsafe
+ 1.12 const qualifiers in the API
+ 1.11 Support installable IDCT, colorspace conversion routines
+ 1.10 Fixes for 64-bit (don't use "unsigned long")
+ optimized upsampling by Fabian "ryg" Giesen
+ 1.09 Fix format-conversion for PSD code (bad global variables!)
+ 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+ 1.07 attempt to fix C++ warning/errors again
+ 1.06 attempt to fix C++ warning/errors again
+ 1.05 fix TGA loading to return correct *comp and use good luminance calc
+ 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
+ 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+ 1.02 support for (subset of) HDR files, float interface for preferred access to them
+ 1.01 fix bug: possible bug in handling right-side up bmps... not sure
+ fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+ 1.00 interface to zlib that skips zlib header
+ 0.99 correct handling of alpha in palette
+ 0.98 TGA loader by lonesock; dynamically add loaders (untested)
+ 0.97 jpeg errors on too large a file; also catch another malloc failure
+ 0.96 fix detection of invalid v value - particleman@mollyrocket forum
+ 0.95 during header scan, seek to markers in case of padding
+ 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+ 0.93 handle jpegtran output; verbose errors
+ 0.92 read 4,8,16,24,32-bit BMP files of several formats
+ 0.91 output 24-bit Windows 3.0 BMP files
+ 0.90 fix a few more warnings; bump version number to approach 1.0
+ 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
+ 0.60 fix compiling as c++
+ 0.59 fix warnings: merge Dave Moore's -Wall fixes
+ 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
+ 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+ 0.56 fix bug: zlib uncompressed mode len vs. nlen
+ 0.55 fix bug: restart_interval not initialized to 0
+ 0.54 allow NULL for 'int *comp'
+ 0.53 fix bug in png 3->4; speedup png decoding
+ 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+ 0.51 obey req_comp requests, 1-component jpegs return as 1-component,
+ on 'test' only check type, not whether we support this variant
+ 0.50 (2006-11-19)
+ first released version
+*/
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/extlibs/headers/stb_image/stb_image_write.h b/extlibs/headers/stb_image/stb_image_write.h
new file mode 100644
index 0000000..9d553e0
--- /dev/null
+++ b/extlibs/headers/stb_image/stb_image_write.h
@@ -0,0 +1,1458 @@
+/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h
+ writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
+ no warranty implied; use at your own risk
+
+ Before #including,
+
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
+
+ in the file that you want to have the implementation.
+
+ Will probably not work correctly with strict-aliasing optimizations.
+
+ABOUT:
+
+ This header file is a library for writing images to C stdio. It could be
+ adapted to write to memory or a general streaming interface; let me know.
+
+ The PNG output is not optimal; it is 20-50% larger than the file
+ written by a decent optimizing implementation. This library is designed
+ for source code compactness and simplicity, not optimal image file size
+ or run-time performance.
+
+BUILDING:
+
+ You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
+ You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
+ malloc,realloc,free.
+ You can define STBIW_MEMMOVE() to replace memmove()
+
+USAGE:
+
+ There are four functions, one for each image file format:
+
+ int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
+ int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
+ int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
+ int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+ int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data);
+
+ There are also four equivalent functions that use an arbitrary write function. You are
+ expected to open/close your file-equivalent before and after calling these:
+
+ int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
+ int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+ int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
+ int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
+
+ where the callback is:
+ void stbi_write_func(void *context, void *data, int size);
+
+ You can define STBI_WRITE_NO_STDIO to disable the file variant of these
+ functions, so the library will not use stdio.h at all. However, this will
+ also disable HDR writing, because it requires stdio for formatted output.
+
+ Each function returns 0 on failure and non-0 on success.
+
+ The functions create an image file defined by the parameters. The image
+ is a rectangle of pixels stored from left-to-right, top-to-bottom.
+ Each pixel contains 'comp' channels of data stored interleaved with 8-bits
+ per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
+ monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
+ The *data pointer points to the first byte of the top-left-most pixel.
+ For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
+ a row of pixels to the first byte of the next row of pixels.
+
+ PNG creates output files with the same number of components as the input.
+ The BMP format expands Y to RGB in the file format and does not
+ output alpha.
+
+ PNG supports writing rectangles of data even when the bytes storing rows of
+ data are not consecutive in memory (e.g. sub-rectangles of a larger image),
+ by supplying the stride between the beginning of adjacent rows. The other
+ formats do not. (Thus you cannot write a native-format BMP through the BMP
+ writer, both because it is in BGR order and because it may have padding
+ at the end of the line.)
+
+ HDR expects linear float data. Since the format is always 32-bit rgb(e)
+ data, alpha (if provided) is discarded, and for monochrome data it is
+ replicated across all three channels.
+
+ TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
+ data, set the global variable 'stbi_write_tga_with_rle' to 0.
+
+ JPEG does ignore alpha channels in input data; quality is between 1 and 100.
+ Higher quality looks better but results in a bigger image.
+ JPEG baseline (no JPEG progressive).
+
+CREDITS:
+
+ PNG/BMP/TGA
+ Sean Barrett
+ HDR
+ Baldur Karlsson
+ TGA monochrome:
+ Jean-Sebastien Guay
+ misc enhancements:
+ Tim Kelsey
+ TGA RLE
+ Alan Hickman
+ initial file IO callback implementation
+ Emmanuel Julien
+ JPEG
+ Jon Olick (original jo_jpeg.cpp code)
+ Daniel Gibson
+ bugfixes:
+ github:Chribba
+ Guillaume Chereau
+ github:jry2
+ github:romigrou
+ Sergio Gonzalez
+ Jonas Karlsson
+ Filip Wasil
+ Thatcher Ulrich
+ github:poppolopoppo
+ Patrick Boettcher
+
+LICENSE
+
+ See end of file for license information.
+
+*/
+
+#ifndef INCLUDE_STB_IMAGE_WRITE_H
+#define INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_WRITE_STATIC
+#define STBIWDEF static
+#else
+#define STBIWDEF extern
+extern int stbi_write_tga_with_rle;
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
+#endif
+
+typedef void stbi_write_func(void *context, void *data, int size);
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
+STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
+STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
+
+#ifdef _WIN32
+ #ifndef _CRT_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_WARNINGS
+ #endif
+ #ifndef _CRT_NONSTDC_NO_DEPRECATE
+ #define _CRT_NONSTDC_NO_DEPRECATE
+ #endif
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+#include <stdio.h>
+#endif // STBI_WRITE_NO_STDIO
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
+// ok
+#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
+#endif
+
+#ifndef STBIW_MALLOC
+#define STBIW_MALLOC(sz) malloc(sz)
+#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
+#define STBIW_FREE(p) free(p)
+#endif
+
+#ifndef STBIW_REALLOC_SIZED
+#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
+#endif
+
+
+#ifndef STBIW_MEMMOVE
+#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
+#endif
+
+
+#ifndef STBIW_ASSERT
+#include <assert.h>
+#define STBIW_ASSERT(x) assert(x)
+#endif
+
+#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
+
+typedef struct
+{
+ stbi_write_func *func;
+ void *context;
+} stbi__write_context;
+
+// initialize a callback-based context
+static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
+{
+ s->func = c;
+ s->context = context;
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+
+static void stbi__stdio_write(void *context, void *data, int size)
+{
+ fwrite(data,1,size,(FILE*) context);
+}
+
+static int stbi__start_write_file(stbi__write_context *s, const char *filename)
+{
+ FILE *f = fopen(filename, "wb");
+ stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
+ return f != NULL;
+}
+
+static void stbi__end_write_file(stbi__write_context *s)
+{
+ fclose((FILE *)s->context);
+}
+
+#endif // !STBI_WRITE_NO_STDIO
+
+typedef unsigned int stbiw_uint32;
+typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
+
+#ifdef STB_IMAGE_WRITE_STATIC
+static int stbi_write_tga_with_rle = 1;
+#else
+int stbi_write_tga_with_rle = 1;
+#endif
+
+static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
+{
+ while (*fmt) {
+ switch (*fmt++) {
+ case ' ': break;
+ case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
+ s->func(s->context,&x,1);
+ break; }
+ case '2': { int x = va_arg(v,int);
+ unsigned char b[2];
+ b[0] = STBIW_UCHAR(x);
+ b[1] = STBIW_UCHAR(x>>8);
+ s->func(s->context,b,2);
+ break; }
+ case '4': { stbiw_uint32 x = va_arg(v,int);
+ unsigned char b[4];
+ b[0]=STBIW_UCHAR(x);
+ b[1]=STBIW_UCHAR(x>>8);
+ b[2]=STBIW_UCHAR(x>>16);
+ b[3]=STBIW_UCHAR(x>>24);
+ s->func(s->context,b,4);
+ break; }
+ default:
+ STBIW_ASSERT(0);
+ return;
+ }
+ }
+}
+
+static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
+{
+ va_list v;
+ va_start(v, fmt);
+ stbiw__writefv(s, fmt, v);
+ va_end(v);
+}
+
+static void stbiw__putc(stbi__write_context *s, unsigned char c)
+{
+ s->func(s->context, &c, 1);
+}
+
+static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
+{
+ unsigned char arr[3];
+ arr[0] = a, arr[1] = b, arr[2] = c;
+ s->func(s->context, arr, 3);
+}
+
+static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
+{
+ unsigned char bg[3] = { 255, 0, 255}, px[3];
+ int k;
+
+ if (write_alpha < 0)
+ s->func(s->context, &d[comp - 1], 1);
+
+ switch (comp) {
+ case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
+ case 1:
+ if (expand_mono)
+ stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
+ else
+ s->func(s->context, d, 1); // monochrome TGA
+ break;
+ case 4:
+ if (!write_alpha) {
+ // composite against pink background
+ for (k = 0; k < 3; ++k)
+ px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
+ stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
+ break;
+ }
+ /* FALLTHROUGH */
+ case 3:
+ stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
+ break;
+ }
+ if (write_alpha > 0)
+ s->func(s->context, &d[comp - 1], 1);
+}
+
+static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
+{
+ stbiw_uint32 zero = 0;
+ int i,j, j_end;
+
+ if (y <= 0)
+ return;
+
+ if (vdir < 0)
+ j_end = -1, j = y-1;
+ else
+ j_end = y, j = 0;
+
+ for (; j != j_end; j += vdir) {
+ for (i=0; i < x; ++i) {
+ unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
+ stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
+ }
+ s->func(s->context, &zero, scanline_pad);
+ }
+}
+
+static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
+{
+ if (y < 0 || x < 0) {
+ return 0;
+ } else {
+ va_list v;
+ va_start(v, fmt);
+ stbiw__writefv(s, fmt, v);
+ va_end(v);
+ stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
+ return 1;
+ }
+}
+
+static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
+{
+ int pad = (-x*3) & 3;
+ return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
+ "11 4 22 4" "4 44 22 444444",
+ 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
+ 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
+}
+
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_bmp_core(&s, x, y, comp, data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_bmp_core(&s, x, y, comp, data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif //!STBI_WRITE_NO_STDIO
+
+static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
+{
+ int has_alpha = (comp == 2 || comp == 4);
+ int colorbytes = has_alpha ? comp-1 : comp;
+ int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
+
+ if (y < 0 || x < 0)
+ return 0;
+
+ if (!stbi_write_tga_with_rle) {
+ return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
+ "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+ } else {
+ int i,j,k;
+
+ stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+
+ for (j = y - 1; j >= 0; --j) {
+ unsigned char *row = (unsigned char *) data + j * x * comp;
+ int len;
+
+ for (i = 0; i < x; i += len) {
+ unsigned char *begin = row + i * comp;
+ int diff = 1;
+ len = 1;
+
+ if (i < x - 1) {
+ ++len;
+ diff = memcmp(begin, row + (i + 1) * comp, comp);
+ if (diff) {
+ const unsigned char *prev = begin;
+ for (k = i + 2; k < x && len < 128; ++k) {
+ if (memcmp(prev, row + k * comp, comp)) {
+ prev += comp;
+ ++len;
+ } else {
+ --len;
+ break;
+ }
+ }
+ } else {
+ for (k = i + 2; k < x && len < 128; ++k) {
+ if (!memcmp(begin, row + k * comp, comp)) {
+ ++len;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ if (diff) {
+ unsigned char header = STBIW_UCHAR(len - 1);
+ s->func(s->context, &header, 1);
+ for (k = 0; k < len; ++k) {
+ stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
+ }
+ } else {
+ unsigned char header = STBIW_UCHAR(len - 129);
+ s->func(s->context, &header, 1);
+ stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_tga_core(&s, x, y, comp, (void *) data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR writer
+// by Baldur Karlsson
+
+#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
+
+void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
+{
+ int exponent;
+ float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
+
+ if (maxcomp < 1e-32f) {
+ rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
+ } else {
+ float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
+
+ rgbe[0] = (unsigned char)(linear[0] * normalize);
+ rgbe[1] = (unsigned char)(linear[1] * normalize);
+ rgbe[2] = (unsigned char)(linear[2] * normalize);
+ rgbe[3] = (unsigned char)(exponent + 128);
+ }
+}
+
+void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
+{
+ unsigned char lengthbyte = STBIW_UCHAR(length+128);
+ STBIW_ASSERT(length+128 <= 255);
+ s->func(s->context, &lengthbyte, 1);
+ s->func(s->context, &databyte, 1);
+}
+
+void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
+{
+ unsigned char lengthbyte = STBIW_UCHAR(length);
+ STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
+ s->func(s->context, &lengthbyte, 1);
+ s->func(s->context, data, length);
+}
+
+void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
+{
+ unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
+ unsigned char rgbe[4];
+ float linear[3];
+ int x;
+
+ scanlineheader[2] = (width&0xff00)>>8;
+ scanlineheader[3] = (width&0x00ff);
+
+ /* skip RLE for images too small or large */
+ if (width < 8 || width >= 32768) {
+ for (x=0; x < width; x++) {
+ switch (ncomp) {
+ case 4: /* fallthrough */
+ case 3: linear[2] = scanline[x*ncomp + 2];
+ linear[1] = scanline[x*ncomp + 1];
+ linear[0] = scanline[x*ncomp + 0];
+ break;
+ default:
+ linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
+ break;
+ }
+ stbiw__linear_to_rgbe(rgbe, linear);
+ s->func(s->context, rgbe, 4);
+ }
+ } else {
+ int c,r;
+ /* encode into scratch buffer */
+ for (x=0; x < width; x++) {
+ switch(ncomp) {
+ case 4: /* fallthrough */
+ case 3: linear[2] = scanline[x*ncomp + 2];
+ linear[1] = scanline[x*ncomp + 1];
+ linear[0] = scanline[x*ncomp + 0];
+ break;
+ default:
+ linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
+ break;
+ }
+ stbiw__linear_to_rgbe(rgbe, linear);
+ scratch[x + width*0] = rgbe[0];
+ scratch[x + width*1] = rgbe[1];
+ scratch[x + width*2] = rgbe[2];
+ scratch[x + width*3] = rgbe[3];
+ }
+
+ s->func(s->context, scanlineheader, 4);
+
+ /* RLE each component separately */
+ for (c=0; c < 4; c++) {
+ unsigned char *comp = &scratch[width*c];
+
+ x = 0;
+ while (x < width) {
+ // find first run
+ r = x;
+ while (r+2 < width) {
+ if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
+ break;
+ ++r;
+ }
+ if (r+2 >= width)
+ r = width;
+ // dump up to first run
+ while (x < r) {
+ int len = r-x;
+ if (len > 128) len = 128;
+ stbiw__write_dump_data(s, len, &comp[x]);
+ x += len;
+ }
+ // if there's a run, output it
+ if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
+ // find next byte after run
+ while (r < width && comp[r] == comp[x])
+ ++r;
+ // output run up to r
+ while (x < r) {
+ int len = r-x;
+ if (len > 127) len = 127;
+ stbiw__write_run_data(s, len, comp[x]);
+ x += len;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
+{
+ if (y <= 0 || x <= 0 || data == NULL)
+ return 0;
+ else {
+ // Each component is stored separately. Allocate scratch space for full output scanline.
+ unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
+ int i, len;
+ char buffer[128];
+ char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
+ s->func(s->context, header, sizeof(header)-1);
+
+ len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
+ s->func(s->context, buffer, len);
+
+ for(i=0; i < y; i++)
+ stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
+ STBIW_FREE(scratch);
+ return 1;
+ }
+}
+
+STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif // STBI_WRITE_NO_STDIO
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PNG writer
+//
+
+// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
+#define stbiw__sbraw(a) ((int *) (a) - 2)
+#define stbiw__sbm(a) stbiw__sbraw(a)[0]
+#define stbiw__sbn(a) stbiw__sbraw(a)[1]
+
+#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
+#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
+#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
+
+#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
+#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
+#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
+
+static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
+{
+ int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
+ void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
+ STBIW_ASSERT(p);
+ if (p) {
+ if (!*arr) ((int *) p)[1] = 0;
+ *arr = (void *) ((int *) p + 2);
+ stbiw__sbm(*arr) = m;
+ }
+ return *arr;
+}
+
+static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
+{
+ while (*bitcount >= 8) {
+ stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
+ *bitbuffer >>= 8;
+ *bitcount -= 8;
+ }
+ return data;
+}
+
+static int stbiw__zlib_bitrev(int code, int codebits)
+{
+ int res=0;
+ while (codebits--) {
+ res = (res << 1) | (code & 1);
+ code >>= 1;
+ }
+ return res;
+}
+
+static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
+{
+ int i;
+ for (i=0; i < limit && i < 258; ++i)
+ if (a[i] != b[i]) break;
+ return i;
+}
+
+static unsigned int stbiw__zhash(unsigned char *data)
+{
+ stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+ return hash;
+}
+
+#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
+#define stbiw__zlib_add(code,codebits) \
+ (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
+#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
+// default huffman tables
+#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
+#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
+#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
+#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
+#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
+#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
+
+#define stbiw__ZHASH 16384
+
+unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
+{
+ static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
+ static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
+ static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
+ static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
+ unsigned int bitbuf=0;
+ int i,j, bitcount=0;
+ unsigned char *out = NULL;
+ unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
+ if (quality < 5) quality = 5;
+
+ stbiw__sbpush(out, 0x78); // DEFLATE 32K window
+ stbiw__sbpush(out, 0x5e); // FLEVEL = 1
+ stbiw__zlib_add(1,1); // BFINAL = 1
+ stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
+
+ for (i=0; i < stbiw__ZHASH; ++i)
+ hash_table[i] = NULL;
+
+ i=0;
+ while (i < data_len-3) {
+ // hash next 3 bytes of data to be compressed
+ int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
+ unsigned char *bestloc = 0;
+ unsigned char **hlist = hash_table[h];
+ int n = stbiw__sbcount(hlist);
+ for (j=0; j < n; ++j) {
+ if (hlist[j]-data > i-32768) { // if entry lies within window
+ int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
+ if (d >= best) best=d,bestloc=hlist[j];
+ }
+ }
+ // when hash table entry is too long, delete half the entries
+ if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
+ STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
+ stbiw__sbn(hash_table[h]) = quality;
+ }
+ stbiw__sbpush(hash_table[h],data+i);
+
+ if (bestloc) {
+ // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
+ h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
+ hlist = hash_table[h];
+ n = stbiw__sbcount(hlist);
+ for (j=0; j < n; ++j) {
+ if (hlist[j]-data > i-32767) {
+ int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
+ if (e > best) { // if next match is better, bail on current match
+ bestloc = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ if (bestloc) {
+ int d = (int) (data+i - bestloc); // distance back
+ STBIW_ASSERT(d <= 32767 && best <= 258);
+ for (j=0; best > lengthc[j+1]-1; ++j);
+ stbiw__zlib_huff(j+257);
+ if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
+ for (j=0; d > distc[j+1]-1; ++j);
+ stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
+ if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
+ i += best;
+ } else {
+ stbiw__zlib_huffb(data[i]);
+ ++i;
+ }
+ }
+ // write out final bytes
+ for (;i < data_len; ++i)
+ stbiw__zlib_huffb(data[i]);
+ stbiw__zlib_huff(256); // end of block
+ // pad with 0 bits to byte boundary
+ while (bitcount)
+ stbiw__zlib_add(0,1);
+
+ for (i=0; i < stbiw__ZHASH; ++i)
+ (void) stbiw__sbfree(hash_table[i]);
+ STBIW_FREE(hash_table);
+
+ {
+ // compute adler32 on input
+ unsigned int s1=1, s2=0;
+ int blocklen = (int) (data_len % 5552);
+ j=0;
+ while (j < data_len) {
+ for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
+ s1 %= 65521, s2 %= 65521;
+ j += blocklen;
+ blocklen = 5552;
+ }
+ stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
+ stbiw__sbpush(out, STBIW_UCHAR(s2));
+ stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
+ stbiw__sbpush(out, STBIW_UCHAR(s1));
+ }
+ *out_len = stbiw__sbn(out);
+ // make returned pointer freeable
+ STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
+ return (unsigned char *) stbiw__sbraw(out);
+}
+
+static unsigned int stbiw__crc32(unsigned char *buffer, int len)
+{
+ static unsigned int crc_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+
+ unsigned int crc = ~0u;
+ int i;
+ for (i=0; i < len; ++i)
+ crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
+ return ~crc;
+}
+
+#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
+#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
+#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
+
+static void stbiw__wpcrc(unsigned char **data, int len)
+{
+ unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
+ stbiw__wp32(*data, crc);
+}
+
+static unsigned char stbiw__paeth(int a, int b, int c)
+{
+ int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
+ if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
+ if (pb <= pc) return STBIW_UCHAR(b);
+ return STBIW_UCHAR(c);
+}
+
+// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
+unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
+{
+ int ctype[5] = { -1, 0, 4, 2, 6 };
+ unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
+ unsigned char *out,*o, *filt, *zlib;
+ signed char *line_buffer;
+ int i,j,k,p,zlen;
+
+ if (stride_bytes == 0)
+ stride_bytes = x * n;
+
+ filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
+ line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
+ for (j=0; j < y; ++j) {
+ static int mapping[] = { 0,1,2,3,4 };
+ static int firstmap[] = { 0,1,0,5,6 };
+ int *mymap = (j != 0) ? mapping : firstmap;
+ int best = 0, bestval = 0x7fffffff;
+ for (p=0; p < 2; ++p) {
+ for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
+ int type = mymap[k],est=0;
+ unsigned char *z = pixels + stride_bytes*j;
+ for (i=0; i < n; ++i)
+ switch (type) {
+ case 0: line_buffer[i] = z[i]; break;
+ case 1: line_buffer[i] = z[i]; break;
+ case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+ case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
+ case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
+ case 5: line_buffer[i] = z[i]; break;
+ case 6: line_buffer[i] = z[i]; break;
+ }
+ for (i=n; i < x*n; ++i) {
+ switch (type) {
+ case 0: line_buffer[i] = z[i]; break;
+ case 1: line_buffer[i] = z[i] - z[i-n]; break;
+ case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+ case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
+ case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
+ case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
+ case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
+ }
+ }
+ if (p) break;
+ for (i=0; i < x*n; ++i)
+ est += abs((signed char) line_buffer[i]);
+ if (est < bestval) { bestval = est; best = k; }
+ }
+ }
+ // when we get here, best contains the filter type, and line_buffer contains the data
+ filt[j*(x*n+1)] = (unsigned char) best;
+ STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
+ }
+ STBIW_FREE(line_buffer);
+ zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
+ STBIW_FREE(filt);
+ if (!zlib) return 0;
+
+ // each tag requires 12 bytes of overhead
+ out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
+ if (!out) return 0;
+ *out_len = 8 + 12+13 + 12+zlen + 12;
+
+ o=out;
+ STBIW_MEMMOVE(o,sig,8); o+= 8;
+ stbiw__wp32(o, 13); // header length
+ stbiw__wptag(o, "IHDR");
+ stbiw__wp32(o, x);
+ stbiw__wp32(o, y);
+ *o++ = 8;
+ *o++ = STBIW_UCHAR(ctype[n]);
+ *o++ = 0;
+ *o++ = 0;
+ *o++ = 0;
+ stbiw__wpcrc(&o,13);
+
+ stbiw__wp32(o, zlen);
+ stbiw__wptag(o, "IDAT");
+ STBIW_MEMMOVE(o, zlib, zlen);
+ o += zlen;
+ STBIW_FREE(zlib);
+ stbiw__wpcrc(&o, zlen);
+
+ stbiw__wp32(o,0);
+ stbiw__wptag(o, "IEND");
+ stbiw__wpcrc(&o,0);
+
+ STBIW_ASSERT(o == out + *out_len);
+
+ return out;
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
+{
+ FILE *f;
+ int len;
+ unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
+ if (png == NULL) return 0;
+ f = fopen(filename, "wb");
+ if (!f) { STBIW_FREE(png); return 0; }
+ fwrite(png, 1, len, f);
+ fclose(f);
+ STBIW_FREE(png);
+ return 1;
+}
+#endif
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
+{
+ int len;
+ unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
+ if (png == NULL) return 0;
+ func(context, png, len);
+ STBIW_FREE(png);
+ return 1;
+}
+
+
+/* ***************************************************************************
+ *
+ * JPEG writer
+ *
+ * This is based on Jon Olick's jo_jpeg.cpp:
+ * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
+ */
+
+static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
+ 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
+
+static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
+ int bitBuf = *bitBufP, bitCnt = *bitCntP;
+ bitCnt += bs[1];
+ bitBuf |= bs[0] << (24 - bitCnt);
+ while(bitCnt >= 8) {
+ unsigned char c = (bitBuf >> 16) & 255;
+ stbiw__putc(s, c);
+ if(c == 255) {
+ stbiw__putc(s, 0);
+ }
+ bitBuf <<= 8;
+ bitCnt -= 8;
+ }
+ *bitBufP = bitBuf;
+ *bitCntP = bitCnt;
+}
+
+static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
+ float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
+ float z1, z2, z3, z4, z5, z11, z13;
+
+ float tmp0 = d0 + d7;
+ float tmp7 = d0 - d7;
+ float tmp1 = d1 + d6;
+ float tmp6 = d1 - d6;
+ float tmp2 = d2 + d5;
+ float tmp5 = d2 - d5;
+ float tmp3 = d3 + d4;
+ float tmp4 = d3 - d4;
+
+ // Even part
+ float tmp10 = tmp0 + tmp3; // phase 2
+ float tmp13 = tmp0 - tmp3;
+ float tmp11 = tmp1 + tmp2;
+ float tmp12 = tmp1 - tmp2;
+
+ d0 = tmp10 + tmp11; // phase 3
+ d4 = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * 0.707106781f; // c4
+ d2 = tmp13 + z1; // phase 5
+ d6 = tmp13 - z1;
+
+ // Odd part
+ tmp10 = tmp4 + tmp5; // phase 2
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ // The rotator is modified from fig 4-8 to avoid extra negations.
+ z5 = (tmp10 - tmp12) * 0.382683433f; // c6
+ z2 = tmp10 * 0.541196100f + z5; // c2-c6
+ z4 = tmp12 * 1.306562965f + z5; // c2+c6
+ z3 = tmp11 * 0.707106781f; // c4
+
+ z11 = tmp7 + z3; // phase 5
+ z13 = tmp7 - z3;
+
+ *d5p = z13 + z2; // phase 6
+ *d3p = z13 - z2;
+ *d1p = z11 + z4;
+ *d7p = z11 - z4;
+
+ *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
+}
+
+static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
+ int tmp1 = val < 0 ? -val : val;
+ val = val < 0 ? val-1 : val;
+ bits[1] = 1;
+ while(tmp1 >>= 1) {
+ ++bits[1];
+ }
+ bits[0] = val & ((1<<bits[1])-1);
+}
+
+static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
+ const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
+ const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
+ int dataOff, i, diff, end0pos;
+ int DU[64];
+
+ // DCT rows
+ for(dataOff=0; dataOff<64; dataOff+=8) {
+ stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
+ }
+ // DCT columns
+ for(dataOff=0; dataOff<8; ++dataOff) {
+ stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
+ }
+ // Quantize/descale/zigzag the coefficients
+ for(i=0; i<64; ++i) {
+ float v = CDU[i]*fdtbl[i];
+ // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
+ // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
+ DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
+ }
+
+ // Encode DC
+ diff = DU[0] - DC;
+ if (diff == 0) {
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
+ } else {
+ unsigned short bits[2];
+ stbiw__jpg_calcBits(diff, bits);
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
+ }
+ // Encode ACs
+ end0pos = 63;
+ for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
+ }
+ // end0pos = first element in reverse order !=0
+ if(end0pos == 0) {
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
+ return DU[0];
+ }
+ for(i = 1; i <= end0pos; ++i) {
+ int startpos = i;
+ int nrzeroes;
+ unsigned short bits[2];
+ for (; DU[i]==0 && i<=end0pos; ++i) {
+ }
+ nrzeroes = i-startpos;
+ if ( nrzeroes >= 16 ) {
+ int lng = nrzeroes>>4;
+ int nrmarker;
+ for (nrmarker=1; nrmarker <= lng; ++nrmarker)
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
+ nrzeroes &= 15;
+ }
+ stbiw__jpg_calcBits(DU[i], bits);
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
+ }
+ if(end0pos != 63) {
+ stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
+ }
+ return DU[0];
+}
+
+static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
+ // Constants that don't pollute global namespace
+ static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
+ static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
+ static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
+ static const unsigned char std_ac_luminance_values[] = {
+ 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
+ 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
+ 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
+ 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
+ 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
+ 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
+ 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
+ };
+ static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
+ static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
+ static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
+ static const unsigned char std_ac_chrominance_values[] = {
+ 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
+ 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
+ 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
+ 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
+ 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
+ 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
+ };
+ // Huffman tables
+ static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};
+ static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};
+ static const unsigned short YAC_HT[256][2] = {
+ {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
+ };
+ static const unsigned short UVAC_HT[256][2] = {
+ {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},
+ {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
+ };
+ static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,
+ 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
+ static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
+ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
+ static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
+ 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
+
+ int row, col, i, k;
+ float fdtbl_Y[64], fdtbl_UV[64];
+ unsigned char YTable[64], UVTable[64];
+
+ if(!data || !width || !height || comp > 4 || comp < 1) {
+ return 0;
+ }
+
+ quality = quality ? quality : 90;
+ quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
+ quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
+
+ for(i = 0; i < 64; ++i) {
+ int uvti, yti = (YQT[i]*quality+50)/100;
+ YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
+ uvti = (UVQT[i]*quality+50)/100;
+ UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
+ }
+
+ for(row = 0, k = 0; row < 8; ++row) {
+ for(col = 0; col < 8; ++col, ++k) {
+ fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
+ fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
+ }
+ }
+
+ // Write Headers
+ {
+ static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
+ static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
+ const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
+ 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
+ s->func(s->context, (void*)head0, sizeof(head0));
+ s->func(s->context, (void*)YTable, sizeof(YTable));
+ stbiw__putc(s, 1);
+ s->func(s->context, UVTable, sizeof(UVTable));
+ s->func(s->context, (void*)head1, sizeof(head1));
+ s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
+ s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
+ stbiw__putc(s, 0x10); // HTYACinfo
+ s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
+ s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
+ stbiw__putc(s, 1); // HTUDCinfo
+ s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
+ s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
+ stbiw__putc(s, 0x11); // HTUACinfo
+ s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
+ s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
+ s->func(s->context, (void*)head2, sizeof(head2));
+ }
+
+ // Encode 8x8 macroblocks
+ {
+ static const unsigned short fillBits[] = {0x7F, 7};
+ const unsigned char *imageData = (const unsigned char *)data;
+ int DCY=0, DCU=0, DCV=0;
+ int bitBuf=0, bitCnt=0;
+ // comp == 2 is grey+alpha (alpha is ignored)
+ int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
+ int x, y, pos;
+ for(y = 0; y < height; y += 8) {
+ for(x = 0; x < width; x += 8) {
+ float YDU[64], UDU[64], VDU[64];
+ for(row = y, pos = 0; row < y+8; ++row) {
+ for(col = x; col < x+8; ++col, ++pos) {
+ int p = row*width*comp + col*comp;
+ float r, g, b;
+ if(row >= height) {
+ p -= width*comp*(row+1 - height);
+ }
+ if(col >= width) {
+ p -= comp*(col+1 - width);
+ }
+
+ r = imageData[p+0];
+ g = imageData[p+ofsG];
+ b = imageData[p+ofsB];
+ YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
+ UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
+ VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
+ }
+ }
+
+ DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
+ DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
+ DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
+ }
+ }
+
+ // Do the bit alignment of the EOI marker
+ stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
+ }
+
+ // EOI
+ stbiw__putc(s, 0xFF);
+ stbiw__putc(s, 0xD9);
+
+ return 1;
+}
+
+STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
+{
+ stbi__write_context s;
+ stbi__start_write_callbacks(&s, func, context);
+ return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
+}
+
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
+{
+ stbi__write_context s;
+ if (stbi__start_write_file(&s,filename)) {
+ int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
+ stbi__end_write_file(&s);
+ return r;
+ } else
+ return 0;
+}
+#endif
+
+#endif // STB_IMAGE_WRITE_IMPLEMENTATION
+
+/* Revision history
+ 1.07 (2017-07-24)
+ doc fix
+ 1.06 (2017-07-23)
+ writing JPEG (using Jon Olick's code)
+ 1.05 ???
+ 1.04 (2017-03-03)
+ monochrome BMP expansion
+ 1.03 ???
+ 1.02 (2016-04-02)
+ avoid allocating large structures on the stack
+ 1.01 (2016-01-16)
+ STBIW_REALLOC_SIZED: support allocators with no realloc support
+ avoid race-condition in crc initialization
+ minor compile issues
+ 1.00 (2015-09-14)
+ installable file IO function
+ 0.99 (2015-09-13)
+ warning fixes; TGA rle support
+ 0.98 (2015-04-08)
+ added STBIW_MALLOC, STBIW_ASSERT etc
+ 0.97 (2015-01-18)
+ fixed HDR asserts, rewrote HDR rle logic
+ 0.96 (2015-01-17)
+ add HDR output
+ fix monochrome BMP
+ 0.95 (2014-08-17)
+ add monochrome TGA output
+ 0.94 (2014-05-31)
+ rename private functions to avoid conflicts with stb_image.h
+ 0.93 (2014-05-27)
+ warning fixes
+ 0.92 (2010-08-01)
+ casts to unsigned char to fix warnings
+ 0.91 (2010-07-17)
+ first public release
+ 0.90 first internal release
+*/
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/include/SFML/Audio.hpp b/include/SFML/Audio.hpp
new file mode 100644
index 0000000..3167927
--- /dev/null
+++ b/include/SFML/Audio.hpp
@@ -0,0 +1,56 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System.hpp>
+#include <SFML/Audio/InputSoundFile.hpp>
+#include <SFML/Audio/Listener.hpp>
+#include <SFML/Audio/Music.hpp>
+#include <SFML/Audio/OutputSoundFile.hpp>
+#include <SFML/Audio/Sound.hpp>
+#include <SFML/Audio/SoundBuffer.hpp>
+#include <SFML/Audio/SoundBufferRecorder.hpp>
+#include <SFML/Audio/SoundFileFactory.hpp>
+#include <SFML/Audio/SoundFileReader.hpp>
+#include <SFML/Audio/SoundFileWriter.hpp>
+#include <SFML/Audio/SoundRecorder.hpp>
+#include <SFML/Audio/SoundSource.hpp>
+#include <SFML/Audio/SoundStream.hpp>
+
+
+#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..dd7d44c
--- /dev/null
+++ b/include/SFML/Audio/AlResource.hpp
@@ -0,0 +1,70 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+
+
+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..9e5e09c
--- /dev/null
+++ b/include/SFML/Audio/Export.hpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+// 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..317b952
--- /dev/null
+++ b/include/SFML/Audio/InputSoundFile.hpp
@@ -0,0 +1,263 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Time.hpp>
+#include <string>
+#include <algorithm>
+
+
+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 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 Get the read offset of the file in time
+ ///
+ /// \return Time position
+ ///
+ ////////////////////////////////////////////////////////////
+ Time getTimeOffset() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the read offset of the file in samples
+ ///
+ /// \return Sample position
+ ///
+ ////////////////////////////////////////////////////////////
+ Uint64 getSampleOffset() 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.
+ /// If you have a time offset instead, you can easily find
+ /// the corresponding sample offset with the following formula:
+ /// `timeInSeconds * 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_sampleOffset; ///< Sample Read Position
+ 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..9fb7fff
--- /dev/null
+++ b/include/SFML/Audio/Listener.hpp
@@ -0,0 +1,234 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/System/Vector3.hpp>
+
+
+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..5351905
--- /dev/null
+++ b/include/SFML/Audio/Music.hpp
@@ -0,0 +1,337 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/SoundStream.hpp>
+#include <SFML/Audio/InputSoundFile.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Time.hpp>
+#include <string>
+#include <vector>
+
+
+namespace sf
+{
+class InputStream;
+
+////////////////////////////////////////////////////////////
+/// \brief Streamed music played from an audio file
+///
+////////////////////////////////////////////////////////////
+class SFML_AUDIO_API Music : public SoundStream
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Structure defining a time range using the template type
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename T>
+ struct Span
+ {
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ Span()
+ {
+
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Initialization constructor
+ ///
+ /// \param off Initial Offset
+ /// \param len Initial Length
+ ///
+ ////////////////////////////////////////////////////////////
+ Span(T off, T len):
+ offset(off),
+ length(len)
+ {
+
+ }
+
+ T offset; ///< The beginning offset of the time range
+ T length; ///< The length of the time range
+ };
+
+ // Define the relevant Span types
+ typedef Span<Time> TimeSpan;
+
+ ////////////////////////////////////////////////////////////
+ /// \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;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the positions of the of the sound's looping sequence
+ ///
+ /// \return Loop Time position class.
+ ///
+ /// \warning Since setLoopPoints() performs some adjustments on the
+ /// provided values and rounds them to internal samples, a call to
+ /// getLoopPoints() is not guaranteed to return the same times passed
+ /// into a previous call to setLoopPoints(). However, it is guaranteed
+ /// to return times that will map to the valid internal samples of
+ /// this Music if they are later passed to setLoopPoints().
+ ///
+ /// \see setLoopPoints
+ ///
+ ////////////////////////////////////////////////////////////
+ TimeSpan getLoopPoints() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Sets the beginning and end of the sound's looping sequence using sf::Time
+ ///
+ /// Loop points allow one to specify a pair of positions such that, when the music
+ /// is enabled for looping, it will seamlessly seek to the beginning whenever it
+ /// encounters the end. Valid ranges for timePoints.offset and timePoints.length are
+ /// [0, Dur) and (0, Dur-offset] respectively, where Dur is the value returned by getDuration().
+ /// Note that the EOF "loop point" from the end to the beginning of the stream is still honored,
+ /// in case the caller seeks to a point after the end of the loop range. This function can be
+ /// safely called at any point after a stream is opened, and will be applied to a playing sound
+ /// without affecting the current playing offset.
+ ///
+ /// \warning Setting the loop points while the stream's status is Paused
+ /// will set its status to Stopped. The playing offset will be unaffected.
+ ///
+ /// \param timePoints The definition of the loop. Can be any time points within the sound's length
+ ///
+ /// \see getLoopPoints
+ ///
+ ////////////////////////////////////////////////////////////
+ void setLoopPoints(TimeSpan timePoints);
+
+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);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current playing position in the stream source to the loop offset
+ ///
+ /// This is called by the underlying SoundStream whenever it needs us to reset
+ /// the seek position for a loop. We then determine whether we are looping on a
+ /// loop point or the end-of-file, perform the seek, and return the new position.
+ ///
+ /// \return The seek position after looping (or -1 if there's no loop)
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Int64 onLoop();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Initialize the internal state after loading a new music
+ ///
+ ////////////////////////////////////////////////////////////
+ void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Helper to convert an sf::Time to a sample position
+ ///
+ /// \param position Time to convert to samples
+ ///
+ /// \return The number of samples elapsed at the given time
+ ///
+ ////////////////////////////////////////////////////////////
+ Uint64 timeToSamples(Time position) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Helper to convert a sample position to an sf::Time
+ ///
+ /// \param samples Sample count to convert to Time
+ ///
+ /// \return The Time position of the given sample
+ ///
+ ////////////////////////////////////////////////////////////
+ Time samplesToTime(Uint64 samples) const;
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ InputSoundFile m_file; ///< The streamed music file
+ std::vector<Int16> m_samples; ///< Temporary buffer of samples
+ Mutex m_mutex; ///< Mutex protecting the data
+ Span<Uint64> m_loopSpan; ///< Loop Range Specifier
+};
+
+} // 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..5da374b
--- /dev/null
+++ b/include/SFML/Audio/OutputSoundFile.hpp
@@ -0,0 +1,133 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <string>
+
+
+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<sf::Int16> 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..f8e2e14
--- /dev/null
+++ b/include/SFML/Audio/Sound.hpp
@@ -0,0 +1,264 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/SoundSource.hpp>
+#include <SFML/System/Time.hpp>
+#include <cstdlib>
+
+
+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..5aaa4ca
--- /dev/null
+++ b/include/SFML/Audio/SoundBuffer.hpp
@@ -0,0 +1,352 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/AlResource.hpp>
+#include <SFML/System/Time.hpp>
+#include <string>
+#include <vector>
+#include <set>
+
+
+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<Sound*> SoundList; ///< Set of unique sound instances
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ unsigned int m_buffer; ///< OpenAL buffer identifier
+ std::vector<Int16> 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..266603d
--- /dev/null
+++ b/include/SFML/Audio/SoundBufferRecorder.hpp
@@ -0,0 +1,144 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/SoundBuffer.hpp>
+#include <SFML/Audio/SoundRecorder.hpp>
+#include <vector>
+
+
+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<Int16> 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..e3719c8
--- /dev/null
+++ b/include/SFML/Audio/SoundFileFactory.hpp
@@ -0,0 +1,197 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <string>
+#include <vector>
+
+
+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 <typename T>
+ static void registerReader();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unregister a reader
+ ///
+ /// \see registerReader
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename T>
+ static void unregisterReader();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a new writer
+ ///
+ /// \see unregisterWriter
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename T>
+ static void registerWriter();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unregister a writer
+ ///
+ /// \see registerWriter
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename T>
+ 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<ReaderFactory> ReaderFactoryArray;
+
+ struct WriterFactory
+ {
+ bool (*check)(const std::string&);
+ SoundFileWriter* (*create)();
+ };
+ typedef std::vector<WriterFactory> 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 <SFML/Audio/SoundFileFactory.inl>
+
+#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<MySoundFileReader>();
+/// sf::SoundFileFactory::registerWriter<MySoundFileWriter>();
+/// \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..6c499f3
--- /dev/null
+++ b/include/SFML/Audio/SoundFileFactory.inl
@@ -0,0 +1,100 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T> SoundFileReader* createReader() {return new T;}
+ template <typename T> SoundFileWriter* createWriter() {return new T;}
+}
+
+////////////////////////////////////////////////////////////
+template <typename T>
+void SoundFileFactory::registerReader()
+{
+ // Make sure the same class won't be registered twice
+ unregisterReader<T>();
+
+ // Create a new factory with the functions provided by the class
+ ReaderFactory factory;
+ factory.check = &T::check;
+ factory.create = &priv::createReader<T>;
+
+ // Add it
+ s_readers.push_back(factory);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+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<T>)
+ it = s_readers.erase(it);
+ else
+ ++it;
+ }
+}
+
+////////////////////////////////////////////////////////////
+template <typename T>
+void SoundFileFactory::registerWriter()
+{
+ // Make sure the same class won't be registered twice
+ unregisterWriter<T>();
+
+ // Create a new factory with the functions provided by the class
+ WriterFactory factory;
+ factory.check = &T::check;
+ factory.create = &priv::createWriter<T>;
+
+ // Add it
+ s_writers.push_back(factory);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+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<T>)
+ 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..a040db9
--- /dev/null
+++ b/include/SFML/Audio/SoundFileReader.hpp
@@ -0,0 +1,165 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <string>
+
+
+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.
+ /// If you have a time offset instead, you can easily find
+ /// the corresponding sample offset with the following formula:
+ /// `timeInSeconds * 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<MySoundFileReader>();
+/// \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..8651ddc
--- /dev/null
+++ b/include/SFML/Audio/SoundFileWriter.hpp
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <string>
+
+
+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<MySoundFileWriter>();
+/// \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..d4dc74f
--- /dev/null
+++ b/include/SFML/Audio/SoundRecorder.hpp
@@ -0,0 +1,408 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/AlResource.hpp>
+#include <SFML/System/Thread.hpp>
+#include <SFML/System/Time.hpp>
+#include <vector>
+#include <string>
+
+
+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<std::string> 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<Int16> 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..fcc9c79
--- /dev/null
+++ b/include/SFML/Audio/SoundSource.hpp
@@ -0,0 +1,332 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/AlResource.hpp>
+#include <SFML/System/Vector3.hpp>
+
+
+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);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Start or resume playing the sound source
+ ///
+ /// This function starts the source if it was stopped, resumes
+ /// it if it was paused, and restarts it from the beginning if
+ /// it was already playing.
+ ///
+ /// \see pause, stop
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void play() = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Pause the sound source
+ ///
+ /// This function pauses the source if it was playing,
+ /// otherwise (source already paused or stopped) it has no effect.
+ ///
+ /// \see play, stop
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void pause() = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Stop playing the sound source
+ ///
+ /// This function stops the source 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
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void stop() = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current status of the sound (stopped, paused, playing)
+ ///
+ /// \return Current status of the sound
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Status getStatus() const;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// This constructor is meant to be called by derived classes only.
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundSource();
+
+ ////////////////////////////////////////////////////////////
+ // 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..bed8311
--- /dev/null
+++ b/include/SFML/Audio/SoundStream.hpp
@@ -0,0 +1,405 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Audio/Export.hpp>
+#include <SFML/Audio/SoundSource.hpp>
+#include <SFML/System/Thread.hpp>
+#include <SFML/System/Time.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <cstdlib>
+
+
+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:
+
+ enum
+ {
+ NoLoop = -1 ///< "Invalid" endSeeks value, telling us to continue uninterrupted
+ };
+
+ ////////////////////////////////////////////////////////////
+ /// \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;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current playing position in the stream source to the beginning of the loop
+ ///
+ /// This function can be overridden by derived classes to
+ /// allow implementation of custom loop points. Otherwise,
+ /// it just calls onSeek(Time::Zero) and returns 0.
+ ///
+ /// \return The seek position after looping (or -1 if there's no loop)
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Int64 onLoop();
+
+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])
+ /// \param immediateLoop Treat empty buffers as spent, and act on loops immediately
+ ///
+ /// \return True if the stream source has requested to stop, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool fillAndPushBuffer(unsigned int bufferNum, bool immediateLoop = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \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
+ BufferRetries = 2 ///< Number of retries (excluding initial try) for onGetData()
+ };
+
+ ////////////////////////////////////////////////////////////
+ // 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
+ Int64 m_bufferSeeks[BufferCount]; ///< If buffer is an "end buffer", holds next seek position, else NoLoop. For play offset 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..40b677e
--- /dev/null
+++ b/include/SFML/Config.hpp
@@ -0,0 +1,236 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 5
+#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
+
+ #elif defined(__OpenBSD__)
+
+ // OpenBSD
+ #define SFML_SYSTEM_OPENBSD
+
+ #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/GpuPreference.hpp b/include/SFML/GpuPreference.hpp
new file mode 100644
index 0000000..cde4f9f
--- /dev/null
+++ b/include/SFML/GpuPreference.hpp
@@ -0,0 +1,74 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GPUPREFERENCE_HPP
+#define SFML_GPUPREFERENCE_HPP
+
+
+////////////////////////////////////////////////////////////
+/// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+/// \file
+///
+/// \brief File containing SFML_DEFINE_DISCRETE_GPU_PREFERENCE
+///
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+/// \def SFML_DEFINE_DISCRETE_GPU_PREFERENCE
+///
+/// \brief A macro to encourage usage of the discrete GPU
+///
+/// In order to inform the Nvidia/AMD driver that an SFML
+/// application could benefit from using the more powerful
+/// discrete GPU, special symbols have to be publicly
+/// exported from the final executable.
+///
+/// SFML defines a helper macro to easily do this.
+///
+/// Place SFML_DEFINE_DISCRETE_GPU_PREFERENCE in the
+/// global scope of a source file that will be linked into
+/// the final executable. Typically it is best to place it
+/// where the main function is also defined.
+///
+////////////////////////////////////////////////////////////
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #define SFML_DEFINE_DISCRETE_GPU_PREFERENCE \
+ extern "C" __declspec(dllexport) unsigned long NvOptimusEnablement = 1; \
+ extern "C" __declspec(dllexport) unsigned long AmdPowerXpressRequestHighPerformance = 1;
+
+#else
+
+ #define SFML_DEFINE_DISCRETE_GPU_PREFERENCE
+
+#endif
+
+
+#endif // SFML_GPUPREFERENCE_HPP
diff --git a/include/SFML/Graphics.hpp b/include/SFML/Graphics.hpp
new file mode 100644
index 0000000..252c6e9
--- /dev/null
+++ b/include/SFML/Graphics.hpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window.hpp>
+#include <SFML/Graphics/BlendMode.hpp>
+#include <SFML/Graphics/CircleShape.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/Graphics/ConvexShape.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Graphics/Font.hpp>
+#include <SFML/Graphics/Glyph.hpp>
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Graphics/PrimitiveType.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/Graphics/RectangleShape.hpp>
+#include <SFML/Graphics/RenderStates.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Graphics/RenderTexture.hpp>
+#include <SFML/Graphics/RenderWindow.hpp>
+#include <SFML/Graphics/Shader.hpp>
+#include <SFML/Graphics/Shape.hpp>
+#include <SFML/Graphics/Sprite.hpp>
+#include <SFML/Graphics/Text.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/Transform.hpp>
+#include <SFML/Graphics/Transformable.hpp>
+#include <SFML/Graphics/Vertex.hpp>
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/Graphics/VertexBuffer.hpp>
+#include <SFML/Graphics/View.hpp>
+
+
+#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..15da7d1
--- /dev/null
+++ b/include/SFML/Graphics/BlendMode.hpp
@@ -0,0 +1,215 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+
+
+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..896c893
--- /dev/null
+++ b/include/SFML/Graphics/CircleShape.hpp
@@ -0,0 +1,154 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Shape.hpp>
+
+
+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..43357aa
--- /dev/null
+++ b/include/SFML/Graphics/Color.hpp
@@ -0,0 +1,275 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+
+
+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..e770299
--- /dev/null
+++ b/include/SFML/Graphics/ConvexShape.hpp
@@ -0,0 +1,153 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Shape.hpp>
+#include <vector>
+
+
+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<Vector2f> 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..852b22d
--- /dev/null
+++ b/include/SFML/Graphics/Drawable.hpp
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/RenderStates.hpp>
+
+
+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..0b47b39
--- /dev/null
+++ b/include/SFML/Graphics/Export.hpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+// 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..e753866
--- /dev/null
+++ b/include/SFML/Graphics/Font.hpp
@@ -0,0 +1,439 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Glyph.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/String.hpp>
+#include <map>
+#include <string>
+#include <vector>
+
+
+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 knows 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<Uint64, Glyph> 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<Row> 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<unsigned int, Page> 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<Uint8> 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..e3943e7
--- /dev/null
+++ b/include/SFML/Graphics/Glsl.hpp
@@ -0,0 +1,227 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Transform.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/Vector3.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+ // Forward declarations
+ template <std::size_t Columns, std::size_t Rows>
+ struct Matrix;
+
+ template <typename T>
+ struct Vector4;
+
+#include <SFML/Graphics/Glsl.inl>
+
+} // namespace priv
+
+
+////////////////////////////////////////////////////////////
+/// \brief Namespace with GLSL types
+///
+////////////////////////////////////////////////////////////
+namespace Glsl
+{
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 2D float vector (\p vec2 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector2<float> Vec2;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 2D int vector (\p ivec2 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector2<int> Ivec2;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 2D bool vector (\p bvec2 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector2<bool> Bvec2;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 3D float vector (\p vec3 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector3<float> Vec3;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 3D int vector (\p ivec3 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector3<int> Ivec3;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief 3D bool vector (\p bvec3 in GLSL)
+ ///
+ ////////////////////////////////////////////////////////////
+ typedef Vector3<bool> 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<float> Vec4;
+ typedef priv::Vector4<int> Ivec4;
+ typedef priv::Vector4<bool> 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<T>
+/// and \ref sf::Vector3<T>, 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..9c9f0ae
--- /dev/null
+++ b/include/SFML/Graphics/Glsl.inl
@@ -0,0 +1,155 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+/// <algorithm> 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<float>& dest);
+void SFML_GRAPHICS_API copyVector(const Color& source, Vector4<int>& dest);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Matrix type, used to set uniforms in GLSL
+///
+////////////////////////////////////////////////////////////
+template <std::size_t Columns, std::size_t Rows>
+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 <typename T>
+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 <typename U>
+ explicit Vector4(const Vector4<U>& other) :
+ x(static_cast<T>(other.x)),
+ y(static_cast<T>(other.y)),
+ z(static_cast<T>(other.z)),
+ w(static_cast<T>(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..59deb9b
--- /dev/null
+++ b/include/SFML/Graphics/Glyph.hpp
@@ -0,0 +1,79 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Rect.hpp>
+
+
+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..c1d672a
--- /dev/null
+++ b/include/SFML/Graphics/Image.hpp
@@ -0,0 +1,324 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <string>
+#include <vector>
+
+
+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<Uint8> m_pixels; ///< Pixels of the image
+};
+
+} // 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..28cf58d
--- /dev/null
+++ b/include/SFML/Graphics/PrimitiveType.hpp
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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..17f20a5
--- /dev/null
+++ b/include/SFML/Graphics/Rect.hpp
@@ -0,0 +1,254 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Vector2.hpp>
+#include <algorithm>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// \brief Utility class for manipulating 2D axis aligned rectangles
+///
+////////////////////////////////////////////////////////////
+template <typename T>
+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<T>& position, const Vector2<T>& 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 <typename U>
+ explicit Rect(const Rect<U>& 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<T>& 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<T>& 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<T>& rectangle, Rect<T>& 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 <typename T>
+bool operator ==(const Rect<T>& left, const Rect<T>& 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 <typename T>
+bool operator !=(const Rect<T>& left, const Rect<T>& right);
+
+#include <SFML/Graphics/Rect.inl>
+
+// Create typedefs for the most common types
+typedef Rect<int> IntRect;
+typedef Rect<float> 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<int> is sf::IntRect
+/// \li sf::Rect<float> 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..7a82e46
--- /dev/null
+++ b/include/SFML/Graphics/Rect.inl
@@ -0,0 +1,159 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+Rect<T>::Rect() :
+left (0),
+top (0),
+width (0),
+height(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+Rect<T>::Rect(T rectLeft, T rectTop, T rectWidth, T rectHeight) :
+left (rectLeft),
+top (rectTop),
+width (rectWidth),
+height(rectHeight)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+Rect<T>::Rect(const Vector2<T>& position, const Vector2<T>& size) :
+left (position.x),
+top (position.y),
+width (size.x),
+height(size.y)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+template <typename U>
+Rect<T>::Rect(const Rect<U>& rectangle) :
+left (static_cast<T>(rectangle.left)),
+top (static_cast<T>(rectangle.top)),
+width (static_cast<T>(rectangle.width)),
+height(static_cast<T>(rectangle.height))
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+bool Rect<T>::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<T>(left + width));
+ T maxX = std::max(left, static_cast<T>(left + width));
+ T minY = std::min(top, static_cast<T>(top + height));
+ T maxY = std::max(top, static_cast<T>(top + height));
+
+ return (x >= minX) && (x < maxX) && (y >= minY) && (y < maxY);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+bool Rect<T>::contains(const Vector2<T>& point) const
+{
+ return contains(point.x, point.y);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+bool Rect<T>::intersects(const Rect<T>& rectangle) const
+{
+ Rect<T> intersection;
+ return intersects(rectangle, intersection);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+bool Rect<T>::intersects(const Rect<T>& rectangle, Rect<T>& 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<T>(left + width));
+ T r1MaxX = std::max(left, static_cast<T>(left + width));
+ T r1MinY = std::min(top, static_cast<T>(top + height));
+ T r1MaxY = std::max(top, static_cast<T>(top + height));
+
+ // Compute the min and max of the second rectangle on both axes
+ T r2MinX = std::min(rectangle.left, static_cast<T>(rectangle.left + rectangle.width));
+ T r2MaxX = std::max(rectangle.left, static_cast<T>(rectangle.left + rectangle.width));
+ T r2MinY = std::min(rectangle.top, static_cast<T>(rectangle.top + rectangle.height));
+ T r2MaxY = std::max(rectangle.top, static_cast<T>(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<T>(interLeft, interTop, interRight - interLeft, interBottom - interTop);
+ return true;
+ }
+ else
+ {
+ intersection = Rect<T>(0, 0, 0, 0);
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator ==(const Rect<T>& left, const Rect<T>& right)
+{
+ return (left.left == right.left) && (left.width == right.width) &&
+ (left.top == right.top) && (left.height == right.height);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator !=(const Rect<T>& left, const Rect<T>& right)
+{
+ return !(left == right);
+}
diff --git a/include/SFML/Graphics/RectangleShape.hpp b/include/SFML/Graphics/RectangleShape.hpp
new file mode 100644
index 0000000..4f2c4d9
--- /dev/null
+++ b/include/SFML/Graphics/RectangleShape.hpp
@@ -0,0 +1,132 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Shape.hpp>
+
+
+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..9bcde9b
--- /dev/null
+++ b/include/SFML/Graphics/RenderStates.hpp
@@ -0,0 +1,174 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/BlendMode.hpp>
+#include <SFML/Graphics/Transform.hpp>
+
+
+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..0d16746
--- /dev/null
+++ b/include/SFML/Graphics/RenderTarget.hpp
@@ -0,0 +1,510 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/Graphics/View.hpp>
+#include <SFML/Graphics/Transform.hpp>
+#include <SFML/Graphics/BlendMode.hpp>
+#include <SFML/Graphics/RenderStates.hpp>
+#include <SFML/Graphics/PrimitiveType.hpp>
+#include <SFML/Graphics/Vertex.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+class Drawable;
+class VertexBuffer;
+
+////////////////////////////////////////////////////////////
+/// \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 Draw primitives defined by a vertex buffer
+ ///
+ /// \param vertexBuffer Vertex buffer
+ /// \param states Render states to use for drawing
+ ///
+ ////////////////////////////////////////////////////////////
+ void draw(const VertexBuffer& vertexBuffer, const RenderStates& states = RenderStates::Default);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Draw primitives defined by a vertex buffer
+ ///
+ /// \param vertexBuffer Vertex buffer
+ /// \param firstVertex Index of the first vertex to render
+ /// \param vertexCount Number of vertices to render
+ /// \param states Render states to use for drawing
+ ///
+ ////////////////////////////////////////////////////////////
+ void draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex, std::size_t vertexCount, 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 Activate or deactivate the render target for rendering
+ ///
+ /// This function makes the render target's context current for
+ /// future OpenGL rendering operations (so you shouldn't care
+ /// about it if you're not doing direct OpenGL stuff).
+ /// A render target's context 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 context can be current in a thread, so if you
+ /// want to draw OpenGL geometry to another render target
+ /// don't forget to activate it again. Activating a render
+ /// target will automatically deactivate the previously active
+ /// context (if any).
+ ///
+ /// \param active True to activate, false to deactivate
+ ///
+ /// \return True if operation was successful, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool setActive(bool active = true);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 Setup environment for drawing
+ ///
+ /// \param useVertexCache Are we going to use the vertex cache?
+ /// \param states Render states to use for drawing
+ ///
+ ////////////////////////////////////////////////////////////
+ void setupDraw(bool useVertexCache, const RenderStates& states);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Draw the primitives
+ ///
+ /// \param type Type of primitives to draw
+ /// \param firstVertex Index of the first vertex to use when drawing
+ /// \param vertexCount Number of vertices to use when drawing
+ ///
+ ////////////////////////////////////////////////////////////
+ void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clean up environment after drawing
+ ///
+ /// \param states Render states used for drawing
+ ///
+ ////////////////////////////////////////////////////////////
+ void cleanupDraw(const RenderStates& states);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Render states cache
+ ///
+ ////////////////////////////////////////////////////////////
+ struct StatesCache
+ {
+ enum {VertexCacheSize = 4};
+
+ bool enable; ///< Is the cache enabled?
+ 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 texCoordsArrayEnabled; ///< Is GL_TEXTURE_COORD_ARRAY client state enabled?
+ 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
+ Uint64 m_id; ///< Unique number that identifies the RenderTarget
+};
+
+} // 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..a26d94b
--- /dev/null
+++ b/include/SFML/Graphics/RenderTexture.hpp
@@ -0,0 +1,314 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+
+
+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
+ ///
+ /// \deprecated Use create(unsigned int, unsigned int, const ContextSettings&) instead.
+ ///
+ ////////////////////////////////////////////////////////////
+ SFML_DEPRECATED bool create(unsigned int width, unsigned int height, bool depthBuffer);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 settings, is useful if you want to enable
+ /// multi-sampling or use the render-texture for OpenGL rendering that
+ /// requires a depth or stencil buffer. Otherwise it is unnecessary, and
+ /// you should leave this parameter at its default value.
+ ///
+ /// \param width Width of the render-texture
+ /// \param height Height of the render-texture
+ /// \param settings Additional settings for the underlying OpenGL texture and context
+ ///
+ /// \return True if creation has been successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool create(unsigned int width, unsigned int height, const ContextSettings& settings = ContextSettings());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the maximum anti-aliasing level supported by the system
+ ///
+ /// \return The maximum anti-aliasing level supported by the system
+ ///
+ ////////////////////////////////////////////////////////////
+ static unsigned int getMaximumAntialiasingLevel();
+
+ ////////////////////////////////////////////////////////////
+ /// \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:
+
+ ////////////////////////////////////////////////////////////
+ // 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..2b3b6bc
--- /dev/null
+++ b/include/SFML/Graphics/RenderWindow.hpp
@@ -0,0 +1,284 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Window/Window.hpp>
+#include <string>
+
+
+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 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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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();
+};
+
+} // 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..664dd86
--- /dev/null
+++ b/include/SFML/Graphics/Shader.hpp
@@ -0,0 +1,875 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Glsl.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/Vector3.hpp>
+#include <map>
+#include <string>
+
+
+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<int, const Texture*> TextureTable;
+ typedef std::map<std::string, int> 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 RenderWindow::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..79ac528
--- /dev/null
+++ b/include/SFML/Graphics/Shape.hpp
@@ -0,0 +1,355 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Graphics/Transformable.hpp>
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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..55cc898
--- /dev/null
+++ b/include/SFML/Graphics/Sprite.hpp
@@ -0,0 +1,279 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Graphics/Transformable.hpp>
+#include <SFML/Graphics/Vertex.hpp>
+#include <SFML/Graphics/Rect.hpp>
+
+
+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..dae6ef2
--- /dev/null
+++ b/include/SFML/Graphics/Text.hpp
@@ -0,0 +1,513 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Graphics/Transformable.hpp>
+#include <SFML/Graphics/Font.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/System/String.hpp>
+#include <string>
+#include <vector>
+
+
+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 line spacing factor
+ ///
+ /// The default spacing between lines is defined by the font.
+ /// This method enables you to set a factor for the spacing
+ /// between lines. By default the line spacing factor is 1.
+ ///
+ /// \param spacingFactor New line spacing factor
+ ///
+ /// \see getLineSpacing
+ ///
+ ////////////////////////////////////////////////////////////
+ void setLineSpacing(float spacingFactor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the letter spacing factor
+ ///
+ /// The default spacing between letters is defined by the font.
+ /// This factor doesn't directly apply to the existing
+ /// spacing between each character, it rather adds a fixed
+ /// space between them which is calculated from the font
+ /// metrics and the character size.
+ /// Note that factors below 1 (including negative numbers) bring
+ /// characters closer to each other.
+ /// By default the letter spacing factor is 1.
+ ///
+ /// \param spacingFactor New letter spacing factor
+ ///
+ /// \see getLetterSpacing
+ ///
+ ////////////////////////////////////////////////////////////
+ void setLetterSpacing(float spacingFactor);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 size of the letter spacing factor
+ ///
+ /// \return Size of the letter spacing factor
+ ///
+ /// \see setLetterSpacing
+ ///
+ ////////////////////////////////////////////////////////////
+ float getLetterSpacing() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the size of the line spacing factor
+ ///
+ /// \return Size of the line spacing factor
+ ///
+ /// \see setLineSpacing
+ ///
+ ////////////////////////////////////////////////////////////
+ float getLineSpacing() 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
+ float m_letterSpacingFactor; ///< Spacing factor between letters
+ float m_lineSpacingFactor; ///< Spacing factor between lines
+ 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?
+ mutable Uint64 m_fontTextureId; ///< The font texture id
+};
+
+} // 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 and strike through), the
+/// text color, the outline thickness, the outline color, the character
+/// spacing, the line spacing 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.setFillColor(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..c292856
--- /dev/null
+++ b/include/SFML/Graphics/Texture.hpp
@@ -0,0 +1,733 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Window/GlResource.hpp>
+
+
+namespace sf
+{
+class InputStream;
+class RenderTarget;
+class RenderTexture;
+class Text;
+class Window;
+
+////////////////////////////////////////////////////////////
+/// \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 a part of this texture from another texture
+ ///
+ /// Although the source texture can be smaller than this 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 this texture.
+ ///
+ /// No additional check is performed on the size of the passed
+ /// texture, passing a texture bigger than this texture
+ /// will lead to an undefined behavior.
+ ///
+ /// This function does nothing if either texture was not
+ /// previously created.
+ ///
+ /// \param texture Source texture to copy to this texture
+ ///
+ ////////////////////////////////////////////////////////////
+ void update(const Texture& texture);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update a part of this texture from another texture
+ ///
+ /// No additional check is performed on the size of the texture,
+ /// passing an invalid combination of texture size and offset
+ /// will lead to an undefined behavior.
+ ///
+ /// This function does nothing if either texture was not
+ /// previously created.
+ ///
+ /// \param texture Source texture to copy to this texture
+ /// \param x X offset in this texture where to copy the source texture
+ /// \param y Y offset in this texture where to copy the source texture
+ ///
+ ////////////////////////////////////////////////////////////
+ void update(const Texture& texture, 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 Swap the contents of this texture with those of another
+ ///
+ /// \param right Instance to swap with
+ ///
+ ////////////////////////////////////////////////////////////
+ void swap(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 Text;
+ 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..c77d08a
--- /dev/null
+++ b/include/SFML/Graphics/Transform.hpp
@@ -0,0 +1,479 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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);
+
+////////////////////////////////////////////////////////////
+/// \relates sf::Transform
+/// \brief Overload of binary operator == to compare two transforms
+///
+/// Performs an element-wise comparison of the elements of the
+/// left transform with the elements of the right transform.
+///
+/// \param left Left operand (the first transform)
+/// \param right Right operand (the second transform)
+///
+/// \return true if the transforms are equal, false otherwise
+///
+////////////////////////////////////////////////////////////
+SFML_GRAPHICS_API bool operator ==(const Transform& left, const Transform& right);
+
+////////////////////////////////////////////////////////////
+/// \relates sf::Transform
+/// \brief Overload of binary operator != to compare two transforms
+///
+/// This call is equivalent to !(left == right).
+///
+/// \param left Left operand (the first transform)
+/// \param right Right operand (the second transform)
+///
+/// \return true if the transforms are not equal, false otherwise
+///
+////////////////////////////////////////////////////////////
+SFML_GRAPHICS_API bool operator !=(const Transform& left, const Transform& 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..67a5656
--- /dev/null
+++ b/include/SFML/Graphics/Transformable.hpp
@@ -0,0 +1,429 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Transform.hpp>
+
+
+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..bb24448
--- /dev/null
+++ b/include/SFML/Graphics/Vertex.hpp
@@ -0,0 +1,148 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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..5229065
--- /dev/null
+++ b/include/SFML/Graphics/VertexArray.hpp
@@ -0,0 +1,223 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Vertex.hpp>
+#include <SFML/Graphics/PrimitiveType.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <vector>
+
+
+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<Vertex> 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/VertexBuffer.hpp b/include/SFML/Graphics/VertexBuffer.hpp
new file mode 100644
index 0000000..a91a08f
--- /dev/null
+++ b/include/SFML/Graphics/VertexBuffer.hpp
@@ -0,0 +1,408 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_VERTEXBUFFER_HPP
+#define SFML_VERTEXBUFFER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/PrimitiveType.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Window/GlResource.hpp>
+
+
+namespace sf
+{
+class RenderTarget;
+class Vertex;
+
+////////////////////////////////////////////////////////////
+/// \brief Vertex buffer storage for one or more 2D primitives
+///
+////////////////////////////////////////////////////////////
+class SFML_GRAPHICS_API VertexBuffer : public Drawable, private GlResource
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Usage specifiers
+ ///
+ /// If data is going to be updated once or more every frame,
+ /// set the usage to Stream. If data is going to be set once
+ /// and used for a long time without being modified, set the
+ /// usage to Static. For everything else Dynamic should be a
+ /// good compromise.
+ ///
+ ////////////////////////////////////////////////////////////
+ enum Usage
+ {
+ Stream, ///< Constantly changing data
+ Dynamic, ///< Occasionally changing data
+ Static ///< Rarely changing data
+ };
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Creates an empty vertex buffer.
+ ///
+ ////////////////////////////////////////////////////////////
+ VertexBuffer();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct a VertexBuffer with a specific PrimitiveType
+ ///
+ /// Creates an empty vertex buffer and sets its primitive type to \p type.
+ ///
+ /// \param type Type of primitive
+ ///
+ ////////////////////////////////////////////////////////////
+ explicit VertexBuffer(PrimitiveType type);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct a VertexBuffer with a specific usage specifier
+ ///
+ /// Creates an empty vertex buffer and sets its usage to \p usage.
+ ///
+ /// \param usage Usage specifier
+ ///
+ ////////////////////////////////////////////////////////////
+ explicit VertexBuffer(Usage usage);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct a VertexBuffer with a specific PrimitiveType and usage specifier
+ ///
+ /// Creates an empty vertex buffer and sets its primitive type
+ /// to \p type and usage to \p usage.
+ ///
+ /// \param type Type of primitive
+ /// \param usage Usage specifier
+ ///
+ ////////////////////////////////////////////////////////////
+ VertexBuffer(PrimitiveType type, Usage usage);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Copy constructor
+ ///
+ /// \param copy instance to copy
+ ///
+ ////////////////////////////////////////////////////////////
+ VertexBuffer(const VertexBuffer& copy);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~VertexBuffer();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the vertex buffer
+ ///
+ /// Creates the vertex buffer and allocates enough graphics
+ /// memory to hold \p vertexCount vertices. Any previously
+ /// allocated memory is freed in the process.
+ ///
+ /// In order to deallocate previously allocated memory pass 0
+ /// as \p vertexCount. Don't forget to recreate with a non-zero
+ /// value when graphics memory should be allocated again.
+ ///
+ /// \param vertexCount Number of vertices worth of memory to allocate
+ ///
+ /// \return True if creation was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool create(std::size_t vertexCount);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Return the vertex count
+ ///
+ /// \return Number of vertices in the vertex buffer
+ ///
+ ////////////////////////////////////////////////////////////
+ std::size_t getVertexCount() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the whole buffer from an array of vertices
+ ///
+ /// The \a vertex array is assumed to have the same size as
+ /// the \a created buffer.
+ ///
+ /// No additional check is performed on the size of the vertex
+ /// array, passing invalid arguments will lead to undefined
+ /// behavior.
+ ///
+ /// This function does nothing if \a vertices is null or if the
+ /// buffer was not previously created.
+ ///
+ /// \param vertices Array of vertices to copy to the buffer
+ ///
+ /// \return True if the update was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool update(const Vertex* vertices);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update a part of the buffer from an array of vertices
+ ///
+ /// \p offset is specified as the number of vertices to skip
+ /// from the beginning of the buffer.
+ ///
+ /// If \p offset is 0 and \p vertexCount is equal to the size of
+ /// the currently created buffer, its whole contents are replaced.
+ ///
+ /// If \p offset is 0 and \p vertexCount is greater than the
+ /// size of the currently created buffer, a new buffer is created
+ /// containing the vertex data.
+ ///
+ /// If \p offset is 0 and \p vertexCount is less than the size of
+ /// the currently created buffer, only the corresponding region
+ /// is updated.
+ ///
+ /// If \p offset is not 0 and \p offset + \p vertexCount is greater
+ /// than the size of the currently created buffer, the update fails.
+ ///
+ /// No additional check is performed on the size of the vertex
+ /// array, passing invalid arguments will lead to undefined
+ /// behavior.
+ ///
+ /// \param vertices Array of vertices to copy to the buffer
+ /// \param vertexCount Number of vertices to copy
+ /// \param offset Offset in the buffer to copy to
+ ///
+ /// \return True if the update was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Copy the contents of another buffer into this buffer
+ ///
+ /// \param vertexBuffer Vertex buffer whose contents to copy into this vertex buffer
+ ///
+ /// \return True if the copy was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool update(const VertexBuffer& vertexBuffer);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Overload of assignment operator
+ ///
+ /// \param right Instance to assign
+ ///
+ /// \return Reference to self
+ ///
+ ////////////////////////////////////////////////////////////
+ VertexBuffer& operator =(const VertexBuffer& right);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Swap the contents of this vertex buffer with those of another
+ ///
+ /// \param right Instance to swap with
+ ///
+ ////////////////////////////////////////////////////////////
+ void swap(VertexBuffer& right);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the underlying OpenGL handle of the vertex buffer.
+ ///
+ /// 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 vertex buffer or 0 if not yet created
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getNativeHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the type of primitives to draw
+ ///
+ /// This function defines how the vertices must be interpreted
+ /// when it's time to draw them.
+ ///
+ /// 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 buffer
+ ///
+ /// \return Primitive type
+ ///
+ ////////////////////////////////////////////////////////////
+ PrimitiveType getPrimitiveType() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the usage specifier of this vertex buffer
+ ///
+ /// This function provides a hint about how this vertex buffer is
+ /// going to be used in terms of data update frequency.
+ ///
+ /// After changing the usage specifier, the vertex buffer has
+ /// to be updated with new data for the usage specifier to
+ /// take effect.
+ ///
+ /// The default primitive type is sf::VertexBuffer::Stream.
+ ///
+ /// \param usage Usage specifier
+ ///
+ ////////////////////////////////////////////////////////////
+ void setUsage(Usage usage);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the usage specifier of this vertex buffer
+ ///
+ /// \return Usage specifier
+ ///
+ ////////////////////////////////////////////////////////////
+ Usage getUsage() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Bind a vertex buffer 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::VertexBuffer with OpenGL code.
+ ///
+ /// \code
+ /// sf::VertexBuffer vb1, vb2;
+ /// ...
+ /// sf::VertexBuffer::bind(&vb1);
+ /// // draw OpenGL stuff that use vb1...
+ /// sf::VertexBuffer::bind(&vb2);
+ /// // draw OpenGL stuff that use vb2...
+ /// sf::VertexBuffer::bind(NULL);
+ /// // draw OpenGL stuff that use no vertex buffer...
+ /// \endcode
+ ///
+ /// \param vertexBuffer Pointer to the vertex buffer to bind, can be null to use no vertex buffer
+ ///
+ ////////////////////////////////////////////////////////////
+ static void bind(const VertexBuffer* vertexBuffer);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Tell whether or not the system supports vertex buffers
+ ///
+ /// This function should always be called before using
+ /// the vertex buffer features. If it returns false, then
+ /// any attempt to use sf::VertexBuffer will fail.
+ ///
+ /// \return True if vertex buffers are supported, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Draw the vertex buffer 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
+ ////////////////////////////////////////////////////////////
+ unsigned int m_buffer; ///< Internal buffer identifier
+ std::size_t m_size; ///< Size in Vertexes of the currently allocated buffer
+ PrimitiveType m_primitiveType; ///< Type of primitives to draw
+ Usage m_usage; ///< How this vertex buffer is to be used
+};
+
+} // namespace sf
+
+
+#endif // SFML_VERTEXBUFFER_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class sf::VertexBuffer
+/// \ingroup graphics
+///
+/// sf::VertexBuffer is a simple wrapper around a dynamic
+/// buffer of vertices and a primitives type.
+///
+/// Unlike sf::VertexArray, the vertex data is stored in
+/// graphics memory.
+///
+/// In situations where a large amount of vertex data would
+/// have to be transferred from system memory to graphics memory
+/// every frame, using sf::VertexBuffer can help. By using a
+/// sf::VertexBuffer, data that has not been changed between frames
+/// does not have to be re-transferred from system to graphics
+/// memory as would be the case with sf::VertexArray. If data transfer
+/// is a bottleneck, this can lead to performance gains.
+///
+/// Using sf::VertexBuffer, the user also has the ability to only modify
+/// a portion of the buffer in graphics memory. This way, a large buffer
+/// can be allocated at the start of the application and only the
+/// applicable portions of it need to be updated during the course of
+/// the application. This allows the user to take full control of data
+/// transfers between system and graphics memory if they need to.
+///
+/// In special cases, the user can make use of multiple threads to update
+/// vertex data in multiple distinct regions of the buffer simultaneously.
+/// This might make sense when e.g. the position of multiple objects has to
+/// be recalculated very frequently. The computation load can be spread
+/// across multiple threads as long as there are no other data dependencies.
+///
+/// Simultaneous updates to the vertex buffer are not guaranteed to be
+/// carried out by the driver in any specific order. Updating the same
+/// region of the buffer from multiple threads will not cause undefined
+/// behaviour, however the final state of the buffer will be unpredictable.
+///
+/// Simultaneous updates of distinct non-overlapping regions of the buffer
+/// are also not guaranteed to complete in a specific order. However, in
+/// this case the user can make sure to synchronize the writer threads at
+/// well-defined points in their code. The driver will make sure that all
+/// pending data transfers complete before the vertex buffer is sourced
+/// by the rendering pipeline.
+///
+/// It inherits sf::Drawable, but unlike other drawables it
+/// is not transformable.
+///
+/// Example:
+/// \code
+/// sf::Vertex vertices[15];
+/// ...
+/// sf::VertexBuffer triangles(sf::Triangles);
+/// triangles.create(15);
+/// triangles.update(vertices);
+/// ...
+/// window.draw(triangles);
+/// \endcode
+///
+/// \see sf::Vertex, sf::VertexArray
+///
+////////////////////////////////////////////////////////////
diff --git a/include/SFML/Graphics/View.hpp b/include/SFML/Graphics/View.hpp
new file mode 100644
index 0000000..a3faa6e
--- /dev/null
+++ b/include/SFML/Graphics/View.hpp
@@ -0,0 +1,343 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Graphics/Export.hpp>
+#include <SFML/Graphics/Rect.hpp>
+#include <SFML/Graphics/Transform.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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..c28a7e1
--- /dev/null
+++ b/include/SFML/Main.hpp
@@ -0,0 +1,43 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+#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..ccc9f7c
--- /dev/null
+++ b/include/SFML/Network.hpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System.hpp>
+#include <SFML/Network/Ftp.hpp>
+#include <SFML/Network/Http.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/Socket.hpp>
+#include <SFML/Network/SocketHandle.hpp>
+#include <SFML/Network/SocketSelector.hpp>
+#include <SFML/Network/TcpListener.hpp>
+#include <SFML/Network/TcpSocket.hpp>
+#include <SFML/Network/UdpSocket.hpp>
+
+
+#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..e7ebdd4
--- /dev/null
+++ b/include/SFML/Network/Export.hpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+// 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..ee779cc
--- /dev/null
+++ b/include/SFML/Network/Ftp.hpp
@@ -0,0 +1,616 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/TcpSocket.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Time.hpp>
+#include <string>
+#include <vector>
+
+
+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<std::string>& getListing() const;
+
+ private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ std::vector<std::string> 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.
+ ///
+ /// The append parameter controls whether the remote file is
+ /// appended to or overwritten if it already exists.
+ ///
+ /// \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
+ /// \param append Pass true to append to or false to overwrite the remote file if it already exists
+ ///
+ /// \return Server response to the request
+ ///
+ /// \see download
+ ///
+ ////////////////////////////////////////////////////////////
+ Response upload(const std::string& localFile, const std::string& remotePath, TransferMode mode = Binary, bool append = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \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..44fe67d
--- /dev/null
+++ b/include/SFML/Network/Http.hpp
@@ -0,0 +1,482 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/Network/TcpSocket.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Time.hpp>
+#include <map>
+#include <string>
+
+
+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<std::string, std::string> 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<std::string, std::string> 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..9ec13c4
--- /dev/null
+++ b/include/SFML/Network/IpAddress.hpp
@@ -0,0 +1,328 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/System/Time.hpp>
+#include <istream>
+#include <ostream>
+#include <string>
+
+
+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..9f0edab
--- /dev/null
+++ b/include/SFML/Network/Packet.hpp
@@ -0,0 +1,532 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <string>
+#include <vector>
+
+
+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;
+
+ ////////////////////////////////////////////////////////////
+ /// Overload of operator >> to read data from the packet
+ ///
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(bool& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Int8& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Uint8& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Int16& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Uint16& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Int32& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Uint32& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Int64& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(Uint64& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(float& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(double& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(char* data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(std::string& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(wchar_t* data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(std::wstring& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator >>(String& data);
+
+ ////////////////////////////////////////////////////////////
+ /// Overload of operator << to write data into the packet
+ ///
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(bool data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Int8 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Uint8 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Int16 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Uint16 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Int32 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Uint32 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Int64 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(Uint64 data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(float data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(double data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(const char* data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(const std::string& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(const wchar_t* data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ Packet& operator <<(const std::wstring& data);
+
+ ////////////////////////////////////////////////////////////
+ /// \overload
+ ////////////////////////////////////////////////////////////
+ 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<char> 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..d260174
--- /dev/null
+++ b/include/SFML/Network/Socket.hpp
@@ -0,0 +1,219 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/SocketHandle.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <vector>
+
+
+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..270201b
--- /dev/null
+++ b/include/SFML/Network/SocketHandle.hpp
@@ -0,0 +1,57 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <basetsd.h>
+#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..106d708
--- /dev/null
+++ b/include/SFML/Network/SocketSelector.hpp
@@ -0,0 +1,263 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/System/Time.hpp>
+
+
+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<sf::TcpSocket*> 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<sf::TcpSocket*>::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..e0e05d6
--- /dev/null
+++ b/include/SFML/Network/TcpListener.hpp
@@ -0,0 +1,166 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/Socket.hpp>
+#include <SFML/Network/IpAddress.hpp>
+
+
+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 incoming connection attempts
+ ///
+ /// This function makes the socket start listening on the
+ /// specified port, waiting for incoming connection attempts.
+ ///
+ /// If the socket is already listening on a port when this
+ /// function is called, it will stop listening on the old
+ /// port before starting to listen on the new port.
+ ///
+ /// \param port Port to listen on for incoming connection attempts
+ /// \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..6c0ab98
--- /dev/null
+++ b/include/SFML/Network/TcpSocket.hpp
@@ -0,0 +1,316 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/Socket.hpp>
+#include <SFML/System/Time.hpp>
+
+
+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 is already connected, the connection is
+ /// forcibly disconnected before attempting to connect again.
+ ///
+ /// \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<char> 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..7ce3fe5
--- /dev/null
+++ b/include/SFML/Network/UdpSocket.hpp
@@ -0,0 +1,291 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Network/Export.hpp>
+#include <SFML/Network/Socket.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <vector>
+
+
+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.
+ ///
+ /// Since the socket can only be bound to a single port at
+ /// any given moment, if it is already bound when this
+ /// function is called, it will be unbound from the previous
+ /// port before being bound to the new one.
+ ///
+ /// \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<char> 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..6db5d01
--- /dev/null
+++ b/include/SFML/OpenGL.hpp
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+/// 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 <windows.h>
+ #endif
+
+ #include <GL/gl.h>
+
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+
+ #if defined(SFML_OPENGL_ES)
+ #include <GLES/gl.h>
+ #include <GLES/glext.h>
+ #else
+ #include <GL/gl.h>
+ #endif
+
+#elif defined(SFML_SYSTEM_MACOS)
+
+ #include <OpenGL/gl.h>
+
+#elif defined (SFML_SYSTEM_IOS)
+
+ #include <OpenGLES/ES1/gl.h>
+ #include <OpenGLES/ES1/glext.h>
+
+#elif defined (SFML_SYSTEM_ANDROID)
+
+ #include <GLES/gl.h>
+ #include <GLES/glext.h>
+
+ // We're not using OpenGL ES 2+ yet, but we can use the sRGB extension
+ #include <GLES2/gl2platform.h>
+ #include <GLES2/gl2ext.h>
+
+#endif
+
+
+#endif // SFML_OPENGL_HPP
diff --git a/include/SFML/System.hpp b/include/SFML/System.hpp
new file mode 100644
index 0000000..fa4f9c9
--- /dev/null
+++ b/include/SFML/System.hpp
@@ -0,0 +1,60 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <SFML/System/Clock.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/FileInputStream.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/MemoryInputStream.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/String.hpp>
+#include <SFML/System/Thread.hpp>
+#include <SFML/System/ThreadLocal.hpp>
+#include <SFML/System/ThreadLocalPtr.hpp>
+#include <SFML/System/Time.hpp>
+#include <SFML/System/Utf.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/Vector3.hpp>
+
+#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..391e2c4
--- /dev/null
+++ b/include/SFML/System/Clock.hpp
@@ -0,0 +1,117 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/Time.hpp>
+
+
+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..a701fef
--- /dev/null
+++ b/include/SFML/System/Err.hpp
@@ -0,0 +1,80 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <ostream>
+
+
+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..e9c8ef8
--- /dev/null
+++ b/include/SFML/System/Export.hpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+// 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..ca26797
--- /dev/null
+++ b/include/SFML/System/FileInputStream.hpp
@@ -0,0 +1,169 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <SFML/System/Export.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <cstdio>
+#include <string>
+
+#ifdef SFML_SYSTEM_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 SFML_SYSTEM_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..495a4b9
--- /dev/null
+++ b/include/SFML/System/InputStream.hpp
@@ -0,0 +1,152 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <SFML/System/Export.hpp>
+
+
+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..906016c
--- /dev/null
+++ b/include/SFML/System/Lock.hpp
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+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..4b7f9ef
--- /dev/null
+++ b/include/SFML/System/MemoryInputStream.hpp
@@ -0,0 +1,148 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Export.hpp>
+#include <cstdlib>
+
+
+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..eda6909
--- /dev/null
+++ b/include/SFML/System/Mutex.hpp
@@ -0,0 +1,148 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+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..e8a3b17
--- /dev/null
+++ b/include/SFML/System/NativeActivity.hpp
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+
+
+#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..dbe1eeb
--- /dev/null
+++ b/include/SFML/System/NonCopyable.hpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+
+
+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() {}
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default destructor
+ ///
+ /// By declaring a protected destructor it's impossible to
+ /// call delete on a pointer of sf::NonCopyable, thus
+ /// preventing possible resource leaks.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~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..ac3144b
--- /dev/null
+++ b/include/SFML/System/Sleep.hpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/Time.hpp>
+
+
+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..5d047e2
--- /dev/null
+++ b/include/SFML/System/String.hpp
@@ -0,0 +1,669 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/Utf.hpp>
+#include <iterator>
+#include <locale>
+#include <string>
+
+
+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<Uint32>::iterator Iterator; ///< Iterator type
+ typedef std::basic_string<Uint32>::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<Uint32>& 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 <typename T>
+ 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 <typename T>
+ 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<sf::Uint32>.
+ ///
+ /// \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 <typename T>
+ 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<Uint8> toUtf8() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert the Unicode string to a UTF-16 string
+ ///
+ /// \return Converted UTF-16 string
+ ///
+ /// \see toUtf8, toUtf32
+ ///
+ ////////////////////////////////////////////////////////////
+ std::basic_string<Uint16> 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<Uint32> 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<Uint32> 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 <SFML/System/String.inl>
+
+} // 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..b8893e7
--- /dev/null
+++ b/include/SFML/System/String.inl
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+String String::fromUtf8(T begin, T end)
+{
+ String string;
+ Utf8::toUtf32(begin, end, std::back_inserter(string.m_string));
+ return string;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+String String::fromUtf16(T begin, T end)
+{
+ String string;
+ Utf16::toUtf32(begin, end, std::back_inserter(string.m_string));
+ return string;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+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..15ae4a5
--- /dev/null
+++ b/include/SFML/System/Thread.hpp
@@ -0,0 +1,282 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <cstdlib>
+
+
+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 <typename F>
+ 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 <typename F, typename A>
+ 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 <typename C>
+ 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 <SFML/System/Thread.inl>
+
+} // 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..1f2e8de
--- /dev/null
+++ b/include/SFML/System/Thread.inl
@@ -0,0 +1,90 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+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 <typename F, typename A>
+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 <typename C>
+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 <typename F>
+Thread::Thread(F functor) :
+m_impl (NULL),
+m_entryPoint(new priv::ThreadFunctor<F>(functor))
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename F, typename A>
+Thread::Thread(F function, A argument) :
+m_impl (NULL),
+m_entryPoint(new priv::ThreadFunctorWithArg<F, A>(function, argument))
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename C>
+Thread::Thread(void(C::*function)(), C* object) :
+m_impl (NULL),
+m_entryPoint(new priv::ThreadMemberFunc<C>(function, object))
+{
+}
diff --git a/include/SFML/System/ThreadLocal.hpp b/include/SFML/System/ThreadLocal.hpp
new file mode 100644
index 0000000..1ace1ba
--- /dev/null
+++ b/include/SFML/System/ThreadLocal.hpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <cstdlib>
+
+
+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..bee944d
--- /dev/null
+++ b/include/SFML/System/ThreadLocalPtr.hpp
@@ -0,0 +1,158 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/ThreadLocal.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// \brief Pointer to a thread-local variable
+///
+////////////////////////////////////////////////////////////
+template <typename T>
+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<T>& operator =(T* value);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Assignment operator for a ThreadLocalPtr parameter
+ ///
+ /// \param right ThreadLocalPtr to assign
+ ///
+ /// \return Reference to self
+ ///
+ ////////////////////////////////////////////////////////////
+ ThreadLocalPtr<T>& operator =(const ThreadLocalPtr<T>& right);
+};
+
+} // namespace sf
+
+#include <SFML/System/ThreadLocalPtr.inl>
+
+
+#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<MyClass> 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..12c7690
--- /dev/null
+++ b/include/SFML/System/ThreadLocalPtr.inl
@@ -0,0 +1,77 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+ThreadLocalPtr<T>::ThreadLocalPtr(T* value) :
+ThreadLocal(value)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+T& ThreadLocalPtr<T>::operator *() const
+{
+ return *static_cast<T*>(getValue());
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+T* ThreadLocalPtr<T>::operator ->() const
+{
+ return static_cast<T*>(getValue());
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+ThreadLocalPtr<T>::operator T*() const
+{
+ return static_cast<T*>(getValue());
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+ThreadLocalPtr<T>& ThreadLocalPtr<T>::operator =(T* value)
+{
+ setValue(value);
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+ThreadLocalPtr<T>& ThreadLocalPtr<T>::operator =(const ThreadLocalPtr<T>& 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..43d7548
--- /dev/null
+++ b/include/SFML/System/Time.hpp
@@ -0,0 +1,488 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System/Export.hpp>
+
+
+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..e1e78f6
--- /dev/null
+++ b/include/SFML/System/Utf.hpp
@@ -0,0 +1,763 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <algorithm>
+#include <locale>
+#include <string>
+#include <cstdlib>
+
+
+namespace sf
+{
+template <unsigned int N>
+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 <typename In>
+ 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 <typename Out>
+ 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 <typename In>
+ 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 <typename In>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In>
+ 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 <typename Out>
+ 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 <typename In>
+ 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 <typename In>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In>
+ 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 <typename Out>
+ 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 <typename In>
+ 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 <typename In>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In, typename Out>
+ 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 <typename In>
+ 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 <typename In>
+ 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 <typename Out>
+ 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 <typename Out>
+ static Out encodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0);
+};
+
+#include <SFML/System/Utf.inl>
+
+// 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<X> 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..67fad8b
--- /dev/null
+++ b/include/SFML/System/Utf.inl
@@ -0,0 +1,752 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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:
+//
+// https://www.unicode.org/
+// https://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
+// https://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h
+// https://people.w3.org/rishida/scripts/uniview/conversion
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+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<Uint8>(*begin)];
+ if (begin + trailingBytes < end)
+ {
+ output = 0;
+ switch (trailingBytes)
+ {
+ case 5: output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 4: output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 3: output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 2: output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 1: output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 0: output += static_cast<Uint8>(*begin++);
+ }
+ output -= offsets[trailingBytes];
+ }
+ else
+ {
+ // Incomplete character
+ begin = end;
+ output = replacement;
+ }
+
+ return begin;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename Out>
+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<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 3: bytes[2] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 2: bytes[1] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 1: bytes[0] = static_cast<Uint8> (input | firstBytes[bytestoWrite]);
+ }
+
+ // Add them to the output
+ output = std::copy(bytes, bytes + bytestoWrite, output);
+ }
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+In Utf<8>::next(In begin, In end)
+{
+ Uint32 codepoint;
+ return decode(begin, end, codepoint);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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<char>(codepoint) : replacement;
+ }
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<8>::toUtf8(In begin, In end, Out output)
+{
+ return std::copy(begin, end, output);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In>
+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<Uint32>(((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 <typename Out>
+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<Uint16>(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<Uint16>((input >> 10) + 0xD800);
+ *output++ = static_cast<Uint16>((input & 0x3FFUL) + 0xDC00);
+ }
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+In Utf<16>::next(In begin, In end)
+{
+ Uint32 codepoint;
+ return decode(begin, end, codepoint);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+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<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+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 <typename In, typename Out>
+Out Utf<16>::toUtf16(In begin, In end, Out output)
+{
+ return std::copy(begin, end, output);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+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 <typename In>
+In Utf<32>::decode(In begin, In /*end*/, Uint32& output, Uint32 /*replacement*/)
+{
+ output = *begin++;
+ return begin;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename Out>
+Out Utf<32>::encode(Uint32 input, Out output, Uint32 /*replacement*/)
+{
+ *output++ = input;
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+In Utf<32>::next(In begin, In /*end*/)
+{
+ return ++begin;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+std::size_t Utf<32>::count(In begin, In end)
+{
+ return begin - end;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<32>::fromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ *output++ = decodeAnsi(*begin++, locale);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<32>::fromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = decodeWide(*begin++);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+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 <typename In, typename Out>
+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 <typename In, typename Out>
+Out Utf<32>::toWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ output = encodeWide(*begin++, output, replacement);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+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<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<32>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<8>::encode(*begin++, output);
+
+ return output;
+}
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<32>::toUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<16>::encode(*begin++, output);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In, typename Out>
+Out Utf<32>::toUtf32(In begin, In end, Out output)
+{
+ return std::copy(begin, end, output);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+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<Uint32>(character);
+
+ #else
+
+ // Get the facet of the locale which deals with character conversion
+ const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+
+ // Use the facet to convert each character of the input string
+ return static_cast<Uint32>(facet.widen(input));
+
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename In>
+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 <typename Out>
+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<wchar_t>(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<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+
+ // Use the facet to convert each character of the input string
+ *output++ = facet.narrow(static_cast<wchar_t>(codepoint), replacement);
+
+ return output;
+
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename Out>
+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<wchar_t>(codepoint);
+ break;
+ }
+
+ default:
+ {
+ if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF)))
+ {
+ *output++ = static_cast<wchar_t>(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..237f214
--- /dev/null
+++ b/include/SFML/System/Vector2.hpp
@@ -0,0 +1,301 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+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 <typename U>
+ explicit Vector2(const Vector2<U>& 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 <typename T>
+Vector2<T> operator -(const Vector2<T>& 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 <typename T>
+Vector2<T>& operator +=(Vector2<T>& left, const Vector2<T>& 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 <typename T>
+Vector2<T>& operator -=(Vector2<T>& left, const Vector2<T>& 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 <typename T>
+Vector2<T> operator +(const Vector2<T>& left, const Vector2<T>& 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 <typename T>
+Vector2<T> operator -(const Vector2<T>& left, const Vector2<T>& 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 <typename T>
+Vector2<T> operator *(const Vector2<T>& 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 <typename T>
+Vector2<T> operator *(T left, const Vector2<T>& 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 <typename T>
+Vector2<T>& operator *=(Vector2<T>& 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 <typename T>
+Vector2<T> operator /(const Vector2<T>& 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 <typename T>
+Vector2<T>& operator /=(Vector2<T>& 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 <typename T>
+bool operator ==(const Vector2<T>& left, const Vector2<T>& 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 <typename T>
+bool operator !=(const Vector2<T>& left, const Vector2<T>& right);
+
+#include <SFML/System/Vector2.inl>
+
+// Define the most common types
+typedef Vector2<int> Vector2i;
+typedef Vector2<unsigned int> Vector2u;
+typedef Vector2<float> 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<T>),
+/// the most common specializations have special typedefs:
+/// \li sf::Vector2<float> is sf::Vector2f
+/// \li sf::Vector2<int> is sf::Vector2i
+/// \li sf::Vector2<unsigned int> 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..29ad76f
--- /dev/null
+++ b/include/SFML/System/Vector2.inl
@@ -0,0 +1,161 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+inline Vector2<T>::Vector2() :
+x(0),
+y(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T>::Vector2(T X, T Y) :
+x(X),
+y(Y)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+template <typename U>
+inline Vector2<T>::Vector2(const Vector2<U>& vector) :
+x(static_cast<T>(vector.x)),
+y(static_cast<T>(vector.y))
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator -(const Vector2<T>& right)
+{
+ return Vector2<T>(-right.x, -right.y);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T>& operator +=(Vector2<T>& left, const Vector2<T>& right)
+{
+ left.x += right.x;
+ left.y += right.y;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T>& operator -=(Vector2<T>& left, const Vector2<T>& right)
+{
+ left.x -= right.x;
+ left.y -= right.y;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator +(const Vector2<T>& left, const Vector2<T>& right)
+{
+ return Vector2<T>(left.x + right.x, left.y + right.y);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator -(const Vector2<T>& left, const Vector2<T>& right)
+{
+ return Vector2<T>(left.x - right.x, left.y - right.y);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator *(const Vector2<T>& left, T right)
+{
+ return Vector2<T>(left.x * right, left.y * right);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator *(T left, const Vector2<T>& right)
+{
+ return Vector2<T>(right.x * left, right.y * left);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T>& operator *=(Vector2<T>& left, T right)
+{
+ left.x *= right;
+ left.y *= right;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T> operator /(const Vector2<T>& left, T right)
+{
+ return Vector2<T>(left.x / right, left.y / right);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector2<T>& operator /=(Vector2<T>& left, T right)
+{
+ left.x /= right;
+ left.y /= right;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator ==(const Vector2<T>& left, const Vector2<T>& right)
+{
+ return (left.x == right.x) && (left.y == right.y);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator !=(const Vector2<T>& left, const Vector2<T>& 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..b12b2f5
--- /dev/null
+++ b/include/SFML/System/Vector3.hpp
@@ -0,0 +1,302 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+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 <typename U>
+ explicit Vector3(const Vector3<U>& 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 <typename T>
+Vector3<T> operator -(const Vector3<T>& 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 <typename T>
+Vector3<T>& operator +=(Vector3<T>& left, const Vector3<T>& 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 <typename T>
+Vector3<T>& operator -=(Vector3<T>& left, const Vector3<T>& 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 <typename T>
+Vector3<T> operator +(const Vector3<T>& left, const Vector3<T>& 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 <typename T>
+Vector3<T> operator -(const Vector3<T>& left, const Vector3<T>& 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 <typename T>
+Vector3<T> operator *(const Vector3<T>& 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 <typename T>
+Vector3<T> operator *(T left, const Vector3<T>& 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 <typename T>
+Vector3<T>& operator *=(Vector3<T>& 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 <typename T>
+Vector3<T> operator /(const Vector3<T>& 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 <typename T>
+Vector3<T>& operator /=(Vector3<T>& 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 <typename T>
+bool operator ==(const Vector3<T>& left, const Vector3<T>& 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 <typename T>
+bool operator !=(const Vector3<T>& left, const Vector3<T>& right);
+
+#include <SFML/System/Vector3.inl>
+
+// Define the most common types
+typedef Vector3<int> Vector3i;
+typedef Vector3<float> 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<T>),
+/// the most common specializations have special typedefs:
+/// \li sf::Vector3<float> is sf::Vector3f
+/// \li sf::Vector3<int> 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..b532fe0
--- /dev/null
+++ b/include/SFML/System/Vector3.inl
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <typename T>
+inline Vector3<T>::Vector3() :
+x(0),
+y(0),
+z(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T>::Vector3(T X, T Y, T Z) :
+x(X),
+y(Y),
+z(Z)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+template <typename U>
+inline Vector3<T>::Vector3(const Vector3<U>& vector) :
+x(static_cast<T>(vector.x)),
+y(static_cast<T>(vector.y)),
+z(static_cast<T>(vector.z))
+{
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator -(const Vector3<T>& left)
+{
+ return Vector3<T>(-left.x, -left.y, -left.z);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T>& operator +=(Vector3<T>& left, const Vector3<T>& right)
+{
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T>& operator -=(Vector3<T>& left, const Vector3<T>& right)
+{
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator +(const Vector3<T>& left, const Vector3<T>& right)
+{
+ return Vector3<T>(left.x + right.x, left.y + right.y, left.z + right.z);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator -(const Vector3<T>& left, const Vector3<T>& right)
+{
+ return Vector3<T>(left.x - right.x, left.y - right.y, left.z - right.z);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator *(const Vector3<T>& left, T right)
+{
+ return Vector3<T>(left.x * right, left.y * right, left.z * right);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator *(T left, const Vector3<T>& right)
+{
+ return Vector3<T>(right.x * left, right.y * left, right.z * left);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T>& operator *=(Vector3<T>& left, T right)
+{
+ left.x *= right;
+ left.y *= right;
+ left.z *= right;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T> operator /(const Vector3<T>& left, T right)
+{
+ return Vector3<T>(left.x / right, left.y / right, left.z / right);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline Vector3<T>& operator /=(Vector3<T>& left, T right)
+{
+ left.x /= right;
+ left.y /= right;
+ left.z /= right;
+
+ return left;
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator ==(const Vector3<T>& left, const Vector3<T>& right)
+{
+ return (left.x == right.x) && (left.y == right.y) && (left.z == right.z);
+}
+
+
+////////////////////////////////////////////////////////////
+template <typename T>
+inline bool operator !=(const Vector3<T>& left, const Vector3<T>& 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..836f13a
--- /dev/null
+++ b/include/SFML/Window.hpp
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/System.hpp>
+#include <SFML/Window/Clipboard.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+#include <SFML/Window/Sensor.hpp>
+#include <SFML/Window/Touch.hpp>
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/Window.hpp>
+#include <SFML/Window/WindowHandle.hpp>
+#include <SFML/Window/WindowStyle.hpp>
+
+
+
+#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/Clipboard.hpp b/include/SFML/Window/Clipboard.hpp
new file mode 100644
index 0000000..50ea804
--- /dev/null
+++ b/include/SFML/Window/Clipboard.hpp
@@ -0,0 +1,119 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARD_HPP
+#define SFML_CLIPBOARD_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Export.hpp>
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class SFML_WINDOW_API Clipboard
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Clipboard contents as sf::String object
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \warning Due to limitations on some operating systems,
+ /// setting the clipboard contents is only
+ /// guaranteed to work if there is currently an
+ /// open window for which events are being handled.
+ ///
+ /// \param text sf::String containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+};
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARD_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class sf::Clipboard
+/// \ingroup window
+///
+/// sf::Clipboard provides an interface for getting and
+/// setting the contents of the system clipboard.
+///
+/// It is important to note that due to limitations on some
+/// operating systems, setting the clipboard contents is
+/// only guaranteed to work if there is currently an open
+/// window for which events are being handled.
+///
+/// Usage example:
+/// \code
+/// // get the clipboard content as a string
+/// sf::String string = sf::Clipboard::getString();
+///
+/// // or use it in the event loop
+/// sf::Event event;
+/// while(window.pollEvent(event))
+/// {
+/// if(event.type == sf::Event::Closed)
+/// window.close();
+/// if(event.type == sf::Event::KeyPressed)
+/// {
+/// // Using Ctrl + V to paste a string into SFML
+/// if(event.key.control && event.key.code == sf::Keyboard::V)
+/// string = sf::Clipboard::getString();
+///
+/// // Using Ctrl + C to copy a string out of SFML
+/// if(event.key.control && event.key.code == sf::Keyboard::C)
+/// sf::Clipboard::setString("Hello World!");
+/// }
+/// }
+/// \endcode
+///
+/// \see sf::String, sf::Event
+///
+////////////////////////////////////////////////////////////
diff --git a/include/SFML/Window/Context.hpp b/include/SFML/Window/Context.hpp
new file mode 100644
index 0000000..71e2c0a
--- /dev/null
+++ b/include/SFML/Window/Context.hpp
@@ -0,0 +1,195 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+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
+ ///
+ /// This function will only return sf::Context objects.
+ /// Contexts created e.g. by RenderTargets or for internal
+ /// use will not be returned by this function.
+ ///
+ /// \return The currently active context or NULL if none is active
+ ///
+ ////////////////////////////////////////////////////////////
+ static const Context* getActiveContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the currently active context's ID
+ ///
+ /// The context ID is used to identify contexts when
+ /// managing unshareable OpenGL resources.
+ ///
+ /// \return The active context's ID or 0 if no context is currently active
+ ///
+ ////////////////////////////////////////////////////////////
+ static Uint64 getActiveContextId();
+
+ ////////////////////////////////////////////////////////////
+ /// \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..00afbc4
--- /dev/null
+++ b/include/SFML/Window/ContextSettings.hpp
@@ -0,0 +1,149 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+
+#include <SFML/Config.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.
+/// <b>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.</b>
+///
+/// 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.
+///
+/// <b>Special Note for OS X:</b>
+/// 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
+/// <a href="https://developer.apple.com/opengl/capabilities/index.html">
+/// OpenGL Capabilities Tables</a> 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/Cursor.hpp b/include/SFML/Window/Cursor.hpp
new file mode 100644
index 0000000..9daa13b
--- /dev/null
+++ b/include/SFML/Window/Cursor.hpp
@@ -0,0 +1,222 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSOR_HPP
+#define SFML_CURSOR_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+
+namespace sf
+{
+namespace priv
+{
+ class CursorImpl;
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Cursor defines the appearance of a system cursor
+///
+////////////////////////////////////////////////////////////
+class SFML_WINDOW_API Cursor : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enumeration of the native system cursor types
+ ///
+ /// Refer to the following table to determine which cursor
+ /// is available on which platform.
+ ///
+ /// Type | Linux | Mac OS X | Windows |
+ /// ------------------------------------|:-----:|:--------:|:--------:|
+ /// sf::Cursor::Arrow | yes | yes | yes |
+ /// sf::Cursor::ArrowWait | no | no | yes |
+ /// sf::Cursor::Wait | yes | no | yes |
+ /// sf::Cursor::Text | yes | yes | yes |
+ /// sf::Cursor::Hand | yes | yes | yes |
+ /// sf::Cursor::SizeHorizontal | yes | yes | yes |
+ /// sf::Cursor::SizeVertical | yes | yes | yes |
+ /// sf::Cursor::SizeTopLeftBottomRight | no | yes* | yes |
+ /// sf::Cursor::SizeBottomLeftTopRight | no | yes* | yes |
+ /// sf::Cursor::SizeAll | yes | no | yes |
+ /// sf::Cursor::Cross | yes | yes | yes |
+ /// sf::Cursor::Help | yes | yes* | yes |
+ /// sf::Cursor::NotAllowed | yes | yes | yes |
+ ///
+ /// * These cursor types are undocumented so may not
+ /// be available on all versions, but have been tested on 10.13
+ ///
+ ////////////////////////////////////////////////////////////
+ enum Type
+ {
+ Arrow, ///< Arrow cursor (default)
+ ArrowWait, ///< Busy arrow cursor
+ Wait, ///< Busy cursor
+ Text, ///< I-beam, cursor when hovering over a field allowing text entry
+ Hand, ///< Pointing hand cursor
+ SizeHorizontal, ///< Horizontal double arrow cursor
+ SizeVertical, ///< Vertical double arrow cursor
+ SizeTopLeftBottomRight, ///< Double arrow cursor going from top-left to bottom-right
+ SizeBottomLeftTopRight, ///< Double arrow cursor going from bottom-left to top-right
+ SizeAll, ///< Combination of SizeHorizontal and SizeVertical
+ Cross, ///< Crosshair cursor
+ Help, ///< Help cursor
+ NotAllowed ///< Action not allowed cursor
+ };
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// This constructor doesn't actually create the cursor;
+ /// initially the new instance is invalid and must not be
+ /// used until either loadFromPixels() or loadFromSystem()
+ /// is called and successfully created a cursor.
+ ///
+ ////////////////////////////////////////////////////////////
+ Cursor();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// This destructor releases the system resources
+ /// associated with this cursor, if any.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~Cursor();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// \a pixels must be an array of \a width by \a height pixels
+ /// in 32-bit RGBA format. If not, this will cause undefined behavior.
+ ///
+ /// If \a pixels is null or either \a width or \a height are 0,
+ /// the current cursor is left unchanged and the function will
+ /// return false.
+ ///
+ /// In addition to specifying the pixel data, you can also
+ /// specify the location of the hotspot of the cursor. The
+ /// hotspot is the pixel coordinate within the cursor image
+ /// which will be located exactly where the mouse pointer
+ /// position is. Any mouse actions that are performed will
+ /// return the window/screen location of the hotspot.
+ ///
+ /// \warning On Unix, the pixels are mapped into a monochrome
+ /// bitmap: pixels with an alpha channel to 0 are
+ /// transparent, black if the RGB channel are close
+ /// to zero, and white otherwise.
+ ///
+ /// \param pixels Array of pixels of the image
+ /// \param size Width and height of the image
+ /// \param hotspot (x,y) location of the hotspot
+ /// \return true if the cursor was successfully loaded;
+ /// false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Refer to the list of cursor available on each system
+ /// (see sf::Cursor::Type) to know whether a given cursor is
+ /// expected to load successfully or is not supported by
+ /// the operating system.
+ ///
+ /// \param type Native system cursor type
+ /// \return true if and only if the corresponding cursor is
+ /// natively supported by the operating system;
+ /// false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Type type);
+
+private:
+
+ friend class Window;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get access to the underlying implementation
+ ///
+ /// This is primarily designed for sf::Window::setMouseCursor,
+ /// hence the friendship.
+ ///
+ /// \return a reference to the OS-specific implementation
+ ///
+ ////////////////////////////////////////////////////////////
+ const priv::CursorImpl& getImpl() const;
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ priv::CursorImpl* m_impl; ///< Platform-specific implementation of the cursor
+};
+
+} // namespace sf
+
+
+#endif // SFML_CURSOR_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class sf::Cursor
+/// \ingroup window
+///
+/// \warning Features related to Cursor are not supported on
+/// iOS and Android.
+///
+/// This class abstracts the operating system resources
+/// associated with either a native system cursor or a custom
+/// cursor.
+///
+/// After loading the cursor the graphical appearance
+/// with either loadFromPixels() or loadFromSystem(), the
+/// cursor can be changed with sf::Window::setMouseCursor().
+///
+/// The behaviour is undefined if the cursor is destroyed while
+/// in use by the window.
+///
+/// Usage example:
+/// \code
+/// sf::Window window;
+///
+/// // ... create window as usual ...
+///
+/// sf::Cursor cursor;
+/// if (cursor.loadFromSystem(sf::Cursor::Hand))
+/// window.setMouseCursor(cursor);
+/// \endcode
+///
+/// \see sf::Window::setMouseCursor
+///
+////////////////////////////////////////////////////////////
diff --git a/include/SFML/Window/Event.hpp b/include/SFML/Window/Event.hpp
new file mode 100644
index 0000000..9261785
--- /dev/null
+++ b/include/SFML/Window/Event.hpp
@@ -0,0 +1,284 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+#include <SFML/Window/Sensor.hpp>
+
+
+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..37826a2
--- /dev/null
+++ b/include/SFML/Window/Export.hpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+
+////////////////////////////////////////////////////////////
+// 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..f701242
--- /dev/null
+++ b/include/SFML/Window/GlResource.hpp
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+
+class Context;
+
+typedef void(*ContextDestroyCallback)(void*);
+
+////////////////////////////////////////////////////////////
+/// \brief Base class for classes that require an OpenGL context
+///
+////////////////////////////////////////////////////////////
+class SFML_WINDOW_API GlResource
+{
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ GlResource();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~GlResource();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a function to be called when a context is destroyed
+ ///
+ /// This is used for internal purposes in order to properly
+ /// clean up OpenGL resources that cannot be shared between
+ /// contexts.
+ ///
+ /// \param callback Function to be called when a context is destroyed
+ /// \param arg Argument to pass when calling the function
+ ///
+ ////////////////////////////////////////////////////////////
+ static void registerContextDestroyCallback(ContextDestroyCallback callback, void* arg);
+
+ ////////////////////////////////////////////////////////////
+ /// \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();
+ };
+};
+
+} // 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..ab49c74
--- /dev/null
+++ b/include/SFML/Window/Joystick.hpp
@@ -0,0 +1,227 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/System/String.hpp>
+
+
+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..7c59c57
--- /dev/null
+++ b/include/SFML/Window/Keyboard.hpp
@@ -0,0 +1,232 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+
+
+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
+ Hyphen, ///< The - key (hyphen)
+ Space, ///< The Space key
+ Enter, ///< The Enter/Return keys
+ 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 (minus, usually from numpad)
+ 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
+
+ // Deprecated values:
+
+ Dash = Hyphen, ///< \deprecated Use Hyphen instead
+ BackSpace = Backspace, ///< \deprecated Use Backspace instead
+ BackSlash = Backslash, ///< \deprecated Use Backslash instead
+ SemiColon = Semicolon, ///< \deprecated Use Semicolon instead
+ Return = Enter ///< \deprecated Use Enter instead
+ };
+
+ ////////////////////////////////////////////////////////////
+ /// \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..0d1e470
--- /dev/null
+++ b/include/SFML/Window/Mouse.hpp
@@ -0,0 +1,177 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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..6915fa0
--- /dev/null
+++ b/include/SFML/Window/Sensor.hpp
@@ -0,0 +1,150 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/System/Vector3.hpp>
+#include <SFML/System/Time.hpp>
+
+
+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..1c2b3fe
--- /dev/null
+++ b/include/SFML/Window/Touch.hpp
@@ -0,0 +1,137 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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..24797f6
--- /dev/null
+++ b/include/SFML/Window/VideoMode.hpp
@@ -0,0 +1,228 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/Export.hpp>
+#include <vector>
+
+
+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<VideoMode>& 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<sf::VideoMode> 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..7ff81e2
--- /dev/null
+++ b/include/SFML/Window/Window.hpp
@@ -0,0 +1,622 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Window/ContextSettings.hpp>
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/Window/Export.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/WindowHandle.hpp>
+#include <SFML/Window/WindowStyle.hpp>
+#include <SFML/System/Clock.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/String.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+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 Set the displayed cursor to a native system cursor
+ ///
+ /// Upon window creation, the arrow cursor is used by default.
+ ///
+ /// \warning The cursor must not be destroyed while in use by
+ /// the window.
+ ///
+ /// \warning Features related to Cursor are not supported on
+ /// iOS and Android.
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ /// \see sf::Cursor::loadFromSystem
+ /// \see sf::Cursor::loadFromPixels
+ ///
+ ////////////////////////////////////////////////////////////
+ void setMouseCursor(const Cursor& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+///
+/// On dual-graphics systems consisting of a low-power integrated GPU
+/// and a powerful discrete GPU, the driver picks which GPU will run an
+/// SFML application. In order to inform the driver that an SFML application
+/// can benefit from being run on the more powerful discrete GPU,
+/// #SFML_DEFINE_DISCRETE_GPU_PREFERENCE can be placed in a source file
+/// that is compiled and linked into the final application. The macro
+/// should be placed outside of any scopes in the global namespace.
+///
+/// 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..daad047
--- /dev/null
+++ b/include/SFML/Window/WindowHandle.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 <SFML/Config.hpp>
+
+// 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) || defined(SFML_SYSTEM_OPENBSD)
+
+ // 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..53e2c9d
--- /dev/null
+++ b/include/SFML/Window/WindowStyle.hpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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/license.md b/license.md
new file mode 100644
index 0000000..0e6d7b1
--- /dev/null
+++ b/license.md
@@ -0,0 +1,20 @@
+# SFML
+
+SFML - Copyright (C) 2007-2018 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.
+
+## External libraries used by SFML
+
+ * _OpenAL-Soft_ is under the LGPL license
+ * _stb_image_ and _stb_image_write_ are public domain
+ * _freetype_ is under the FreeType license or the GPL license
+ * _libogg_ is under the BSD license
+ * _libvorbis_ is under the BSD license
+ * _libflac_ is under the BSD license
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..b6f9de0
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,39 @@
+[![SFML logo](https://www.sfml-dev.org/images/logo.png)](https://www.sfml-dev.org)
+
+# SFML — Simple and Fast Multimedia Library
+
+SFML is a simple, fast, cross-platform and object-oriented multimedia API. It provides access to windowing, graphics, audio and network. It is written in C++, and has bindings for various languages such as C, .Net, Ruby, Python.
+
+## Authors
+
+ - Laurent Gomila — main developer (laurent@sfml-dev.org)
+ - Marco Antognini — OS X developer (hiura@sfml-dev.org)
+ - Jonathan De Wachter — Android developer (dewachter.jonathan@gmail.com)
+ - Jan Haller (bromeon@sfml-dev.org)
+ - Stefan Schindler (tank@sfml-dev.org)
+ - Lukas Dürrenberger (eXpl0it3r@sfml-dev.org)
+ - binary1248 (binary1248@hotmail.com)
+ - Artur Moreira (artturmoreira@gmail.com)
+ - Mario Liebisch (mario@sfml-dev.org)
+ - And many other members of the SFML community
+
+## Download
+
+You can get the latest official release on [SFML's website](https://www.sfml-dev.org/download.php). You can also get the current development version from the [Git repository](https://github.com/SFML/SFML).
+
+## Install
+
+Follow the instructions of the [tutorials](https://www.sfml-dev.org/tutorials/), there is one for each platform/compiler that SFML supports.
+
+## Learn
+
+There are several places to learn SFML:
+
+ * The [official tutorials](https://www.sfml-dev.org/tutorials/)
+ * The [online API documentation](https://www.sfml-dev.org/documentation/)
+ * The [community wiki](https://github.com/SFML/SFML/wiki/)
+ * The [community forum](https://en.sfml-dev.org/forums/) ([French](https://fr.sfml-dev.org/forums/))
+
+## Contribute
+
+SFML is an open-source project, and it needs your help to go on growing and improving. If you want to get involved and suggest some additional features, file a bug report or submit a patch, please have a look at the [contribution guidelines](https://www.sfml-dev.org/contribute.php).
diff --git a/src/SFML/Android.mk b/src/SFML/Android.mk
new file mode 100644
index 0000000..2c3a626
--- /dev/null
+++ b/src/SFML/Android.mk
@@ -0,0 +1,183 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-system
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-system.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-window
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-window.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_LDLIBS := -lEGL -llog -landroid
+LOCAL_SHARED_LIBRARIES := sfml-system
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-graphics
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-graphics.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES += sfml-system sfml-window
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-audio
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-audio.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-window sfml-system openal
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-network
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-network.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-system
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-main
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-main.a
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-window sfml-system
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_STATIC_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-activity
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-activity.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-system-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-system-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-window-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-window-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_LDLIBS := -lEGL -llog -landroid
+LOCAL_SHARED_LIBRARIES := sfml-system-d
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-graphics-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-graphics-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES += sfml-system-d sfml-window-d
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-audio-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-audio-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-window-d sfml-system-d openal
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-network-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-network-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-system-d
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-main-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-main-d.a
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := sfml-window-d sfml-system-d
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_STATIC_LIBRARY)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sfml-activity-d
+LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libsfml-activity-d.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+
+prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
+prebuilt := $(strip $(wildcard $(prebuilt_path)))
+
+ifdef prebuilt
+ include $(PREBUILT_SHARED_LIBRARY)
+endif
+
+$(call import-module,third_party/sfml/extlibs)
+
diff --git a/src/SFML/Audio/ALCheck.cpp b/src/SFML/Audio/ALCheck.cpp
new file mode 100644
index 0000000..b6f1e2a
--- /dev/null
+++ b/src/SFML/Audio/ALCheck.cpp
@@ -0,0 +1,99 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/System/Err.hpp>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void alCheckError(const char* file, unsigned int line, const char* expression)
+{
+ // Get the last error
+ ALenum errorCode = alGetError();
+
+ if (errorCode != AL_NO_ERROR)
+ {
+ std::string fileString = file;
+ std::string error = "Unknown error";
+ std::string description = "No description";
+
+ // Decode the error code
+ switch (errorCode)
+ {
+ case AL_INVALID_NAME:
+ {
+ error = "AL_INVALID_NAME";
+ description = "A bad name (ID) has been specified.";
+ break;
+ }
+
+ case AL_INVALID_ENUM:
+ {
+ error = "AL_INVALID_ENUM";
+ description = "An unacceptable value has been specified for an enumerated argument.";
+ break;
+ }
+
+ case AL_INVALID_VALUE:
+ {
+ error = "AL_INVALID_VALUE";
+ description = "A numeric argument is out of range.";
+ break;
+ }
+
+ case AL_INVALID_OPERATION:
+ {
+ error = "AL_INVALID_OPERATION";
+ description = "The specified operation is not allowed in the current state.";
+ break;
+ }
+
+ case AL_OUT_OF_MEMORY:
+ {
+ error = "AL_OUT_OF_MEMORY";
+ description = "There is not enough memory left to execute the command.";
+ break;
+ }
+ }
+
+ // Log the error
+ err() << "An internal OpenAL call failed in "
+ << fileString.substr(fileString.find_last_of("\\/") + 1) << "(" << line << ")."
+ << "\nExpression:\n " << expression
+ << "\nError description:\n " << error << "\n " << description << "\n"
+ << std::endl;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/ALCheck.hpp b/src/SFML/Audio/ALCheck.hpp
new file mode 100644
index 0000000..c67d117
--- /dev/null
+++ b/src/SFML/Audio/ALCheck.hpp
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_ALCHECK_HPP
+#define SFML_ALCHECK_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#include <al.h>
+#include <alc.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// Let's define a macro to quickly check every OpenAL API call
+////////////////////////////////////////////////////////////
+#ifdef SFML_DEBUG
+
+ // If in debug mode, perform a test on every call
+ // The do-while loop is needed so that alCheck can be used as a single statement in if/else branches
+ #define alCheck(expr) do { expr; sf::priv::alCheckError(__FILE__, __LINE__, #expr); } while (false)
+
+#else
+
+ // Else, we don't add any overhead
+ #define alCheck(expr) (expr)
+
+#endif
+
+
+////////////////////////////////////////////////////////////
+/// Check the last OpenAL error
+///
+/// \param file Source file where the call is located
+/// \param line Line number of the source file where the call is located
+/// \param expression The evaluated expression as a string
+///
+////////////////////////////////////////////////////////////
+void alCheckError(const char* file, unsigned int line, const char* expression);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_ALCHECK_HPP
diff --git a/src/SFML/Audio/AlResource.cpp b/src/SFML/Audio/AlResource.cpp
new file mode 100644
index 0000000..9be2e34
--- /dev/null
+++ b/src/SFML/Audio/AlResource.cpp
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/AlResource.hpp>
+#include <SFML/Audio/AudioDevice.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+
+
+namespace
+{
+ // OpenAL resources counter and its mutex
+ unsigned int count = 0;
+ sf::Mutex mutex;
+
+ // The audio device is instantiated on demand rather than at global startup,
+ // which solves a lot of weird crashes and errors.
+ // It is destroyed when it is no longer needed.
+ sf::priv::AudioDevice* globalDevice;
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+AlResource::AlResource()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // If this is the very first resource, trigger the global device initialization
+ if (count == 0)
+ globalDevice = new priv::AudioDevice;
+
+ // Increment the resources counter
+ count++;
+}
+
+
+////////////////////////////////////////////////////////////
+AlResource::~AlResource()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // Decrement the resources counter
+ count--;
+
+ // If there's no more resource alive, we can destroy the device
+ if (count == 0)
+ delete globalDevice;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/AudioDevice.cpp b/src/SFML/Audio/AudioDevice.cpp
new file mode 100644
index 0000000..a9472f0
--- /dev/null
+++ b/src/SFML/Audio/AudioDevice.cpp
@@ -0,0 +1,228 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/AudioDevice.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/Audio/Listener.hpp>
+#include <SFML/System/Err.hpp>
+#include <memory>
+
+
+namespace
+{
+ ALCdevice* audioDevice = NULL;
+ ALCcontext* audioContext = NULL;
+
+ float listenerVolume = 100.f;
+ sf::Vector3f listenerPosition (0.f, 0.f, 0.f);
+ sf::Vector3f listenerDirection(0.f, 0.f, -1.f);
+ sf::Vector3f listenerUpVector (0.f, 1.f, 0.f);
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+AudioDevice::AudioDevice()
+{
+ // Create the device
+ audioDevice = alcOpenDevice(NULL);
+
+ if (audioDevice)
+ {
+ // Create the context
+ audioContext = alcCreateContext(audioDevice, NULL);
+
+ if (audioContext)
+ {
+ // Set the context as the current one (we'll only need one)
+ alcMakeContextCurrent(audioContext);
+
+ // Apply the listener properties the user might have set
+ float orientation[] = {listenerDirection.x,
+ listenerDirection.y,
+ listenerDirection.z,
+ listenerUpVector.x,
+ listenerUpVector.y,
+ listenerUpVector.z};
+ alCheck(alListenerf(AL_GAIN, listenerVolume * 0.01f));
+ alCheck(alListener3f(AL_POSITION, listenerPosition.x, listenerPosition.y, listenerPosition.z));
+ alCheck(alListenerfv(AL_ORIENTATION, orientation));
+ }
+ else
+ {
+ err() << "Failed to create the audio context" << std::endl;
+ }
+ }
+ else
+ {
+ err() << "Failed to open the audio device" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+AudioDevice::~AudioDevice()
+{
+ // Destroy the context
+ alcMakeContextCurrent(NULL);
+ if (audioContext)
+ alcDestroyContext(audioContext);
+
+ // Destroy the device
+ if (audioDevice)
+ alcCloseDevice(audioDevice);
+}
+
+
+////////////////////////////////////////////////////////////
+bool AudioDevice::isExtensionSupported(const std::string& extension)
+{
+ // Create a temporary audio device in case none exists yet.
+ // This device will not be used in this function and merely
+ // makes sure there is a valid OpenAL device for extension
+ // queries if none has been created yet.
+ std::auto_ptr<AudioDevice> device;
+ if (!audioDevice)
+ device.reset(new AudioDevice);
+
+ if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC"))
+ return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE;
+ else
+ return alIsExtensionPresent(extension.c_str()) != AL_FALSE;
+}
+
+
+////////////////////////////////////////////////////////////
+int AudioDevice::getFormatFromChannelCount(unsigned int channelCount)
+{
+ // Create a temporary audio device in case none exists yet.
+ // This device will not be used in this function and merely
+ // makes sure there is a valid OpenAL device for format
+ // queries if none has been created yet.
+ std::auto_ptr<AudioDevice> device;
+ if (!audioDevice)
+ device.reset(new AudioDevice);
+
+ // Find the good format according to the number of channels
+ int format = 0;
+ switch (channelCount)
+ {
+ case 1: format = AL_FORMAT_MONO16; break;
+ case 2: format = AL_FORMAT_STEREO16; break;
+ case 4: format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
+ case 6: format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
+ case 7: format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
+ case 8: format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
+ default: format = 0; break;
+ }
+
+ // Fixes a bug on OS X
+ if (format == -1)
+ format = 0;
+
+ return format;
+}
+
+
+////////////////////////////////////////////////////////////
+void AudioDevice::setGlobalVolume(float volume)
+{
+ if (audioContext)
+ alCheck(alListenerf(AL_GAIN, volume * 0.01f));
+
+ listenerVolume = volume;
+}
+
+
+////////////////////////////////////////////////////////////
+float AudioDevice::getGlobalVolume()
+{
+ return listenerVolume;
+}
+
+
+////////////////////////////////////////////////////////////
+void AudioDevice::setPosition(const Vector3f& position)
+{
+ if (audioContext)
+ alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z));
+
+ listenerPosition = position;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f AudioDevice::getPosition()
+{
+ return listenerPosition;
+}
+
+
+////////////////////////////////////////////////////////////
+void AudioDevice::setDirection(const Vector3f& direction)
+{
+ if (audioContext)
+ {
+ float orientation[] = {direction.x, direction.y, direction.z, listenerUpVector.x, listenerUpVector.y, listenerUpVector.z};
+ alCheck(alListenerfv(AL_ORIENTATION, orientation));
+ }
+
+ listenerDirection = direction;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f AudioDevice::getDirection()
+{
+ return listenerDirection;
+}
+
+
+////////////////////////////////////////////////////////////
+void AudioDevice::setUpVector(const Vector3f& upVector)
+{
+ if (audioContext)
+ {
+ float orientation[] = {listenerDirection.x, listenerDirection.y, listenerDirection.z, upVector.x, upVector.y, upVector.z};
+ alCheck(alListenerfv(AL_ORIENTATION, orientation));
+ }
+
+ listenerUpVector = upVector;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f AudioDevice::getUpVector()
+{
+ return listenerUpVector;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/AudioDevice.hpp b/src/SFML/Audio/AudioDevice.hpp
new file mode 100644
index 0000000..f5007ed
--- /dev/null
+++ b/src/SFML/Audio/AudioDevice.hpp
@@ -0,0 +1,192 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_AUDIODEVICE_HPP
+#define SFML_AUDIODEVICE_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Vector3.hpp>
+#include <set>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief High-level wrapper around the audio API, it manages
+/// the creation and destruction of the audio device and
+/// context and stores the device capabilities
+///
+////////////////////////////////////////////////////////////
+class AudioDevice
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ AudioDevice();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~AudioDevice();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if an OpenAL extension is supported
+ ///
+ /// This functions automatically finds whether it
+ /// is an AL or ALC extension, and calls the corresponding
+ /// function.
+ ///
+ /// \param extension Name of the extension to test
+ ///
+ /// \return True if the extension is supported, false if not
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isExtensionSupported(const std::string& extension);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OpenAL format that matches the given number of channels
+ ///
+ /// \param channelCount Number of channels
+ ///
+ /// \return Corresponding format
+ ///
+ ////////////////////////////////////////////////////////////
+ static int getFormatFromChannelCount(unsigned int channelCount);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 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 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 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 priv
+
+} // namespace sf
+
+
+#endif // SFML_AUDIODEVICE_HPP
diff --git a/src/SFML/Audio/CMakeLists.txt b/src/SFML/Audio/CMakeLists.txt
new file mode 100644
index 0000000..420e13b
--- /dev/null
+++ b/src/SFML/Audio/CMakeLists.txt
@@ -0,0 +1,90 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Audio)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Audio)
+
+# all source files
+set(SRC
+ ${SRCROOT}/ALCheck.cpp
+ ${SRCROOT}/ALCheck.hpp
+ ${SRCROOT}/AlResource.cpp
+ ${INCROOT}/AlResource.hpp
+ ${SRCROOT}/AudioDevice.cpp
+ ${SRCROOT}/AudioDevice.hpp
+ ${INCROOT}/Export.hpp
+ ${SRCROOT}/Listener.cpp
+ ${INCROOT}/Listener.hpp
+ ${SRCROOT}/Music.cpp
+ ${INCROOT}/Music.hpp
+ ${SRCROOT}/Sound.cpp
+ ${INCROOT}/Sound.hpp
+ ${SRCROOT}/SoundBuffer.cpp
+ ${INCROOT}/SoundBuffer.hpp
+ ${SRCROOT}/SoundBufferRecorder.cpp
+ ${INCROOT}/SoundBufferRecorder.hpp
+ ${SRCROOT}/InputSoundFile.cpp
+ ${INCROOT}/InputSoundFile.hpp
+ ${SRCROOT}/OutputSoundFile.cpp
+ ${INCROOT}/OutputSoundFile.hpp
+ ${SRCROOT}/SoundRecorder.cpp
+ ${INCROOT}/SoundRecorder.hpp
+ ${SRCROOT}/SoundSource.cpp
+ ${INCROOT}/SoundSource.hpp
+ ${SRCROOT}/SoundStream.cpp
+ ${INCROOT}/SoundStream.hpp
+)
+source_group("" FILES ${SRC})
+
+set(CODECS_SRC
+ ${SRCROOT}/SoundFileFactory.cpp
+ ${INCROOT}/SoundFileFactory.hpp
+ ${INCROOT}/SoundFileFactory.inl
+ ${INCROOT}/SoundFileReader.hpp
+ ${SRCROOT}/SoundFileReaderFlac.hpp
+ ${SRCROOT}/SoundFileReaderFlac.cpp
+ ${SRCROOT}/SoundFileReaderOgg.hpp
+ ${SRCROOT}/SoundFileReaderOgg.cpp
+ ${SRCROOT}/SoundFileReaderWav.hpp
+ ${SRCROOT}/SoundFileReaderWav.cpp
+ ${INCROOT}/SoundFileWriter.hpp
+ ${SRCROOT}/SoundFileWriterFlac.hpp
+ ${SRCROOT}/SoundFileWriterFlac.cpp
+ ${SRCROOT}/SoundFileWriterOgg.hpp
+ ${SRCROOT}/SoundFileWriterOgg.cpp
+ ${SRCROOT}/SoundFileWriterWav.hpp
+ ${SRCROOT}/SoundFileWriterWav.cpp
+)
+source_group("codecs" FILES ${CODECS_SRC})
+
+# let CMake know about our additional audio libraries paths (on Windows and OSX)
+if(SFML_OS_WINDOWS)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
+elseif(SFML_OS_MACOSX)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks")
+elseif(SFML_OS_ANDROID)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/android")
+endif()
+
+# find external libraries
+sfml_find_package(OpenAL INCLUDE "OPENAL_INCLUDE_DIR" LINK "OPENAL_LIBRARY")
+sfml_find_package(Vorbis INCLUDE "VORBIS_INCLUDE_DIRS" LINK "VORBIS_LIBRARIES")
+sfml_find_package(FLAC INCLUDE "FLAC_INCLUDE_DIR" LINK "FLAC_LIBRARY")
+
+# avoids warnings in vorbisfile.h
+target_compile_definitions(Vorbis INTERFACE "OV_EXCLUDE_STATIC_CALLBACKS")
+target_compile_definitions(FLAC INTERFACE "FLAC__NO_DLL")
+
+# define the sfml-audio target
+sfml_add_library(sfml-audio
+ SOURCES ${SRC} ${CODECS_SRC})
+
+# setup dependencies
+target_link_libraries(sfml-audio PRIVATE OpenAL)
+
+if(SFML_OS_ANDROID)
+ target_link_libraries(sfml-audio PRIVATE android OpenSLES)
+endif()
+
+target_link_libraries(sfml-audio
+ PUBLIC sfml-system
+ PRIVATE Vorbis FLAC)
diff --git a/src/SFML/Audio/InputSoundFile.cpp b/src/SFML/Audio/InputSoundFile.cpp
new file mode 100644
index 0000000..9cc781f
--- /dev/null
+++ b/src/SFML/Audio/InputSoundFile.cpp
@@ -0,0 +1,278 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/InputSoundFile.hpp>
+#include <SFML/Audio/SoundFileReader.hpp>
+#include <SFML/Audio/SoundFileFactory.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/FileInputStream.hpp>
+#include <SFML/System/MemoryInputStream.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+InputSoundFile::InputSoundFile() :
+m_reader (NULL),
+m_stream (NULL),
+m_streamOwned (false),
+m_sampleOffset (0),
+m_sampleCount (0),
+m_channelCount(0),
+m_sampleRate (0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+InputSoundFile::~InputSoundFile()
+{
+ // Close the file in case it was open
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputSoundFile::openFromFile(const std::string& filename)
+{
+ // If the file is already open, first close it
+ close();
+
+ // Find a suitable reader for the file type
+ m_reader = SoundFileFactory::createReaderFromFilename(filename);
+ if (!m_reader)
+ return false;
+
+ // Wrap the file into a stream
+ FileInputStream* file = new FileInputStream;
+ m_stream = file;
+ m_streamOwned = true;
+
+ // Open it
+ if (!file->open(filename))
+ {
+ close();
+ return false;
+ }
+
+ // Pass the stream to the reader
+ SoundFileReader::Info info;
+ if (!m_reader->open(*file, info))
+ {
+ close();
+ return false;
+ }
+
+ // Retrieve the attributes of the open sound file
+ m_sampleCount = info.sampleCount;
+ m_channelCount = info.channelCount;
+ m_sampleRate = info.sampleRate;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
+{
+ // If the file is already open, first close it
+ close();
+
+ // Find a suitable reader for the file type
+ m_reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes);
+ if (!m_reader)
+ return false;
+
+ // Wrap the memory file into a stream
+ MemoryInputStream* memory = new MemoryInputStream;
+ m_stream = memory;
+ m_streamOwned = true;
+
+ // Open it
+ memory->open(data, sizeInBytes);
+
+ // Pass the stream to the reader
+ SoundFileReader::Info info;
+ if (!m_reader->open(*memory, info))
+ {
+ close();
+ return false;
+ }
+
+ // Retrieve the attributes of the open sound file
+ m_sampleCount = info.sampleCount;
+ m_channelCount = info.channelCount;
+ m_sampleRate = info.sampleRate;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputSoundFile::openFromStream(InputStream& stream)
+{
+ // If the file is already open, first close it
+ close();
+
+ // Find a suitable reader for the file type
+ m_reader = SoundFileFactory::createReaderFromStream(stream);
+ if (!m_reader)
+ return false;
+
+ // store the stream
+ m_stream = &stream;
+ m_streamOwned = false;
+
+ // Don't forget to reset the stream to its beginning before re-opening it
+ if (stream.seek(0) != 0)
+ {
+ err() << "Failed to open sound file from stream (cannot restart stream)" << std::endl;
+ return false;
+ }
+
+ // Pass the stream to the reader
+ SoundFileReader::Info info;
+ if (!m_reader->open(stream, info))
+ {
+ close();
+ return false;
+ }
+
+ // Retrieve the attributes of the open sound file
+ m_sampleCount = info.sampleCount;
+ m_channelCount = info.channelCount;
+ m_sampleRate = info.sampleRate;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 InputSoundFile::getSampleCount() const
+{
+ return m_sampleCount;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int InputSoundFile::getChannelCount() const
+{
+ return m_channelCount;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int InputSoundFile::getSampleRate() const
+{
+ return m_sampleRate;
+}
+
+
+////////////////////////////////////////////////////////////
+Time InputSoundFile::getDuration() const
+{
+ // Make sure we don't divide by 0
+ if (m_channelCount == 0 || m_sampleRate == 0)
+ return Time::Zero;
+
+ return seconds(static_cast<float>(m_sampleCount) / m_channelCount / m_sampleRate);
+}
+
+
+////////////////////////////////////////////////////////////
+Time InputSoundFile::getTimeOffset() const
+{
+ // Make sure we don't divide by 0
+ if (m_channelCount == 0 || m_sampleRate == 0)
+ return Time::Zero;
+
+ return seconds(static_cast<float>(m_sampleOffset) / m_channelCount / m_sampleRate);
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 InputSoundFile::getSampleOffset() const
+{
+ return m_sampleOffset;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputSoundFile::seek(Uint64 sampleOffset)
+{
+ if (m_reader)
+ {
+ // The reader handles an overrun gracefully, but we
+ // pre-check to keep our known position consistent
+ m_sampleOffset = std::min(sampleOffset, m_sampleCount);
+ m_reader->seek(m_sampleOffset);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputSoundFile::seek(Time timeOffset)
+{
+ seek(static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount));
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 InputSoundFile::read(Int16* samples, Uint64 maxCount)
+{
+ Uint64 readSamples = 0;
+ if (m_reader && samples && maxCount)
+ readSamples = m_reader->read(samples, maxCount);
+ m_sampleOffset += readSamples;
+ return readSamples;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputSoundFile::close()
+{
+ // Destroy the reader
+ delete m_reader;
+ m_reader = NULL;
+
+ // Destroy the stream if we own it
+ if (m_streamOwned)
+ {
+ delete m_stream;
+ m_streamOwned = false;
+ }
+ m_stream = NULL;
+ m_sampleOffset = 0;
+
+ // Reset the sound file attributes
+ m_sampleCount = 0;
+ m_channelCount = 0;
+ m_sampleRate = 0;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/Listener.cpp b/src/SFML/Audio/Listener.cpp
new file mode 100644
index 0000000..dc348f9
--- /dev/null
+++ b/src/SFML/Audio/Listener.cpp
@@ -0,0 +1,110 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/Listener.hpp>
+#include <SFML/Audio/AudioDevice.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+void Listener::setGlobalVolume(float volume)
+{
+ priv::AudioDevice::setGlobalVolume(volume);
+}
+
+
+////////////////////////////////////////////////////////////
+float Listener::getGlobalVolume()
+{
+ return priv::AudioDevice::getGlobalVolume();
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setPosition(float x, float y, float z)
+{
+ setPosition(Vector3f(x, y, z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setPosition(const Vector3f& position)
+{
+ priv::AudioDevice::setPosition(position);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f Listener::getPosition()
+{
+ return priv::AudioDevice::getPosition();
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setDirection(float x, float y, float z)
+{
+ setDirection(Vector3f(x, y, z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setDirection(const Vector3f& direction)
+{
+ priv::AudioDevice::setDirection(direction);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f Listener::getDirection()
+{
+ return priv::AudioDevice::getDirection();
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setUpVector(float x, float y, float z)
+{
+ setUpVector(Vector3f(x, y, z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Listener::setUpVector(const Vector3f& upVector)
+{
+ priv::AudioDevice::setUpVector(upVector);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f Listener::getUpVector()
+{
+ return priv::AudioDevice::getUpVector();
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/Music.cpp b/src/SFML/Audio/Music.cpp
new file mode 100644
index 0000000..141d690
--- /dev/null
+++ b/src/SFML/Audio/Music.cpp
@@ -0,0 +1,271 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/Music.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <fstream>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Music::Music() :
+m_file (),
+m_loopSpan (0, 0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Music::~Music()
+{
+ // We must stop before destroying the file
+ stop();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Music::openFromFile(const std::string& filename)
+{
+ // First stop the music if it was already running
+ stop();
+
+ // Open the underlying sound file
+ if (!m_file.openFromFile(filename))
+ return false;
+
+ // Perform common initializations
+ initialize();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Music::openFromMemory(const void* data, std::size_t sizeInBytes)
+{
+ // First stop the music if it was already running
+ stop();
+
+ // Open the underlying sound file
+ if (!m_file.openFromMemory(data, sizeInBytes))
+ return false;
+
+ // Perform common initializations
+ initialize();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Music::openFromStream(InputStream& stream)
+{
+ // First stop the music if it was already running
+ stop();
+
+ // Open the underlying sound file
+ if (!m_file.openFromStream(stream))
+ return false;
+
+ // Perform common initializations
+ initialize();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Time Music::getDuration() const
+{
+ return m_file.getDuration();
+}
+
+
+////////////////////////////////////////////////////////////
+Music::TimeSpan Music::getLoopPoints() const
+{
+ return TimeSpan(samplesToTime(m_loopSpan.offset), samplesToTime(m_loopSpan.length));
+}
+
+
+////////////////////////////////////////////////////////////
+void Music::setLoopPoints(TimeSpan timePoints)
+{
+ Span<Uint64> samplePoints(timeToSamples(timePoints.offset), timeToSamples(timePoints.length));
+
+ // Check our state. This averts a divide-by-zero. GetChannelCount() is cheap enough to use often
+ if (getChannelCount() == 0 || m_file.getSampleCount() == 0)
+ {
+ sf::err() << "Music is not in a valid state to assign Loop Points." << std::endl;
+ return;
+ }
+
+ // Round up to the next even sample if needed
+ samplePoints.offset += (getChannelCount() - 1);
+ samplePoints.offset -= (samplePoints.offset % getChannelCount());
+ samplePoints.length += (getChannelCount() - 1);
+ samplePoints.length -= (samplePoints.length % getChannelCount());
+
+ // Validate
+ if (samplePoints.offset >= m_file.getSampleCount())
+ {
+ sf::err() << "LoopPoints offset val must be in range [0, Duration)." << std::endl;
+ return;
+ }
+ if (samplePoints.length == 0)
+ {
+ sf::err() << "LoopPoints length val must be nonzero." << std::endl;
+ return;
+ }
+
+ // Clamp End Point
+ samplePoints.length = std::min(samplePoints.length, m_file.getSampleCount() - samplePoints.offset);
+
+ // If this change has no effect, we can return without touching anything
+ if (samplePoints.offset == m_loopSpan.offset && samplePoints.length == m_loopSpan.length)
+ return;
+
+ // When we apply this change, we need to "reset" this instance and its buffer
+
+ // Get old playing status and position
+ Status oldStatus = getStatus();
+ Time oldPos = getPlayingOffset();
+
+ // Unload
+ stop();
+
+ // Set
+ m_loopSpan = samplePoints;
+
+ // Restore
+ if (oldPos != Time::Zero)
+ setPlayingOffset(oldPos);
+
+ // Resume
+ if (oldStatus == Playing)
+ play();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Music::onGetData(SoundStream::Chunk& data)
+{
+ Lock lock(m_mutex);
+
+ std::size_t toFill = m_samples.size();
+ Uint64 currentOffset = m_file.getSampleOffset();
+ Uint64 loopEnd = m_loopSpan.offset + m_loopSpan.length;
+
+ // If the loop end is enabled and imminent, request less data.
+ // This will trip an "onLoop()" call from the underlying SoundStream,
+ // and we can then take action.
+ if (getLoop() && (m_loopSpan.length != 0) && (currentOffset <= loopEnd) && (currentOffset + toFill > loopEnd))
+ toFill = static_cast<std::size_t>(loopEnd - currentOffset);
+
+ // Fill the chunk parameters
+ data.samples = &m_samples[0];
+ data.sampleCount = static_cast<std::size_t>(m_file.read(&m_samples[0], toFill));
+ currentOffset += data.sampleCount;
+
+ // Check if we have stopped obtaining samples or reached either the EOF or the loop end point
+ return (data.sampleCount != 0) && (currentOffset < m_file.getSampleCount()) && !(currentOffset == loopEnd && m_loopSpan.length != 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void Music::onSeek(Time timeOffset)
+{
+ Lock lock(m_mutex);
+ m_file.seek(timeOffset);
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 Music::onLoop()
+{
+ // Called by underlying SoundStream so we can determine where to loop.
+ Lock lock(m_mutex);
+ Uint64 currentOffset = m_file.getSampleOffset();
+ if (getLoop() && (m_loopSpan.length != 0) && (currentOffset == m_loopSpan.offset + m_loopSpan.length))
+ {
+ // Looping is enabled, and either we're at the loop end, or we're at the EOF
+ // when it's equivalent to the loop end (loop end takes priority). Send us to loop begin
+ m_file.seek(m_loopSpan.offset);
+ return m_file.getSampleOffset();
+ }
+ else if (getLoop() && (currentOffset >= m_file.getSampleCount()))
+ {
+ // If we're at the EOF, reset to 0
+ m_file.seek(0);
+ return 0;
+ }
+ return NoLoop;
+}
+
+
+////////////////////////////////////////////////////////////
+void Music::initialize()
+{
+ // Compute the music positions
+ m_loopSpan.offset = 0;
+ m_loopSpan.length = m_file.getSampleCount();
+
+ // Resize the internal buffer so that it can contain 1 second of audio samples
+ m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount());
+
+ // Initialize the stream
+ SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate());
+}
+
+////////////////////////////////////////////////////////////
+Uint64 Music::timeToSamples(Time position) const
+{
+ // Always ROUND, no unchecked truncation, hence the addition in the numerator.
+ // This avoids most precision errors arising from "samples => Time => samples" conversions
+ // Original rounding calculation is ((Micros * Freq * Channels) / 1000000) + 0.5
+ // We refactor it to keep Int64 as the data type throughout the whole operation.
+ return ((position.asMicroseconds() * getSampleRate() * getChannelCount()) + 500000) / 1000000;
+}
+
+
+////////////////////////////////////////////////////////////
+Time Music::samplesToTime(Uint64 samples) const
+{
+ Time position = Time::Zero;
+
+ // Make sure we don't divide by 0
+ if (getSampleRate() != 0 && getChannelCount() != 0)
+ position = microseconds((samples * 1000000) / (getChannelCount() * getSampleRate()));
+
+ return position;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/OutputSoundFile.cpp b/src/SFML/Audio/OutputSoundFile.cpp
new file mode 100644
index 0000000..16e41d3
--- /dev/null
+++ b/src/SFML/Audio/OutputSoundFile.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/OutputSoundFile.hpp>
+#include <SFML/Audio/SoundFileWriter.hpp>
+#include <SFML/Audio/SoundFileFactory.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+OutputSoundFile::OutputSoundFile() :
+m_writer(NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+OutputSoundFile::~OutputSoundFile()
+{
+ // Close the file in case it was open
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool OutputSoundFile::openFromFile(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
+{
+ // If the file is already open, first close it
+ close();
+
+ // Find a suitable writer for the file type
+ m_writer = SoundFileFactory::createWriterFromFilename(filename);
+ if (!m_writer)
+ return false;
+
+ // Pass the stream to the reader
+ if (!m_writer->open(filename, sampleRate, channelCount))
+ {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void OutputSoundFile::write(const Int16* samples, Uint64 count)
+{
+ if (m_writer && samples && count)
+ m_writer->write(samples, count);
+}
+
+
+////////////////////////////////////////////////////////////
+void OutputSoundFile::close()
+{
+ // Destroy the reader
+ delete m_writer;
+ m_writer = NULL;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/Sound.cpp b/src/SFML/Audio/Sound.cpp
new file mode 100644
index 0000000..b7a0b13
--- /dev/null
+++ b/src/SFML/Audio/Sound.cpp
@@ -0,0 +1,198 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/Sound.hpp>
+#include <SFML/Audio/SoundBuffer.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Sound::Sound() :
+m_buffer(NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Sound::Sound(const SoundBuffer& buffer) :
+m_buffer(NULL)
+{
+ setBuffer(buffer);
+}
+
+
+////////////////////////////////////////////////////////////
+Sound::Sound(const Sound& copy) :
+SoundSource(copy),
+m_buffer (NULL)
+{
+ if (copy.m_buffer)
+ setBuffer(*copy.m_buffer);
+ setLoop(copy.getLoop());
+}
+
+
+////////////////////////////////////////////////////////////
+Sound::~Sound()
+{
+ stop();
+ if (m_buffer)
+ m_buffer->detachSound(this);
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::play()
+{
+ alCheck(alSourcePlay(m_source));
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::pause()
+{
+ alCheck(alSourcePause(m_source));
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::stop()
+{
+ alCheck(alSourceStop(m_source));
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::setBuffer(const SoundBuffer& buffer)
+{
+ // First detach from the previous buffer
+ if (m_buffer)
+ {
+ stop();
+ m_buffer->detachSound(this);
+ }
+
+ // Assign and use the new buffer
+ m_buffer = &buffer;
+ m_buffer->attachSound(this);
+ alCheck(alSourcei(m_source, AL_BUFFER, m_buffer->m_buffer));
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::setLoop(bool loop)
+{
+ alCheck(alSourcei(m_source, AL_LOOPING, loop));
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::setPlayingOffset(Time timeOffset)
+{
+ alCheck(alSourcef(m_source, AL_SEC_OFFSET, timeOffset.asSeconds()));
+}
+
+
+////////////////////////////////////////////////////////////
+const SoundBuffer* Sound::getBuffer() const
+{
+ return m_buffer;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Sound::getLoop() const
+{
+ ALint loop;
+ alCheck(alGetSourcei(m_source, AL_LOOPING, &loop));
+
+ return loop != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Time Sound::getPlayingOffset() const
+{
+ ALfloat secs = 0.f;
+ alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs));
+
+ return seconds(secs);
+}
+
+
+////////////////////////////////////////////////////////////
+Sound::Status Sound::getStatus() const
+{
+ return SoundSource::getStatus();
+}
+
+
+////////////////////////////////////////////////////////////
+Sound& Sound::operator =(const Sound& right)
+{
+ // Here we don't use the copy-and-swap idiom, because it would mess up
+ // the list of sound instances contained in the buffers and unnecessarily
+ // destroy/create OpenAL sound sources
+
+ // Delegate to base class, which copies all the sound attributes
+ SoundSource::operator=(right);
+
+ // Detach the sound instance from the previous buffer (if any)
+ if (m_buffer)
+ {
+ stop();
+ m_buffer->detachSound(this);
+ m_buffer = NULL;
+ }
+
+ // Copy the remaining sound attributes
+ if (right.m_buffer)
+ setBuffer(*right.m_buffer);
+ setLoop(right.getLoop());
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+void Sound::resetBuffer()
+{
+ // First stop the sound in case it is playing
+ stop();
+
+ // Detach the buffer
+ if (m_buffer)
+ {
+ alCheck(alSourcei(m_source, AL_BUFFER, 0));
+ m_buffer->detachSound(this);
+ m_buffer = NULL;
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundBuffer.cpp b/src/SFML/Audio/SoundBuffer.cpp
new file mode 100644
index 0000000..edcd455
--- /dev/null
+++ b/src/SFML/Audio/SoundBuffer.cpp
@@ -0,0 +1,291 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundBuffer.hpp>
+#include <SFML/Audio/InputSoundFile.hpp>
+#include <SFML/Audio/OutputSoundFile.hpp>
+#include <SFML/Audio/Sound.hpp>
+#include <SFML/Audio/AudioDevice.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/System/Err.hpp>
+#include <memory>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+SoundBuffer::SoundBuffer() :
+m_buffer (0),
+m_duration()
+{
+ // Create the buffer
+ alCheck(alGenBuffers(1, &m_buffer));
+}
+
+
+////////////////////////////////////////////////////////////
+SoundBuffer::SoundBuffer(const SoundBuffer& copy) :
+m_buffer (0),
+m_samples (copy.m_samples),
+m_duration(copy.m_duration),
+m_sounds () // don't copy the attached sounds
+{
+ // Create the buffer
+ alCheck(alGenBuffers(1, &m_buffer));
+
+ // Update the internal buffer with the new samples
+ update(copy.getChannelCount(), copy.getSampleRate());
+}
+
+
+////////////////////////////////////////////////////////////
+SoundBuffer::~SoundBuffer()
+{
+ // To prevent the iterator from becoming invalid, move the entire buffer to another
+ // container. Otherwise calling resetBuffer would result in detachSound being
+ // called which removes the sound from the internal list.
+ SoundList sounds;
+ sounds.swap(m_sounds);
+
+ // Detach the buffer from the sounds that use it (to avoid OpenAL errors)
+ for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it)
+ (*it)->resetBuffer();
+
+ // Destroy the buffer
+ if (m_buffer)
+ alCheck(alDeleteBuffers(1, &m_buffer));
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::loadFromFile(const std::string& filename)
+{
+ InputSoundFile file;
+ if (file.openFromFile(filename))
+ return initialize(file);
+ else
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
+{
+ InputSoundFile file;
+ if (file.openFromMemory(data, sizeInBytes))
+ return initialize(file);
+ else
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::loadFromStream(InputStream& stream)
+{
+ InputSoundFile file;
+ if (file.openFromStream(stream))
+ return initialize(file);
+ else
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate)
+{
+ if (samples && sampleCount && channelCount && sampleRate)
+ {
+ // Copy the new audio samples
+ m_samples.assign(samples, samples + sampleCount);
+
+ // Update the internal buffer with the new samples
+ return update(channelCount, sampleRate);
+ }
+ else
+ {
+ // Error...
+ err() << "Failed to load sound buffer from samples ("
+ << "array: " << samples << ", "
+ << "count: " << sampleCount << ", "
+ << "channels: " << channelCount << ", "
+ << "samplerate: " << sampleRate << ")"
+ << std::endl;
+
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::saveToFile(const std::string& filename) const
+{
+ // Create the sound file in write mode
+ OutputSoundFile file;
+ if (file.openFromFile(filename, getSampleRate(), getChannelCount()))
+ {
+ // Write the samples to the opened file
+ file.write(&m_samples[0], m_samples.size());
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const Int16* SoundBuffer::getSamples() const
+{
+ return m_samples.empty() ? NULL : &m_samples[0];
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 SoundBuffer::getSampleCount() const
+{
+ return m_samples.size();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundBuffer::getSampleRate() const
+{
+ ALint sampleRate;
+ alCheck(alGetBufferi(m_buffer, AL_FREQUENCY, &sampleRate));
+
+ return sampleRate;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundBuffer::getChannelCount() const
+{
+ ALint channelCount;
+ alCheck(alGetBufferi(m_buffer, AL_CHANNELS, &channelCount));
+
+ return channelCount;
+}
+
+
+////////////////////////////////////////////////////////////
+Time SoundBuffer::getDuration() const
+{
+ return m_duration;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right)
+{
+ SoundBuffer temp(right);
+
+ std::swap(m_samples, temp.m_samples);
+ std::swap(m_buffer, temp.m_buffer);
+ std::swap(m_duration, temp.m_duration);
+ std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::initialize(InputSoundFile& file)
+{
+ // Retrieve the sound parameters
+ Uint64 sampleCount = file.getSampleCount();
+ unsigned int channelCount = file.getChannelCount();
+ unsigned int sampleRate = file.getSampleRate();
+
+ // Read the samples from the provided file
+ m_samples.resize(static_cast<std::size_t>(sampleCount));
+ if (file.read(&m_samples[0], sampleCount) == sampleCount)
+ {
+ // Update the internal buffer with the new samples
+ return update(channelCount, sampleRate);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate)
+{
+ // Check parameters
+ if (!channelCount || !sampleRate || m_samples.empty())
+ return false;
+
+ // Find the good format according to the number of channels
+ ALenum format = priv::AudioDevice::getFormatFromChannelCount(channelCount);
+
+ // Check if the format is valid
+ if (format == 0)
+ {
+ err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl;
+ return false;
+ }
+
+ // First make a copy of the list of sounds so we can reattach later
+ SoundList sounds(m_sounds);
+
+ // Detach the buffer from the sounds that use it (to avoid OpenAL errors)
+ for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it)
+ (*it)->resetBuffer();
+
+ // Fill the buffer
+ ALsizei size = static_cast<ALsizei>(m_samples.size()) * sizeof(Int16);
+ alCheck(alBufferData(m_buffer, format, &m_samples[0], size, sampleRate));
+
+ // Compute the duration
+ m_duration = seconds(static_cast<float>(m_samples.size()) / sampleRate / channelCount);
+
+ // Now reattach the buffer to the sounds that use it
+ for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it)
+ (*it)->setBuffer(*this);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundBuffer::attachSound(Sound* sound) const
+{
+ m_sounds.insert(sound);
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundBuffer::detachSound(Sound* sound) const
+{
+ m_sounds.erase(sound);
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundBufferRecorder.cpp b/src/SFML/Audio/SoundBufferRecorder.cpp
new file mode 100644
index 0000000..3c70a65
--- /dev/null
+++ b/src/SFML/Audio/SoundBufferRecorder.cpp
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundBufferRecorder.hpp>
+#include <algorithm>
+#include <iterator>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+SoundBufferRecorder::~SoundBufferRecorder()
+{
+ // Make sure to stop the recording thread
+ stop();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBufferRecorder::onStart()
+{
+ m_samples.clear();
+ m_buffer = SoundBuffer();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundBufferRecorder::onProcessSamples(const Int16* samples, std::size_t sampleCount)
+{
+ std::copy(samples, samples + sampleCount, std::back_inserter(m_samples));
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundBufferRecorder::onStop()
+{
+ if (!m_samples.empty())
+ m_buffer.loadFromSamples(&m_samples[0], m_samples.size(), getChannelCount(), getSampleRate());
+}
+
+
+////////////////////////////////////////////////////////////
+const SoundBuffer& SoundBufferRecorder::getBuffer() const
+{
+ return m_buffer;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileFactory.cpp b/src/SFML/Audio/SoundFileFactory.cpp
new file mode 100644
index 0000000..8138319
--- /dev/null
+++ b/src/SFML/Audio/SoundFileFactory.cpp
@@ -0,0 +1,154 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileFactory.hpp>
+#include <SFML/Audio/SoundFileReaderFlac.hpp>
+#include <SFML/Audio/SoundFileWriterFlac.hpp>
+#include <SFML/Audio/SoundFileReaderOgg.hpp>
+#include <SFML/Audio/SoundFileWriterOgg.hpp>
+#include <SFML/Audio/SoundFileReaderWav.hpp>
+#include <SFML/Audio/SoundFileWriterWav.hpp>
+#include <SFML/System/FileInputStream.hpp>
+#include <SFML/System/MemoryInputStream.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace
+{
+ // Register all the built-in readers and writers if not already done
+ void ensureDefaultReadersWritersRegistered()
+ {
+ static bool registered = false;
+ if (!registered)
+ {
+ sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderFlac>();
+ sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterFlac>();
+ sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderOgg>();
+ sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterOgg>();
+ sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderWav>();
+ sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterWav>();
+ registered = true;
+ }
+ }
+}
+
+namespace sf
+{
+SoundFileFactory::ReaderFactoryArray SoundFileFactory::s_readers;
+SoundFileFactory::WriterFactoryArray SoundFileFactory::s_writers;
+
+
+////////////////////////////////////////////////////////////
+SoundFileReader* SoundFileFactory::createReaderFromFilename(const std::string& filename)
+{
+ // Register the built-in readers/writers on first call
+ ensureDefaultReadersWritersRegistered();
+
+ // Wrap the input file into a file stream
+ FileInputStream stream;
+ if (!stream.open(filename)) {
+ err() << "Failed to open sound file \"" << filename << "\" (couldn't open stream)" << std::endl;
+ return NULL;
+ }
+
+ // Test the filename in all the registered factories
+ for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
+ {
+ stream.seek(0);
+ if (it->check(stream))
+ return it->create();
+ }
+
+ // No suitable reader found
+ err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReader* SoundFileFactory::createReaderFromMemory(const void* data, std::size_t sizeInBytes)
+{
+ // Register the built-in readers/writers on first call
+ ensureDefaultReadersWritersRegistered();
+
+ // Wrap the memory file into a file stream
+ MemoryInputStream stream;
+ stream.open(data, sizeInBytes);
+
+ // Test the stream for all the registered factories
+ for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
+ {
+ stream.seek(0);
+ if (it->check(stream))
+ return it->create();
+ }
+
+ // No suitable reader found
+ err() << "Failed to open sound file from memory (format not supported)" << std::endl;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReader* SoundFileFactory::createReaderFromStream(InputStream& stream)
+{
+ // Register the built-in readers/writers on first call
+ ensureDefaultReadersWritersRegistered();
+
+ // Test the stream for all the registered factories
+ for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
+ {
+ stream.seek(0);
+ if (it->check(stream))
+ return it->create();
+ }
+
+ // No suitable reader found
+ err() << "Failed to open sound file from stream (format not supported)" << std::endl;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriter* SoundFileFactory::createWriterFromFilename(const std::string& filename)
+{
+ // Register the built-in readers/writers on first call
+ ensureDefaultReadersWritersRegistered();
+
+ // Test the filename in all the registered factories
+ for (WriterFactoryArray::const_iterator it = s_writers.begin(); it != s_writers.end(); ++it)
+ {
+ if (it->check(filename))
+ return it->create();
+ }
+
+ // No suitable writer found
+ err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
+ return NULL;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileReaderFlac.cpp b/src/SFML/Audio/SoundFileReaderFlac.cpp
new file mode 100644
index 0000000..f42a132
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderFlac.cpp
@@ -0,0 +1,340 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReaderFlac.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Err.hpp>
+#include <cassert>
+
+
+namespace
+{
+ FLAC__StreamDecoderReadStatus streamRead(const FLAC__StreamDecoder*, FLAC__byte buffer[], std::size_t* bytes, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ sf::Int64 count = data->stream->read(buffer, *bytes);
+ if (count > 0)
+ {
+ *bytes = static_cast<std::size_t>(count);
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else if (count == 0)
+ {
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else
+ {
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ }
+
+ FLAC__StreamDecoderSeekStatus streamSeek(const FLAC__StreamDecoder*, FLAC__uint64 absoluteByteOffset, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ sf::Int64 position = data->stream->seek(absoluteByteOffset);
+ if (position >= 0)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ else
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+
+ FLAC__StreamDecoderTellStatus streamTell(const FLAC__StreamDecoder*, FLAC__uint64* absoluteByteOffset, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ sf::Int64 position = data->stream->tell();
+ if (position >= 0)
+ {
+ *absoluteByteOffset = position;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+ else
+ {
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+ }
+
+ FLAC__StreamDecoderLengthStatus streamLength(const FLAC__StreamDecoder*, FLAC__uint64* streamLength, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ sf::Int64 count = data->stream->getSize();
+ if (count >= 0)
+ {
+ *streamLength = count;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+ else
+ {
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+ }
+
+ FLAC__bool streamEof(const FLAC__StreamDecoder*, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ return data->stream->tell() == data->stream->getSize();
+ }
+
+ FLAC__StreamDecoderWriteStatus streamWrite(const FLAC__StreamDecoder*, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ // Reserve memory if we're going to use the leftovers buffer
+ unsigned int frameSamples = frame->header.blocksize * frame->header.channels;
+ if (data->remaining < frameSamples)
+ data->leftovers.reserve(static_cast<std::size_t>(frameSamples - data->remaining));
+
+ // Decode the samples
+ for (unsigned i = 0; i < frame->header.blocksize; ++i)
+ {
+ for (unsigned int j = 0; j < frame->header.channels; ++j)
+ {
+ // Decode the current sample
+ sf::Int16 sample = 0;
+ switch (frame->header.bits_per_sample)
+ {
+ case 8:
+ sample = buffer[j][i] << 8;
+ break;
+ case 16:
+ sample = buffer[j][i];
+ break;
+ case 24:
+ sample = buffer[j][i] >> 8;
+ break;
+ case 32:
+ sample = buffer[j][i] >> 16;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ if (data->buffer && data->remaining > 0)
+ {
+ // If there's room in the output buffer, copy the sample there
+ *data->buffer++ = sample;
+ data->remaining--;
+ }
+ else
+ {
+ // We are either seeking (null buffer) or have decoded all the requested samples during a
+ // normal read (0 remaining), so we put the sample in a temporary buffer until next call
+ data->leftovers.push_back(sample);
+ }
+ }
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+
+ void streamMetadata(const FLAC__StreamDecoder*, const FLAC__StreamMetadata* meta, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+
+ if (meta->type == FLAC__METADATA_TYPE_STREAMINFO)
+ {
+ data->info.sampleCount = meta->data.stream_info.total_samples * meta->data.stream_info.channels;
+ data->info.sampleRate = meta->data.stream_info.sample_rate;
+ data->info.channelCount = meta->data.stream_info.channels;
+ }
+ }
+
+ void streamError(const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus, void* clientData)
+ {
+ sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
+ data->error = true;
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileReaderFlac::check(InputStream& stream)
+{
+ // Create a decoder
+ FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new();
+ if (!decoder)
+ return false;
+
+ // Initialize the decoder with our callbacks
+ ClientData data;
+ data.stream = &stream;
+ data.error = false;
+ FLAC__stream_decoder_init_stream(decoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof, &streamWrite, NULL, &streamError, &data);
+
+ // Read the header
+ bool valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder) != 0;
+
+ // Destroy the decoder
+ FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ return valid && !data.error;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReaderFlac::SoundFileReaderFlac() :
+m_decoder(NULL),
+m_clientData()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReaderFlac::~SoundFileReaderFlac()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
+{
+ // Create the decoder
+ m_decoder = FLAC__stream_decoder_new();
+ if (!m_decoder)
+ {
+ err() << "Failed to open FLAC file (failed to allocate the decoder)" << std::endl;
+ return false;
+ }
+
+ // Initialize the decoder with our callbacks
+ m_clientData.stream = &stream;
+ FLAC__stream_decoder_init_stream(m_decoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof, &streamWrite, &streamMetadata, &streamError, &m_clientData);
+
+ // Read the header
+ if (!FLAC__stream_decoder_process_until_end_of_metadata(m_decoder))
+ {
+ close();
+ err() << "Failed to open FLAC file (failed to read metadata)" << std::endl;
+ return false;
+ }
+
+ // Retrieve the sound properties
+ info = m_clientData.info; // was filled in the "metadata" callback
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileReaderFlac::seek(Uint64 sampleOffset)
+{
+ assert(m_decoder);
+
+ // Reset the callback data (the "write" callback will be called)
+ m_clientData.buffer = NULL;
+ m_clientData.remaining = 0;
+ m_clientData.leftovers.clear();
+
+ // FLAC decoder expects absolute sample offset, so we take the channel count out
+ if (sampleOffset < m_clientData.info.sampleCount)
+ {
+ // The "write" callback will populate the leftovers buffer with the first batch of samples from the
+ // seek destination, and since we want that data in this typical case, we don't re-clear it afterward
+ FLAC__stream_decoder_seek_absolute(m_decoder, sampleOffset / m_clientData.info.channelCount);
+ }
+ else
+ {
+ // FLAC decoder can't skip straight to EOF, so we short-seek by one sample and skip the rest
+ FLAC__stream_decoder_seek_absolute(m_decoder, (m_clientData.info.sampleCount / m_clientData.info.channelCount) - 1);
+ FLAC__stream_decoder_skip_single_frame(m_decoder);
+
+ // This was re-populated during the seek, but we're skipping everything in this, so we need it emptied
+ m_clientData.leftovers.clear();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 SoundFileReaderFlac::read(Int16* samples, Uint64 maxCount)
+{
+ assert(m_decoder);
+
+ // If there are leftovers from previous call, use it first
+ std::size_t left = m_clientData.leftovers.size();
+ if (left > 0)
+ {
+ if (left > maxCount)
+ {
+ // There are more leftovers than needed
+ std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.begin() + static_cast<std::size_t>(maxCount), samples);
+ std::vector<Int16> leftovers(m_clientData.leftovers.begin() + static_cast<std::size_t>(maxCount), m_clientData.leftovers.end());
+ m_clientData.leftovers.swap(leftovers);
+ return maxCount;
+ }
+ else
+ {
+ // We can use all the leftovers and decode new frames
+ std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.end(), samples);
+ }
+ }
+
+ // Reset the data that will be used in the callback
+ m_clientData.buffer = samples + left;
+ m_clientData.remaining = maxCount - left;
+ m_clientData.leftovers.clear();
+
+ // Decode frames one by one until we reach the requested sample count, the end of file or an error
+ while (m_clientData.remaining > 0)
+ {
+ // Everything happens in the "write" callback
+ // This will break on any fatal error (does not include EOF)
+ if (!FLAC__stream_decoder_process_single(m_decoder))
+ break;
+
+ // Break on EOF
+ if (FLAC__stream_decoder_get_state(m_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
+ break;
+ }
+
+ return maxCount - m_clientData.remaining;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileReaderFlac::close()
+{
+ if (m_decoder)
+ {
+ FLAC__stream_decoder_finish(m_decoder);
+ FLAC__stream_decoder_delete(m_decoder);
+ m_decoder = NULL;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileReaderFlac.hpp b/src/SFML/Audio/SoundFileReaderFlac.hpp
new file mode 100644
index 0000000..6cb0b86
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderFlac.hpp
@@ -0,0 +1,144 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEREADERFLAC_HPP
+#define SFML_SOUNDFILEREADERFLAC_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReader.hpp>
+#include <FLAC/stream_decoder.h>
+#include <string>
+#include <vector>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file reader that handles FLAC files
+///
+////////////////////////////////////////////////////////////
+class SoundFileReaderFlac : public SoundFileReader
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this reader can handle a file given by an input stream
+ ///
+ /// \param stream Source stream to check
+ ///
+ /// \return True if the file is supported by this reader
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(InputStream& stream);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileReaderFlac();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SoundFileReaderFlac();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open a sound file for reading
+ ///
+ /// \param stream Stream to open
+ /// \param info Structure to fill with the attributes of the loaded sound
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool open(sf::InputStream& stream, Info& info);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current read position to the given sample offset
+ ///
+ /// The sample offset takes the channels into account.
+ /// If you have a time offset instead, you can easily find
+ /// the corresponding sample offset with the following formula:
+ /// `timeInSeconds * 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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Hold the state that is passed to the decoder callbacks
+ ///
+ ////////////////////////////////////////////////////////////
+ struct ClientData
+ {
+ InputStream* stream;
+ SoundFileReader::Info info;
+ Int16* buffer;
+ Uint64 remaining;
+ std::vector<Int16> leftovers;
+ bool error;
+ };
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the open FLAC file
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ FLAC__StreamDecoder* m_decoder; ///< FLAC decoder
+ ClientData m_clientData; ///< Structure passed to the decoder callbacks
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEREADERFLAC_HPP
diff --git a/src/SFML/Audio/SoundFileReaderOgg.cpp b/src/SFML/Audio/SoundFileReaderOgg.cpp
new file mode 100644
index 0000000..183e3b2
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderOgg.cpp
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReaderOgg.hpp>
+#include <SFML/System/MemoryInputStream.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+
+
+namespace
+{
+ size_t read(void* ptr, size_t size, size_t nmemb, void* data)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(data);
+ return static_cast<std::size_t>(stream->read(ptr, size * nmemb));
+ }
+
+ int seek(void* data, ogg_int64_t offset, int whence)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(data);
+ switch (whence)
+ {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += stream->tell();
+ break;
+ case SEEK_END:
+ offset = stream->getSize() - offset;
+ }
+ return static_cast<int>(stream->seek(offset));
+ }
+
+ long tell(void* data)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(data);
+ return static_cast<long>(stream->tell());
+ }
+
+ static ov_callbacks callbacks = {&read, &seek, NULL, &tell};
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileReaderOgg::check(InputStream& stream)
+{
+ OggVorbis_File file;
+ if (ov_test_callbacks(&stream, &file, NULL, 0, callbacks) == 0)
+ {
+ ov_clear(&file);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReaderOgg::SoundFileReaderOgg() :
+m_vorbis (),
+m_channelCount(0)
+{
+ m_vorbis.datasource = NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReaderOgg::~SoundFileReaderOgg()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileReaderOgg::open(InputStream& stream, Info& info)
+{
+ // Open the Vorbis stream
+ int status = ov_open_callbacks(&stream, &m_vorbis, NULL, 0, callbacks);
+ if (status < 0)
+ {
+ err() << "Failed to open Vorbis file for reading" << std::endl;
+ return false;
+ }
+
+ // Retrieve the music attributes
+ vorbis_info* vorbisInfo = ov_info(&m_vorbis, -1);
+ info.channelCount = vorbisInfo->channels;
+ info.sampleRate = vorbisInfo->rate;
+ info.sampleCount = static_cast<std::size_t>(ov_pcm_total(&m_vorbis, -1) * vorbisInfo->channels);
+
+ // We must keep the channel count for the seek function
+ m_channelCount = info.channelCount;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileReaderOgg::seek(Uint64 sampleOffset)
+{
+ assert(m_vorbis.datasource);
+
+ ov_pcm_seek(&m_vorbis, sampleOffset / m_channelCount);
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 SoundFileReaderOgg::read(Int16* samples, Uint64 maxCount)
+{
+ assert(m_vorbis.datasource);
+
+ // Try to read the requested number of samples, stop only on error or end of file
+ Uint64 count = 0;
+ while (count < maxCount)
+ {
+ int bytesToRead = static_cast<int>(maxCount - count) * sizeof(Int16);
+ long bytesRead = ov_read(&m_vorbis, reinterpret_cast<char*>(samples), bytesToRead, 0, 2, 1, NULL);
+ if (bytesRead > 0)
+ {
+ long samplesRead = bytesRead / sizeof(Int16);
+ count += samplesRead;
+ samples += samplesRead;
+ }
+ else
+ {
+ // error or end of file
+ break;
+ }
+ }
+
+ return count;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileReaderOgg::close()
+{
+ if (m_vorbis.datasource)
+ {
+ ov_clear(&m_vorbis);
+ m_vorbis.datasource = NULL;
+ m_channelCount = 0;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileReaderOgg.hpp b/src/SFML/Audio/SoundFileReaderOgg.hpp
new file mode 100644
index 0000000..0e84e8f
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderOgg.hpp
@@ -0,0 +1,128 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEREADEROGG_HPP
+#define SFML_SOUNDFILEREADEROGG_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReader.hpp>
+#include <vorbis/vorbisfile.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file reader that handles OGG/Vorbis files
+///
+////////////////////////////////////////////////////////////
+class SoundFileReaderOgg : public SoundFileReader
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this reader can handle a file given by an input stream
+ ///
+ /// \param stream Source stream to check
+ ///
+ /// \return True if the file is supported by this reader
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(InputStream& stream);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileReaderOgg();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SoundFileReaderOgg();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open a sound file for reading
+ ///
+ /// \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);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current read position to the given sample offset
+ ///
+ /// The sample offset takes the channels into account.
+ /// If you have a time offset instead, you can easily find
+ /// the corresponding sample offset with the following formula:
+ /// `timeInSeconds * 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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the open Vorbis file
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ OggVorbis_File m_vorbis; // ogg/vorbis file handle
+ unsigned int m_channelCount; // number of channels of the open sound file
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEREADEROGG_HPP
diff --git a/src/SFML/Audio/SoundFileReaderWav.cpp b/src/SFML/Audio/SoundFileReaderWav.cpp
new file mode 100644
index 0000000..84d92c1
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderWav.cpp
@@ -0,0 +1,357 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReaderWav.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+#include <cstring>
+
+
+namespace
+{
+ // The following functions read integers as little endian and
+ // return them in the host byte order
+
+ bool decode(sf::InputStream& stream, sf::Uint8& value)
+ {
+ return stream.read(&value, sizeof(value)) == sizeof(value);
+ }
+
+ bool decode(sf::InputStream& stream, sf::Int16& value)
+ {
+ unsigned char bytes[sizeof(value)];
+ if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
+ return false;
+
+ value = bytes[0] | (bytes[1] << 8);
+
+ return true;
+ }
+
+ bool decode(sf::InputStream& stream, sf::Uint16& value)
+ {
+ unsigned char bytes[sizeof(value)];
+ if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
+ return false;
+
+ value = bytes[0] | (bytes[1] << 8);
+
+ return true;
+ }
+
+ bool decode24bit(sf::InputStream& stream, sf::Uint32& value)
+ {
+ unsigned char bytes[3];
+ if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
+ return false;
+
+ value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16);
+
+ return true;
+ }
+
+ bool decode(sf::InputStream& stream, sf::Uint32& value)
+ {
+ unsigned char bytes[sizeof(value)];
+ if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
+ return false;
+
+ value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
+
+ return true;
+ }
+
+ const sf::Uint64 mainChunkSize = 12;
+
+ const sf::Uint16 waveFormatPcm = 1;
+
+ const sf::Uint16 waveFormatExtensible= 65534;
+
+ const char* waveSubformatPcm =
+ "\x01\x00\x00\x00\x00\x00\x10\x00"
+ "\x80\x00\x00\xAA\x00\x38\x9B\x71";
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileReaderWav::check(InputStream& stream)
+{
+ char header[mainChunkSize];
+ if (stream.read(header, sizeof(header)) < static_cast<Int64>(sizeof(header)))
+ return false;
+
+ return (header[0] == 'R') && (header[1] == 'I') && (header[2] == 'F') && (header[3] == 'F')
+ && (header[8] == 'W') && (header[9] == 'A') && (header[10] == 'V') && (header[11] == 'E');
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileReaderWav::SoundFileReaderWav() :
+m_stream (NULL),
+m_bytesPerSample(0),
+m_dataStart (0),
+m_dataEnd (0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileReaderWav::open(InputStream& stream, Info& info)
+{
+ m_stream = &stream;
+
+ if (!parseHeader(info))
+ {
+ err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileReaderWav::seek(Uint64 sampleOffset)
+{
+ assert(m_stream);
+
+ m_stream->seek(m_dataStart + sampleOffset * m_bytesPerSample);
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 SoundFileReaderWav::read(Int16* samples, Uint64 maxCount)
+{
+ assert(m_stream);
+
+ Uint64 count = 0;
+ Uint64 startPos = m_stream->tell();
+
+ // Tracking of m_dataEnd is important to prevent sf::Music from reading
+ // data until EOF, as WAV files may have metadata at the end.
+ while ((count < maxCount) && (startPos + count * m_bytesPerSample < m_dataEnd))
+ {
+ switch (m_bytesPerSample)
+ {
+ case 1:
+ {
+ Uint8 sample = 0;
+ if (decode(*m_stream, sample))
+ *samples++ = (static_cast<Int16>(sample) - 128) << 8;
+ else
+ return count;
+ break;
+ }
+
+ case 2:
+ {
+ Int16 sample = 0;
+ if (decode(*m_stream, sample))
+ *samples++ = sample;
+ else
+ return count;
+ break;
+ }
+
+ case 3:
+ {
+ Uint32 sample = 0;
+ if (decode24bit(*m_stream, sample))
+ *samples++ = sample >> 8;
+ else
+ return count;
+ break;
+ }
+
+ case 4:
+ {
+ Uint32 sample = 0;
+ if (decode(*m_stream, sample))
+ *samples++ = sample >> 16;
+ else
+ return count;
+ break;
+ }
+
+ default:
+ {
+ assert(false);
+ return 0;
+ }
+ }
+
+ ++count;
+ }
+
+ return count;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileReaderWav::parseHeader(Info& info)
+{
+ assert(m_stream);
+
+ // If we are here, it means that the first part of the header
+ // (the format) has already been checked
+ char mainChunk[mainChunkSize];
+ if (m_stream->read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk))
+ return false;
+
+ // Parse all the sub-chunks
+ bool dataChunkFound = false;
+ while (!dataChunkFound)
+ {
+ // Parse the sub-chunk id and size
+ char subChunkId[4];
+ if (m_stream->read(subChunkId, sizeof(subChunkId)) != sizeof(subChunkId))
+ return false;
+ Uint32 subChunkSize = 0;
+ if (!decode(*m_stream, subChunkSize))
+ return false;
+ Int64 subChunkStart = m_stream->tell();
+ if (subChunkStart == -1)
+ return false;
+
+ // Check which chunk it is
+ if ((subChunkId[0] == 'f') && (subChunkId[1] == 'm') && (subChunkId[2] == 't') && (subChunkId[3] == ' '))
+ {
+ // "fmt" chunk
+
+ // Audio format
+ Uint16 format = 0;
+ if (!decode(*m_stream, format))
+ return false;
+ if ((format != waveFormatPcm) && (format != waveFormatExtensible))
+ return false;
+
+ // Channel count
+ Uint16 channelCount = 0;
+ if (!decode(*m_stream, channelCount))
+ return false;
+ info.channelCount = channelCount;
+
+ // Sample rate
+ Uint32 sampleRate = 0;
+ if (!decode(*m_stream, sampleRate))
+ return false;
+ info.sampleRate = sampleRate;
+
+ // Byte rate
+ Uint32 byteRate = 0;
+ if (!decode(*m_stream, byteRate))
+ return false;
+
+ // Block align
+ Uint16 blockAlign = 0;
+ if (!decode(*m_stream, blockAlign))
+ return false;
+
+ // Bits per sample
+ Uint16 bitsPerSample = 0;
+ if (!decode(*m_stream, bitsPerSample))
+ return false;
+ if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32)
+ {
+ err() << "Unsupported sample size: " << bitsPerSample << " bit (Supported sample sizes are 8/16/24/32 bit)" << std::endl;
+ return false;
+ }
+ m_bytesPerSample = bitsPerSample / 8;
+
+ if (format == waveFormatExtensible)
+ {
+ // Extension size
+ Uint16 extensionSize = 0;
+ if (!decode(*m_stream, extensionSize))
+ return false;
+
+ // Valid bits per sample
+ Uint16 validBitsPerSample = 0;
+ if (!decode(*m_stream, validBitsPerSample))
+ return false;
+
+ // Channel mask
+ Uint32 channelMask = 0;
+ if (!decode(*m_stream, channelMask))
+ return false;
+
+ // Subformat
+ char subformat[16];
+ if (m_stream->read(subformat, sizeof(subformat)) != sizeof(subformat))
+ return false;
+
+ if (std::memcmp(subformat, waveSubformatPcm, sizeof(subformat)) != 0)
+ {
+ err() << "Unsupported format: extensible format with non-PCM subformat" << std::endl;
+ return false;
+ }
+
+ if (validBitsPerSample != bitsPerSample)
+ {
+ err() << "Unsupported format: sample size (" << validBitsPerSample << " bits) and "
+ "sample container size (" << bitsPerSample << " bits) differ" << std::endl;
+ return false;
+ }
+ }
+
+ // Skip potential extra information
+ if (m_stream->seek(subChunkStart + subChunkSize) == -1)
+ return false;
+ }
+ else if ((subChunkId[0] == 'd') && (subChunkId[1] == 'a') && (subChunkId[2] == 't') && (subChunkId[3] == 'a'))
+ {
+ // "data" chunk
+
+ // Compute the total number of samples
+ info.sampleCount = subChunkSize / m_bytesPerSample;
+
+ // Store the start and end position of samples in the file
+ m_dataStart = subChunkStart;
+ m_dataEnd = m_dataStart + info.sampleCount * m_bytesPerSample;
+
+ dataChunkFound = true;
+ }
+ else
+ {
+ // unknown chunk, skip it
+ if (m_stream->seek(m_stream->tell() + subChunkSize) == -1)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileReaderWav.hpp b/src/SFML/Audio/SoundFileReaderWav.hpp
new file mode 100644
index 0000000..65adb8d
--- /dev/null
+++ b/src/SFML/Audio/SoundFileReaderWav.hpp
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEREADERWAV_HPP
+#define SFML_SOUNDFILEREADERWAV_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileReader.hpp>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file reader that handles wav files
+///
+////////////////////////////////////////////////////////////
+class SoundFileReaderWav : public SoundFileReader
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this reader can handle a file given by an input stream
+ ///
+ /// \param stream Source stream to check
+ ///
+ /// \return True if the file is supported by this reader
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(InputStream& stream);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileReaderWav();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open a sound file for reading
+ ///
+ /// \param stream Stream to open
+ /// \param info Structure to fill with the attributes of the loaded sound
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool open(sf::InputStream& stream, Info& info);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current read position to the given sample offset
+ ///
+ /// The sample offset takes the channels into account.
+ /// If you have a time offset instead, you can easily find
+ /// the corresponding sample offset with the following formula:
+ /// `timeInSeconds * 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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Read the header of the open file
+ ///
+ /// \param info Attributes of the sound file
+ ///
+ /// \return True on success, false on error
+ ///
+ ////////////////////////////////////////////////////////////
+ bool parseHeader(Info& info);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ InputStream* m_stream; ///< Source stream to read from
+ unsigned int m_bytesPerSample; ///< Size of a sample, in bytes
+ Uint64 m_dataStart; ///< Starting position of the audio data in the open file
+ Uint64 m_dataEnd; ///< Position one byte past the end of the audio data in the open file
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEREADERWAV_HPP
diff --git a/src/SFML/Audio/SoundFileWriterFlac.cpp b/src/SFML/Audio/SoundFileWriterFlac.cpp
new file mode 100644
index 0000000..045d086
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterFlac.cpp
@@ -0,0 +1,133 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriterFlac.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileWriterFlac::check(const std::string& filename)
+{
+ std::string extension = filename.substr(filename.find_last_of(".") + 1);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+
+ return extension == "flac";
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterFlac::SoundFileWriterFlac() :
+m_encoder (NULL),
+m_channelCount(0),
+m_samples32 ()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterFlac::~SoundFileWriterFlac()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileWriterFlac::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
+{
+ // Create the encoder
+ m_encoder = FLAC__stream_encoder_new();
+ if (!m_encoder)
+ {
+ err() << "Failed to write flac file \"" << filename << "\" (failed to allocate encoder)" << std::endl;
+ return false;
+ }
+
+ // Setup the encoder
+ FLAC__stream_encoder_set_channels(m_encoder, channelCount);
+ FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16);
+ FLAC__stream_encoder_set_sample_rate(m_encoder, sampleRate);
+
+ // Initialize the output stream
+ if (FLAC__stream_encoder_init_file(m_encoder, filename.c_str(), NULL, NULL) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+ {
+ err() << "Failed to write flac file \"" << filename << "\" (failed to open the file)" << std::endl;
+ close();
+ return false;
+ }
+
+ // Store the channel count
+ m_channelCount = channelCount;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterFlac::write(const Int16* samples, Uint64 count)
+{
+ while (count > 0)
+ {
+ // Make sure that we don't process too many samples at once
+ unsigned int frames = std::min(static_cast<unsigned int>(count / m_channelCount), 10000u);
+
+ // Convert the samples to 32-bits
+ m_samples32.assign(samples, samples + frames * m_channelCount);
+
+ // Write them to the FLAC stream
+ FLAC__stream_encoder_process_interleaved(m_encoder, &m_samples32[0], frames);
+
+ // Next chunk
+ count -= m_samples32.size();
+ samples += m_samples32.size();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterFlac::close()
+{
+ if (m_encoder)
+ {
+ // Close the output stream
+ FLAC__stream_encoder_finish(m_encoder);
+
+ // Destroy the encoder
+ FLAC__stream_encoder_delete(m_encoder);
+ m_encoder = NULL;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileWriterFlac.hpp b/src/SFML/Audio/SoundFileWriterFlac.hpp
new file mode 100644
index 0000000..b6382e0
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterFlac.hpp
@@ -0,0 +1,114 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEWRITERFLAC_HPP
+#define SFML_SOUNDFILEWRITERFLAC_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriter.hpp>
+#include <FLAC/stream_encoder.h>
+#include <vector>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file writer that handles FLAC files
+///
+////////////////////////////////////////////////////////////
+class SoundFileWriterFlac : public SoundFileWriter
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this writer can handle a file on disk
+ ///
+ /// \param filename Path of the sound file to check
+ ///
+ /// \return True if the file can be written by this writer
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(const std::string& filename);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileWriterFlac();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SoundFileWriterFlac();
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the file
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ FLAC__StreamEncoder* m_encoder; ///< FLAC stream encoder
+ unsigned int m_channelCount; ///< Number of channels
+ std::vector<Int32> m_samples32; ///< Conversion buffer
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEWRITERFLAC_HPP
diff --git a/src/SFML/Audio/SoundFileWriterOgg.cpp b/src/SFML/Audio/SoundFileWriterOgg.cpp
new file mode 100644
index 0000000..56e2ac7
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterOgg.cpp
@@ -0,0 +1,216 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriterOgg.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <cstdlib>
+#include <cassert>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileWriterOgg::check(const std::string& filename)
+{
+ std::string extension = filename.substr(filename.find_last_of(".") + 1);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+
+ return extension == "ogg";
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterOgg::SoundFileWriterOgg() :
+m_channelCount(0),
+m_file (),
+m_ogg (),
+m_vorbis (),
+m_state ()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterOgg::~SoundFileWriterOgg()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileWriterOgg::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
+{
+ // Save the channel count
+ m_channelCount = channelCount;
+
+ // Initialize the ogg/vorbis stream
+ ogg_stream_init(&m_ogg, std::rand());
+ vorbis_info_init(&m_vorbis);
+
+ // Setup the encoder: VBR, automatic bitrate management
+ // Quality is in range [-1 .. 1], 0.4 gives ~128 kbps for a 44 KHz stereo sound
+ int status = vorbis_encode_init_vbr(&m_vorbis, channelCount, sampleRate, 0.4f);
+ if (status < 0)
+ {
+ err() << "Failed to write ogg/vorbis file \"" << filename << "\" (unsupported bitrate)" << std::endl;
+ close();
+ return false;
+ }
+ vorbis_analysis_init(&m_state, &m_vorbis);
+
+ // Open the file after the vorbis setup is ok
+ m_file.open(filename.c_str(), std::ios::binary);
+ if (!m_file)
+ {
+ err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot open file)" << std::endl;
+ close();
+ return false;
+ }
+
+ // Generate header metadata (leave it empty)
+ vorbis_comment comment;
+ vorbis_comment_init(&comment);
+
+ // Generate the header packets
+ ogg_packet header, headerComm, headerCode;
+ status = vorbis_analysis_headerout(&m_state, &comment, &header, &headerComm, &headerCode);
+ vorbis_comment_clear(&comment);
+ if (status < 0)
+ {
+ err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot generate the headers)" << std::endl;
+ close();
+ return false;
+ }
+
+ // Write the header packets to the ogg stream
+ ogg_stream_packetin(&m_ogg, &header);
+ ogg_stream_packetin(&m_ogg, &headerComm);
+ ogg_stream_packetin(&m_ogg, &headerCode);
+
+ // This ensures the actual audio data will start on a new page, as per spec
+ ogg_page page;
+ while (ogg_stream_flush(&m_ogg, &page) > 0)
+ {
+ m_file.write(reinterpret_cast<const char*>(page.header), page.header_len);
+ m_file.write(reinterpret_cast<const char*>(page.body), page.body_len);
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterOgg::write(const Int16* samples, Uint64 count)
+{
+ // Vorbis has issues with buffers that are too large, so we ask for 64K
+ static const int bufferSize = 65536;
+
+ // A frame contains a sample from each channel
+ int frameCount = static_cast<int>(count / m_channelCount);
+
+ while (frameCount > 0)
+ {
+ // Prepare a buffer to hold our samples
+ float** buffer = vorbis_analysis_buffer(&m_state, bufferSize);
+ assert(buffer);
+
+ // Write the samples to the buffer, converted to float
+ for (int i = 0; i < std::min(frameCount, bufferSize); ++i)
+ for (unsigned int j = 0; j < m_channelCount; ++j)
+ buffer[j][i] = *samples++ / 32767.0f;
+
+ // Tell the library how many samples we've written
+ vorbis_analysis_wrote(&m_state, std::min(frameCount, bufferSize));
+
+ frameCount -= bufferSize;
+
+ // Flush any produced block
+ flushBlocks();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterOgg::flushBlocks()
+{
+ // Let the library divide uncompressed data into blocks, and process them
+ vorbis_block block;
+ vorbis_block_init(&m_state, &block);
+ while (vorbis_analysis_blockout(&m_state, &block) == 1)
+ {
+ // Let the automatic bitrate management do its job
+ vorbis_analysis(&block, NULL);
+ vorbis_bitrate_addblock(&block);
+
+ // Get new packets from the bitrate management engine
+ ogg_packet packet;
+ while (vorbis_bitrate_flushpacket(&m_state, &packet))
+ {
+ // Write the packet to the ogg stream
+ ogg_stream_packetin(&m_ogg, &packet);
+
+ // If the stream produced new pages, write them to the output file
+ ogg_page page;
+ while (ogg_stream_flush(&m_ogg, &page) > 0)
+ {
+ m_file.write(reinterpret_cast<const char*>(page.header), page.header_len);
+ m_file.write(reinterpret_cast<const char*>(page.body), page.body_len);
+ }
+ }
+ }
+
+ // Clear the allocated block
+ vorbis_block_clear(&block);
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterOgg::close()
+{
+ if (m_file.is_open())
+ {
+ // Submit an empty packet to mark the end of stream
+ vorbis_analysis_wrote(&m_state, 0);
+ flushBlocks();
+
+ // Close the file
+ m_file.close();
+ }
+
+ // Clear all the ogg/vorbis structures
+ ogg_stream_clear(&m_ogg);
+ vorbis_dsp_clear(&m_state);
+ vorbis_info_clear(&m_vorbis);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileWriterOgg.hpp b/src/SFML/Audio/SoundFileWriterOgg.hpp
new file mode 100644
index 0000000..4b4d19b
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterOgg.hpp
@@ -0,0 +1,122 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEWRITEROGG_HPP
+#define SFML_SOUNDFILEWRITEROGG_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriter.hpp>
+#include <vorbis/vorbisenc.h>
+#include <fstream>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file writer that handles OGG/Vorbis files
+///
+////////////////////////////////////////////////////////////
+class SoundFileWriterOgg : public SoundFileWriter
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this writer can handle a file on disk
+ ///
+ /// \param filename Path of the sound file to check
+ ///
+ /// \return True if the file can be written by this writer
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(const std::string& filename);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileWriterOgg();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SoundFileWriterOgg();
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Flush blocks produced by the ogg stream, if any
+ ///
+ ////////////////////////////////////////////////////////////
+ void flushBlocks();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the file
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ unsigned int m_channelCount; // channel count of the sound being written
+ std::ofstream m_file; // output file
+ ogg_stream_state m_ogg; // ogg stream
+ vorbis_info m_vorbis; // vorbis handle
+ vorbis_dsp_state m_state; // current encoding state
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEWRITEROGG_HPP
diff --git a/src/SFML/Audio/SoundFileWriterWav.cpp b/src/SFML/Audio/SoundFileWriterWav.cpp
new file mode 100644
index 0000000..153e148
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterWav.cpp
@@ -0,0 +1,201 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriterWav.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+
+
+namespace
+{
+ // The following functions takes integers in host byte order
+ // and writes them to a stream as little endian
+
+ void encode(std::ostream& stream, sf::Int16 value)
+ {
+ unsigned char bytes[] =
+ {
+ static_cast<unsigned char>(value & 0xFF),
+ static_cast<unsigned char>(value >> 8)
+ };
+ stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
+ }
+
+ void encode(std::ostream& stream, sf::Uint16 value)
+ {
+ unsigned char bytes[] =
+ {
+ static_cast<unsigned char>(value & 0xFF),
+ static_cast<unsigned char>(value >> 8)
+ };
+ stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
+ }
+
+ void encode(std::ostream& stream, sf::Uint32 value)
+ {
+ unsigned char bytes[] =
+ {
+ static_cast<unsigned char>(value & 0x000000FF),
+ static_cast<unsigned char>((value & 0x0000FF00) >> 8),
+ static_cast<unsigned char>((value & 0x00FF0000) >> 16),
+ static_cast<unsigned char>((value & 0xFF000000) >> 24),
+ };
+ stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool SoundFileWriterWav::check(const std::string& filename)
+{
+ std::string extension = filename.substr(filename.find_last_of(".") + 1);
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+
+ return extension == "wav";
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterWav::SoundFileWriterWav() :
+m_file()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+SoundFileWriterWav::~SoundFileWriterWav()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileWriterWav::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
+{
+ // Open the file
+ m_file.open(filename.c_str(), std::ios::binary);
+ if (!m_file)
+ {
+ err() << "Failed to open WAV sound file \"" << filename << "\" for writing" << std::endl;
+ return false;
+ }
+
+ // Write the header
+ if (!writeHeader(sampleRate, channelCount))
+ {
+ err() << "Failed to write header of WAV sound file \"" << filename << "\"" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterWav::write(const Int16* samples, Uint64 count)
+{
+ assert(m_file.good());
+
+ while (count--)
+ encode(m_file, *samples++);
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int channelCount)
+{
+ assert(m_file.good());
+
+ // Write the main chunk ID
+ char mainChunkId[4] = {'R', 'I', 'F', 'F'};
+ m_file.write(mainChunkId, sizeof(mainChunkId));
+
+ // Write the main chunk header
+ Uint32 mainChunkSize = 0; // placeholder, will be written later
+ encode(m_file, mainChunkSize);
+ char mainChunkFormat[4] = {'W', 'A', 'V', 'E'};
+ m_file.write(mainChunkFormat, sizeof(mainChunkFormat));
+
+ // Write the sub-chunk 1 ("format") id and size
+ char fmtChunkId[4] = {'f', 'm', 't', ' '};
+ m_file.write(fmtChunkId, sizeof(fmtChunkId));
+ Uint32 fmtChunkSize = 16;
+ encode(m_file, fmtChunkSize);
+
+ // Write the format (PCM)
+ Uint16 format = 1;
+ encode(m_file, format);
+
+ // Write the sound attributes
+ encode(m_file, static_cast<Uint16>(channelCount));
+ encode(m_file, static_cast<Uint32>(sampleRate));
+ Uint32 byteRate = sampleRate * channelCount * 2;
+ encode(m_file, byteRate);
+ Uint16 blockAlign = channelCount * 2;
+ encode(m_file, blockAlign);
+ Uint16 bitsPerSample = 16;
+ encode(m_file, bitsPerSample);
+
+ // Write the sub-chunk 2 ("data") id and size
+ char dataChunkId[4] = {'d', 'a', 't', 'a'};
+ m_file.write(dataChunkId, sizeof(dataChunkId));
+ Uint32 dataChunkSize = 0; // placeholder, will be written later
+ encode(m_file, dataChunkSize);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundFileWriterWav::close()
+{
+ // If the file is open, finalize the header and close it
+ if (m_file.is_open())
+ {
+ m_file.flush();
+
+ // Update the main chunk size and data sub-chunk size
+ Uint32 fileSize = static_cast<Uint32>(m_file.tellp());
+ Uint32 mainChunkSize = fileSize - 8; // 8 bytes RIFF header
+ Uint32 dataChunkSize = fileSize - 44; // 44 bytes RIFF + WAVE headers
+ m_file.seekp(4);
+ encode(m_file, mainChunkSize);
+ m_file.seekp(40);
+ encode(m_file, dataChunkSize);
+
+ m_file.close();
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundFileWriterWav.hpp b/src/SFML/Audio/SoundFileWriterWav.hpp
new file mode 100644
index 0000000..d8dcc17
--- /dev/null
+++ b/src/SFML/Audio/SoundFileWriterWav.hpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOUNDFILEWRITERWAV_HPP
+#define SFML_SOUNDFILEWRITERWAV_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundFileWriter.hpp>
+#include <fstream>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Implementation of sound file writer that handles wav files
+///
+////////////////////////////////////////////////////////////
+class SoundFileWriterWav : public SoundFileWriter
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if this writer can handle a file on disk
+ ///
+ /// \param filename Path of the sound file to check
+ ///
+ /// \return True if the file can be written by this writer
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool check(const std::string& filename);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SoundFileWriterWav();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SoundFileWriterWav();
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+ ////////////////////////////////////////////////////////////
+ /// \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);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Write the header of the open file
+ ///
+ /// \param sampleRate Sample rate of the sound
+ /// \param channelCount Number of channels of the sound
+ ///
+ /// \return True on success, false on error
+ ///
+ ////////////////////////////////////////////////////////////
+ bool writeHeader(unsigned int sampleRate, unsigned int channelCount);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the file
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ std::ofstream m_file; ///< File stream to write to
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOUNDFILEWRITERWAV_HPP
diff --git a/src/SFML/Audio/SoundRecorder.cpp b/src/SFML/Audio/SoundRecorder.cpp
new file mode 100644
index 0000000..4281b98
--- /dev/null
+++ b/src/SFML/Audio/SoundRecorder.cpp
@@ -0,0 +1,330 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundRecorder.hpp>
+#include <SFML/Audio/AudioDevice.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Err.hpp>
+#include <cstring>
+#include <cassert>
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4355) // 'this' used in base member initializer list
+#endif
+
+
+namespace
+{
+ ALCdevice* captureDevice = NULL;
+}
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+SoundRecorder::SoundRecorder() :
+m_thread (&SoundRecorder::record, this),
+m_sampleRate (0),
+m_processingInterval(milliseconds(100)),
+m_isCapturing (false),
+m_deviceName (getDefaultDevice()),
+m_channelCount (1)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+SoundRecorder::~SoundRecorder()
+{
+ // This assertion is triggered if the recording is still running while
+ // the object is destroyed. It ensures that stop() is called in the
+ // destructor of the derived class, which makes sure that the recording
+ // thread finishes before the derived object is destroyed. Otherwise a
+ // "pure virtual method called" exception is triggered.
+ assert(!m_isCapturing && "You must call stop() in the destructor of your derived class, so that the recording thread finishes before your object is destroyed.");
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundRecorder::start(unsigned int sampleRate)
+{
+ // Check if the device can do audio capture
+ if (!isAvailable())
+ {
+ err() << "Failed to start capture: your system cannot capture audio data (call SoundRecorder::isAvailable to check it)" << std::endl;
+ return false;
+ }
+
+ // Check that another capture is not already running
+ if (captureDevice)
+ {
+ err() << "Trying to start audio capture, but another capture is already running" << std::endl;
+ return false;
+ }
+
+ // Determine the recording format
+ ALCenum format = (m_channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
+
+ // Open the capture device for capturing 16 bits samples
+ captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), sampleRate, format, sampleRate);
+ if (!captureDevice)
+ {
+ err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
+ return false;
+ }
+
+ // Clear the array of samples
+ m_samples.clear();
+
+ // Store the sample rate
+ m_sampleRate = sampleRate;
+
+ // Notify derived class
+ if (onStart())
+ {
+ // Start the capture
+ alcCaptureStart(captureDevice);
+
+ // Start the capture in a new thread, to avoid blocking the main thread
+ m_isCapturing = true;
+ m_thread.launch();
+
+ return true;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::stop()
+{
+ // Stop the capturing thread if there is one
+ if (m_isCapturing)
+ {
+ m_isCapturing = false;
+ m_thread.wait();
+
+ // Notify derived class
+ onStop();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundRecorder::getSampleRate() const
+{
+ return m_sampleRate;
+}
+
+
+////////////////////////////////////////////////////////////
+std::vector<std::string> SoundRecorder::getAvailableDevices()
+{
+ std::vector<std::string> deviceNameList;
+
+ const ALchar* deviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+ if (deviceList)
+ {
+ while (*deviceList)
+ {
+ deviceNameList.push_back(deviceList);
+ deviceList += std::strlen(deviceList) + 1;
+ }
+ }
+
+ return deviceNameList;
+}
+
+
+////////////////////////////////////////////////////////////
+std::string SoundRecorder::getDefaultDevice()
+{
+ return alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundRecorder::setDevice(const std::string& name)
+{
+ // Store the device name
+ if (name.empty())
+ m_deviceName = getDefaultDevice();
+ else
+ m_deviceName = name;
+
+ if (m_isCapturing)
+ {
+ // Stop the capturing thread
+ m_isCapturing = false;
+ m_thread.wait();
+
+ // Determine the recording format
+ ALCenum format = (m_channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
+
+ // Open the requested capture device for capturing 16 bits samples
+ captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), m_sampleRate, format, m_sampleRate);
+ if (!captureDevice)
+ {
+ // Notify derived class
+ onStop();
+
+ err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
+ return false;
+ }
+
+ // Start the capture
+ alcCaptureStart(captureDevice);
+
+ // Start the capture in a new thread, to avoid blocking the main thread
+ m_isCapturing = true;
+ m_thread.launch();
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+const std::string& SoundRecorder::getDevice() const
+{
+ return m_deviceName;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::setChannelCount(unsigned int channelCount)
+{
+ if (m_isCapturing)
+ {
+ err() << "It's not possible to change the channels while recording." << std::endl;
+ return;
+ }
+
+ if (channelCount < 1 || channelCount > 2)
+ {
+ err() << "Unsupported channel count: " << channelCount << " Currently only mono (1) and stereo (2) recording is supported." << std::endl;
+ return;
+ }
+
+ m_channelCount = channelCount;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundRecorder::getChannelCount() const
+{
+ return m_channelCount;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundRecorder::isAvailable()
+{
+ return (priv::AudioDevice::isExtensionSupported("ALC_EXT_CAPTURE") != AL_FALSE) ||
+ (priv::AudioDevice::isExtensionSupported("ALC_EXT_capture") != AL_FALSE); // "bug" in Mac OS X 10.5 and 10.6
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::setProcessingInterval(Time interval)
+{
+ m_processingInterval = interval;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundRecorder::onStart()
+{
+ // Nothing to do
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::onStop()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::record()
+{
+ while (m_isCapturing)
+ {
+ // Process available samples
+ processCapturedSamples();
+
+ // Don't bother the CPU while waiting for more captured data
+ sleep(m_processingInterval);
+ }
+
+ // Capture is finished: clean up everything
+ cleanup();
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::processCapturedSamples()
+{
+ // Get the number of samples available
+ ALCint samplesAvailable;
+ alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable);
+
+ if (samplesAvailable > 0)
+ {
+ // Get the recorded samples
+ m_samples.resize(samplesAvailable * getChannelCount());
+ alcCaptureSamples(captureDevice, &m_samples[0], samplesAvailable);
+
+ // Forward them to the derived class
+ if (!onProcessSamples(&m_samples[0], m_samples.size()))
+ {
+ // The user wants to stop the capture
+ m_isCapturing = false;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundRecorder::cleanup()
+{
+ // Stop the capture
+ alcCaptureStop(captureDevice);
+
+ // Get the samples left in the buffer
+ processCapturedSamples();
+
+ // Close the device
+ alcCaptureCloseDevice(captureDevice);
+ captureDevice = NULL;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundSource.cpp b/src/SFML/Audio/SoundSource.cpp
new file mode 100644
index 0000000..785f9cc
--- /dev/null
+++ b/src/SFML/Audio/SoundSource.cpp
@@ -0,0 +1,209 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundSource.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+SoundSource::SoundSource()
+{
+ alCheck(alGenSources(1, &m_source));
+ alCheck(alSourcei(m_source, AL_BUFFER, 0));
+}
+
+
+////////////////////////////////////////////////////////////
+SoundSource::SoundSource(const SoundSource& copy)
+{
+ alCheck(alGenSources(1, &m_source));
+ alCheck(alSourcei(m_source, AL_BUFFER, 0));
+
+ setPitch(copy.getPitch());
+ setVolume(copy.getVolume());
+ setPosition(copy.getPosition());
+ setRelativeToListener(copy.isRelativeToListener());
+ setMinDistance(copy.getMinDistance());
+ setAttenuation(copy.getAttenuation());
+}
+
+
+////////////////////////////////////////////////////////////
+SoundSource::~SoundSource()
+{
+ alCheck(alSourcei(m_source, AL_BUFFER, 0));
+ alCheck(alDeleteSources(1, &m_source));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setPitch(float pitch)
+{
+ alCheck(alSourcef(m_source, AL_PITCH, pitch));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setVolume(float volume)
+{
+ alCheck(alSourcef(m_source, AL_GAIN, volume * 0.01f));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setPosition(float x, float y, float z)
+{
+ alCheck(alSource3f(m_source, AL_POSITION, x, y, z));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setPosition(const Vector3f& position)
+{
+ setPosition(position.x, position.y, position.z);
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setRelativeToListener(bool relative)
+{
+ alCheck(alSourcei(m_source, AL_SOURCE_RELATIVE, relative));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setMinDistance(float distance)
+{
+ alCheck(alSourcef(m_source, AL_REFERENCE_DISTANCE, distance));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundSource::setAttenuation(float attenuation)
+{
+ alCheck(alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation));
+}
+
+
+////////////////////////////////////////////////////////////
+float SoundSource::getPitch() const
+{
+ ALfloat pitch;
+ alCheck(alGetSourcef(m_source, AL_PITCH, &pitch));
+
+ return pitch;
+}
+
+
+////////////////////////////////////////////////////////////
+float SoundSource::getVolume() const
+{
+ ALfloat gain;
+ alCheck(alGetSourcef(m_source, AL_GAIN, &gain));
+
+ return gain * 100.f;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SoundSource::getPosition() const
+{
+ Vector3f position;
+ alCheck(alGetSource3f(m_source, AL_POSITION, &position.x, &position.y, &position.z));
+
+ return position;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundSource::isRelativeToListener() const
+{
+ ALint relative;
+ alCheck(alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative));
+
+ return relative != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+float SoundSource::getMinDistance() const
+{
+ ALfloat distance;
+ alCheck(alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance));
+
+ return distance;
+}
+
+
+////////////////////////////////////////////////////////////
+float SoundSource::getAttenuation() const
+{
+ ALfloat attenuation;
+ alCheck(alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation));
+
+ return attenuation;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundSource& SoundSource::operator =(const SoundSource& right)
+{
+ // Leave m_source untouched -- it's not necessary to destroy and
+ // recreate the OpenAL sound source, hence no copy-and-swap idiom
+
+ // Assign the sound attributes
+ setPitch(right.getPitch());
+ setVolume(right.getVolume());
+ setPosition(right.getPosition());
+ setRelativeToListener(right.isRelativeToListener());
+ setMinDistance(right.getMinDistance());
+ setAttenuation(right.getAttenuation());
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundSource::Status SoundSource::getStatus() const
+{
+ ALint status;
+ alCheck(alGetSourcei(m_source, AL_SOURCE_STATE, &status));
+
+ switch (status)
+ {
+ case AL_INITIAL:
+ case AL_STOPPED: return Stopped;
+ case AL_PAUSED: return Paused;
+ case AL_PLAYING: return Playing;
+ }
+
+ return Stopped;
+}
+
+} // namespace sf
diff --git a/src/SFML/Audio/SoundStream.cpp b/src/SFML/Audio/SoundStream.cpp
new file mode 100644
index 0000000..0e40548
--- /dev/null
+++ b/src/SFML/Audio/SoundStream.cpp
@@ -0,0 +1,495 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Audio/SoundStream.hpp>
+#include <SFML/Audio/AudioDevice.hpp>
+#include <SFML/Audio/ALCheck.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Lock.hpp>
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4355) // 'this' used in base member initializer list
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+SoundStream::SoundStream() :
+m_thread (&SoundStream::streamData, this),
+m_threadMutex (),
+m_threadStartState(Stopped),
+m_isStreaming (false),
+m_buffers (),
+m_channelCount (0),
+m_sampleRate (0),
+m_format (0),
+m_loop (false),
+m_samplesProcessed(0),
+m_bufferSeeks ()
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+SoundStream::~SoundStream()
+{
+ // Stop the sound if it was playing
+
+ // Request the thread to terminate
+ {
+ Lock lock(m_threadMutex);
+ m_isStreaming = false;
+ }
+
+ // Wait for the thread to terminate
+ m_thread.wait();
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate)
+{
+ m_channelCount = channelCount;
+ m_sampleRate = sampleRate;
+ m_samplesProcessed = 0;
+ m_isStreaming = false;
+
+ // Deduce the format from the number of channels
+ m_format = priv::AudioDevice::getFormatFromChannelCount(channelCount);
+
+ // Check if the format is valid
+ if (m_format == 0)
+ {
+ m_channelCount = 0;
+ m_sampleRate = 0;
+ err() << "Unsupported number of channels (" << m_channelCount << ")" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::play()
+{
+ // Check if the sound parameters have been set
+ if (m_format == 0)
+ {
+ err() << "Failed to play audio stream: sound parameters have not been initialized (call initialize() first)" << std::endl;
+ return;
+ }
+
+ bool isStreaming = false;
+ Status threadStartState = Stopped;
+
+ {
+ Lock lock(m_threadMutex);
+
+ isStreaming = m_isStreaming;
+ threadStartState = m_threadStartState;
+ }
+
+
+ if (isStreaming && (threadStartState == Paused))
+ {
+ // If the sound is paused, resume it
+ Lock lock(m_threadMutex);
+ m_threadStartState = Playing;
+ alCheck(alSourcePlay(m_source));
+ return;
+ }
+ else if (isStreaming && (threadStartState == Playing))
+ {
+ // If the sound is playing, stop it and continue as if it was stopped
+ stop();
+ }
+
+ // Start updating the stream in a separate thread to avoid blocking the application
+ m_isStreaming = true;
+ m_threadStartState = Playing;
+ m_thread.launch();
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::pause()
+{
+ // Handle pause() being called before the thread has started
+ {
+ Lock lock(m_threadMutex);
+
+ if (!m_isStreaming)
+ return;
+
+ m_threadStartState = Paused;
+ }
+
+ alCheck(alSourcePause(m_source));
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::stop()
+{
+ // Request the thread to terminate
+ {
+ Lock lock(m_threadMutex);
+ m_isStreaming = false;
+ }
+
+ // Wait for the thread to terminate
+ m_thread.wait();
+
+ // Move to the beginning
+ onSeek(Time::Zero);
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundStream::getChannelCount() const
+{
+ return m_channelCount;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int SoundStream::getSampleRate() const
+{
+ return m_sampleRate;
+}
+
+
+////////////////////////////////////////////////////////////
+SoundStream::Status SoundStream::getStatus() const
+{
+ Status status = SoundSource::getStatus();
+
+ // To compensate for the lag between play() and alSourceplay()
+ if (status == Stopped)
+ {
+ Lock lock(m_threadMutex);
+
+ if (m_isStreaming)
+ status = m_threadStartState;
+ }
+
+ return status;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::setPlayingOffset(Time timeOffset)
+{
+ // Get old playing status
+ Status oldStatus = getStatus();
+
+ // Stop the stream
+ stop();
+
+ // Let the derived class update the current position
+ onSeek(timeOffset);
+
+ // Restart streaming
+ m_samplesProcessed = static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount);
+
+ if (oldStatus == Stopped)
+ return;
+
+ m_isStreaming = true;
+ m_threadStartState = oldStatus;
+ m_thread.launch();
+}
+
+
+////////////////////////////////////////////////////////////
+Time SoundStream::getPlayingOffset() const
+{
+ if (m_sampleRate && m_channelCount)
+ {
+ ALfloat secs = 0.f;
+ alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs));
+
+ return seconds(secs + static_cast<float>(m_samplesProcessed) / m_sampleRate / m_channelCount);
+ }
+ else
+ {
+ return Time::Zero;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::setLoop(bool loop)
+{
+ m_loop = loop;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundStream::getLoop() const
+{
+ return m_loop;
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 SoundStream::onLoop()
+{
+ onSeek(Time::Zero);
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::streamData()
+{
+ bool requestStop = false;
+
+ {
+ Lock lock(m_threadMutex);
+
+ // Check if the thread was launched Stopped
+ if (m_threadStartState == Stopped)
+ {
+ m_isStreaming = false;
+ return;
+ }
+ }
+
+ // Create the buffers
+ alCheck(alGenBuffers(BufferCount, m_buffers));
+ for (int i = 0; i < BufferCount; ++i)
+ m_bufferSeeks[i] = NoLoop;
+
+ // Fill the queue
+ requestStop = fillQueue();
+
+ // Play the sound
+ alCheck(alSourcePlay(m_source));
+
+ {
+ Lock lock(m_threadMutex);
+
+ // Check if the thread was launched Paused
+ if (m_threadStartState == Paused)
+ alCheck(alSourcePause(m_source));
+ }
+
+ for (;;)
+ {
+ {
+ Lock lock(m_threadMutex);
+ if (!m_isStreaming)
+ break;
+ }
+
+ // The stream has been interrupted!
+ if (SoundSource::getStatus() == Stopped)
+ {
+ if (!requestStop)
+ {
+ // Just continue
+ alCheck(alSourcePlay(m_source));
+ }
+ else
+ {
+ // End streaming
+ Lock lock(m_threadMutex);
+ m_isStreaming = false;
+ }
+ }
+
+ // Get the number of buffers that have been processed (i.e. ready for reuse)
+ ALint nbProcessed = 0;
+ alCheck(alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed));
+
+ while (nbProcessed--)
+ {
+ // Pop the first unused buffer from the queue
+ ALuint buffer;
+ alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
+
+ // Find its number
+ unsigned int bufferNum = 0;
+ for (int i = 0; i < BufferCount; ++i)
+ if (m_buffers[i] == buffer)
+ {
+ bufferNum = i;
+ break;
+ }
+
+ // Retrieve its size and add it to the samples count
+ if (m_bufferSeeks[bufferNum] != NoLoop)
+ {
+ // This was the last buffer before EOF or Loop End: reset the sample count
+ m_samplesProcessed = m_bufferSeeks[bufferNum];
+ m_bufferSeeks[bufferNum] = NoLoop;
+ }
+ else
+ {
+ ALint size, bits;
+ alCheck(alGetBufferi(buffer, AL_SIZE, &size));
+ alCheck(alGetBufferi(buffer, AL_BITS, &bits));
+
+ // Bits can be 0 if the format or parameters are corrupt, avoid division by zero
+ if (bits == 0)
+ {
+ err() << "Bits in sound stream are 0: make sure that the audio format is not corrupt "
+ << "and initialize() has been called correctly" << std::endl;
+
+ // Abort streaming (exit main loop)
+ Lock lock(m_threadMutex);
+ m_isStreaming = false;
+ requestStop = true;
+ break;
+ }
+ else
+ {
+ m_samplesProcessed += size / (bits / 8);
+ }
+ }
+
+ // Fill it and push it back into the playing queue
+ if (!requestStop)
+ {
+ if (fillAndPushBuffer(bufferNum))
+ requestStop = true;
+ }
+ }
+
+ // Leave some time for the other threads if the stream is still playing
+ if (SoundSource::getStatus() != Stopped)
+ sleep(milliseconds(10));
+ }
+
+ // Stop the playback
+ alCheck(alSourceStop(m_source));
+
+ // Dequeue any buffer left in the queue
+ clearQueue();
+
+ // Reset the playing position
+ m_samplesProcessed = 0;
+
+ // Delete the buffers
+ alCheck(alSourcei(m_source, AL_BUFFER, 0));
+ alCheck(alDeleteBuffers(BufferCount, m_buffers));
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundStream::fillAndPushBuffer(unsigned int bufferNum, bool immediateLoop)
+{
+ bool requestStop = false;
+
+ // Acquire audio data, also address EOF and error cases if they occur
+ Chunk data = {NULL, 0};
+ for (Uint32 retryCount = 0; !onGetData(data) && (retryCount < BufferRetries); ++retryCount)
+ {
+ // Check if the stream must loop or stop
+ if (!m_loop)
+ {
+ // Not looping: Mark this buffer as ending with 0 and request stop
+ if (data.samples != NULL && data.sampleCount != 0)
+ m_bufferSeeks[bufferNum] = 0;
+ requestStop = true;
+ break;
+ }
+
+ // Return to the beginning or loop-start of the stream source using onLoop(), and store the result in the buffer seek array
+ // This marks the buffer as the "last" one (so that we know where to reset the playing position)
+ m_bufferSeeks[bufferNum] = onLoop();
+
+ // If we got data, break and process it, else try to fill the buffer once again
+ if (data.samples != NULL && data.sampleCount != 0)
+ break;
+
+ // If immediateLoop is specified, we have to immediately adjust the sample count
+ if (immediateLoop && (m_bufferSeeks[bufferNum] != NoLoop))
+ {
+ // We just tried to begin preloading at EOF or Loop End: reset the sample count
+ m_samplesProcessed = m_bufferSeeks[bufferNum];
+ m_bufferSeeks[bufferNum] = NoLoop;
+ }
+
+ // We're a looping sound that got no data, so we retry onGetData()
+ }
+
+ // Fill the buffer if some data was returned
+ if (data.samples && data.sampleCount)
+ {
+ unsigned int buffer = m_buffers[bufferNum];
+
+ // Fill the buffer
+ ALsizei size = static_cast<ALsizei>(data.sampleCount) * sizeof(Int16);
+ alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate));
+
+ // Push it into the sound queue
+ alCheck(alSourceQueueBuffers(m_source, 1, &buffer));
+ }
+ else
+ {
+ // If we get here, we most likely ran out of retries
+ requestStop = true;
+ }
+
+ return requestStop;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SoundStream::fillQueue()
+{
+ // Fill and enqueue all the available buffers
+ bool requestStop = false;
+ for (int i = 0; (i < BufferCount) && !requestStop; ++i)
+ {
+ // Since no sound has been loaded yet, we can't schedule loop seeks preemptively,
+ // So if we start on EOF or Loop End, we let fillAndPushBuffer() adjust the sample count
+ if (fillAndPushBuffer(i, (i == 0)))
+ requestStop = true;
+ }
+
+ return requestStop;
+}
+
+
+////////////////////////////////////////////////////////////
+void SoundStream::clearQueue()
+{
+ // Get the number of buffers still in the queue
+ ALint nbQueued;
+ alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued));
+
+ // Dequeue them all
+ ALuint buffer;
+ for (ALint i = 0; i < nbQueued; ++i)
+ alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
+}
+
+} // namespace sf
diff --git a/src/SFML/CMakeLists.txt b/src/SFML/CMakeLists.txt
new file mode 100644
index 0000000..25a5bb1
--- /dev/null
+++ b/src/SFML/CMakeLists.txt
@@ -0,0 +1,76 @@
+
+# include the SFML specific macros
+include(${PROJECT_SOURCE_DIR}/cmake/Macros.cmake)
+
+# let CMake know about our additional libraries paths
+if (SFML_OS_WINDOWS)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers")
+ if(SFML_COMPILER_GCC)
+ if(ARCH_32BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x86")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/bin/x86")
+ elseif(ARCH_64BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x64")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/bin/x64")
+ endif()
+ elseif(SFML_COMPILER_MSVC)
+ if(SFML_MSVC_VERSION LESS 14)
+ if(ARCH_32BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-msvc/x86")
+ elseif(ARCH_64BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-msvc/x64")
+ endif()
+ else()
+ if(ARCH_32BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-msvc-universal/x86")
+ elseif(ARCH_64BITS)
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-msvc-universal/x64")
+ endif()
+ endif()
+ endif()
+elseif(SFML_OS_MACOSX)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/lib/")
+elseif(SFML_OS_IOS)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-ios/")
+elseif(SFML_OS_ANDROID)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-android/${CMAKE_ANDROID_ARCH_ABI}")
+endif()
+
+# define the path of our additional CMake modules
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/")
+
+# set the output directory for SFML libraries
+set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib")
+
+# add the modules subdirectories
+
+# sfml-system
+add_subdirectory(System)
+
+# sfml-main and sfml-activity
+if(SFML_OS_WINDOWS OR SFML_OS_ANDROID OR SFML_OS_IOS)
+ add_subdirectory(Main)
+endif()
+
+# sfml-window
+if(SFML_BUILD_WINDOW OR SFML_BUILD_GRAPHICS)
+ add_subdirectory(Window)
+endif()
+
+# sfml-network
+if(SFML_BUILD_NETWORK)
+ add_subdirectory(Network)
+endif()
+
+# sfml-graphics
+if(SFML_BUILD_GRAPHICS)
+ add_subdirectory(Graphics)
+endif()
+
+# sfml-audio
+if(SFML_BUILD_AUDIO)
+ add_subdirectory(Audio)
+endif()
diff --git a/src/SFML/Graphics/BlendMode.cpp b/src/SFML/Graphics/BlendMode.cpp
new file mode 100644
index 0000000..0d9cf95
--- /dev/null
+++ b/src/SFML/Graphics/BlendMode.cpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/BlendMode.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+// Commonly used blending modes
+////////////////////////////////////////////////////////////
+const BlendMode BlendAlpha(BlendMode::SrcAlpha, BlendMode::OneMinusSrcAlpha, BlendMode::Add,
+ BlendMode::One, BlendMode::OneMinusSrcAlpha, BlendMode::Add);
+const BlendMode BlendAdd(BlendMode::SrcAlpha, BlendMode::One, BlendMode::Add,
+ BlendMode::One, BlendMode::One, BlendMode::Add);
+const BlendMode BlendMultiply(BlendMode::DstColor, BlendMode::Zero);
+const BlendMode BlendNone(BlendMode::One, BlendMode::Zero);
+
+
+////////////////////////////////////////////////////////////
+BlendMode::BlendMode() :
+colorSrcFactor(BlendMode::SrcAlpha),
+colorDstFactor(BlendMode::OneMinusSrcAlpha),
+colorEquation (BlendMode::Add),
+alphaSrcFactor(BlendMode::One),
+alphaDstFactor(BlendMode::OneMinusSrcAlpha),
+alphaEquation (BlendMode::Add)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+BlendMode::BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation) :
+colorSrcFactor(sourceFactor),
+colorDstFactor(destinationFactor),
+colorEquation (blendEquation),
+alphaSrcFactor(sourceFactor),
+alphaDstFactor(destinationFactor),
+alphaEquation (blendEquation)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+BlendMode::BlendMode(Factor colorSourceFactor, Factor colorDestinationFactor,
+ Equation colorBlendEquation, Factor alphaSourceFactor,
+ Factor alphaDestinationFactor, Equation alphaBlendEquation) :
+colorSrcFactor(colorSourceFactor),
+colorDstFactor(colorDestinationFactor),
+colorEquation (colorBlendEquation),
+alphaSrcFactor(alphaSourceFactor),
+alphaDstFactor(alphaDestinationFactor),
+alphaEquation (alphaBlendEquation)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const BlendMode& left, const BlendMode& right)
+{
+ return (left.colorSrcFactor == right.colorSrcFactor) &&
+ (left.colorDstFactor == right.colorDstFactor) &&
+ (left.colorEquation == right.colorEquation) &&
+ (left.alphaSrcFactor == right.alphaSrcFactor) &&
+ (left.alphaDstFactor == right.alphaDstFactor) &&
+ (left.alphaEquation == right.alphaEquation);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const BlendMode& left, const BlendMode& right)
+{
+ return !(left == right);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/CMakeLists.txt b/src/SFML/Graphics/CMakeLists.txt
new file mode 100644
index 0000000..883c758
--- /dev/null
+++ b/src/SFML/Graphics/CMakeLists.txt
@@ -0,0 +1,147 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Graphics)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Graphics)
+
+# all source files
+set(SRC
+ ${SRCROOT}/BlendMode.cpp
+ ${INCROOT}/BlendMode.hpp
+ ${SRCROOT}/Color.cpp
+ ${INCROOT}/Color.hpp
+ ${INCROOT}/Export.hpp
+ ${SRCROOT}/Font.cpp
+ ${INCROOT}/Font.hpp
+ ${SRCROOT}/Glsl.cpp
+ ${INCROOT}/Glsl.hpp
+ ${INCROOT}/Glsl.inl
+ ${INCROOT}/Glyph.hpp
+ ${SRCROOT}/GLCheck.cpp
+ ${SRCROOT}/GLCheck.hpp
+ ${SRCROOT}/GLExtensions.hpp
+ ${SRCROOT}/GLExtensions.cpp
+ ${SRCROOT}/Image.cpp
+ ${INCROOT}/Image.hpp
+ ${SRCROOT}/ImageLoader.cpp
+ ${SRCROOT}/ImageLoader.hpp
+ ${INCROOT}/PrimitiveType.hpp
+ ${INCROOT}/Rect.hpp
+ ${INCROOT}/Rect.inl
+ ${SRCROOT}/RenderStates.cpp
+ ${INCROOT}/RenderStates.hpp
+ ${SRCROOT}/RenderTexture.cpp
+ ${INCROOT}/RenderTexture.hpp
+ ${SRCROOT}/RenderTarget.cpp
+ ${INCROOT}/RenderTarget.hpp
+ ${SRCROOT}/RenderWindow.cpp
+ ${INCROOT}/RenderWindow.hpp
+ ${SRCROOT}/Shader.cpp
+ ${INCROOT}/Shader.hpp
+ ${SRCROOT}/Texture.cpp
+ ${INCROOT}/Texture.hpp
+ ${SRCROOT}/TextureSaver.cpp
+ ${SRCROOT}/TextureSaver.hpp
+ ${SRCROOT}/Transform.cpp
+ ${INCROOT}/Transform.hpp
+ ${SRCROOT}/Transformable.cpp
+ ${INCROOT}/Transformable.hpp
+ ${SRCROOT}/View.cpp
+ ${INCROOT}/View.hpp
+ ${SRCROOT}/Vertex.cpp
+ ${INCROOT}/Vertex.hpp
+)
+if(NOT SFML_OPENGL_ES)
+ list(APPEND SRC ${SRCROOT}/GLLoader.cpp)
+ list(APPEND SRC ${SRCROOT}/GLLoader.hpp)
+endif()
+source_group("" FILES ${SRC})
+
+# drawables sources
+set(DRAWABLES_SRC
+ ${INCROOT}/Drawable.hpp
+ ${SRCROOT}/Shape.cpp
+ ${INCROOT}/Shape.hpp
+ ${SRCROOT}/CircleShape.cpp
+ ${INCROOT}/CircleShape.hpp
+ ${SRCROOT}/RectangleShape.cpp
+ ${INCROOT}/RectangleShape.hpp
+ ${SRCROOT}/ConvexShape.cpp
+ ${INCROOT}/ConvexShape.hpp
+ ${SRCROOT}/Sprite.cpp
+ ${INCROOT}/Sprite.hpp
+ ${SRCROOT}/Text.cpp
+ ${INCROOT}/Text.hpp
+ ${SRCROOT}/VertexArray.cpp
+ ${INCROOT}/VertexArray.hpp
+ ${SRCROOT}/VertexBuffer.cpp
+ ${INCROOT}/VertexBuffer.hpp
+)
+source_group("drawables" FILES ${DRAWABLES_SRC})
+
+# render-texture sources
+set(RENDER_TEXTURE_SRC
+ ${SRCROOT}/RenderTextureImpl.cpp
+ ${SRCROOT}/RenderTextureImpl.hpp
+ ${SRCROOT}/RenderTextureImplFBO.cpp
+ ${SRCROOT}/RenderTextureImplFBO.hpp
+ ${SRCROOT}/RenderTextureImplDefault.cpp
+ ${SRCROOT}/RenderTextureImplDefault.hpp
+)
+source_group("render texture" FILES ${RENDER_TEXTURE_SRC})
+
+
+# define the sfml-graphics target
+sfml_add_library(sfml-graphics
+ SOURCES ${SRC} ${DRAWABLES_SRC} ${RENDER_TEXTURE_SRC} ${STB_SRC})
+
+# setup dependencies
+target_link_libraries(sfml-graphics PUBLIC sfml-window)
+
+# stb_image sources
+target_include_directories(sfml-graphics PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/stb_image")
+
+# let CMake know about our additional graphics libraries paths
+if(SFML_OS_WINDOWS)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/freetype2")
+elseif(SFML_OS_MACOSX)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/freetype2")
+ set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks")
+elseif(SFML_OS_IOS)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/freetype2")
+elseif(SFML_OS_ANDROID)
+ set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/freetype2")
+endif()
+
+# find external libraries
+if(SFML_OPENGL_ES)
+ if(SFML_OS_LINUX)
+ sfml_find_package(EGL INCLUDE "EGL_INCLUDE_DIR" LINK "EGL_LIBRARY")
+ sfml_find_package(GLES INCLUDE "GLES_INCLUDE_DIR" LINK "GLES_LIBRARY")
+ target_link_libraries(sfml-graphics PRIVATE EGL GLES)
+ elseif(SFML_OS_IOS)
+ target_link_libraries(sfml-graphics PRIVATE "-framework OpenGLES")
+ endif()
+else()
+ # Target OpenGL already defined for Window component so no sfml_find_package() here
+ target_link_libraries(sfml-graphics PRIVATE OpenGL)
+
+ if(SFML_OS_LINUX)
+ # Target X11 already defined for Window component so no sfml_find_package() here
+ target_link_libraries(sfml-graphics PRIVATE X11)
+ endif()
+endif()
+
+if(SFML_OS_ANDROID)
+ target_link_libraries(sfml-graphics PRIVATE z EGL GLESv1_CM)
+endif()
+
+sfml_find_package(Freetype INCLUDE "FREETYPE_INCLUDE_DIRS" LINK "FREETYPE_LIBRARY")
+target_link_libraries(sfml-graphics PRIVATE Freetype)
+
+# add preprocessor symbols
+target_compile_definitions(sfml-graphics PRIVATE "STBI_FAILURE_USERMSG")
+
+# ImageLoader.cpp must be compiled with the -fno-strict-aliasing
+# when gcc is used; otherwise saving PNGs may crash in stb_image_write
+if(SFML_COMPILER_GCC)
+ set_source_files_properties(${SRCROOT}/ImageLoader.cpp PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
+endif()
diff --git a/src/SFML/Graphics/CircleShape.cpp b/src/SFML/Graphics/CircleShape.cpp
new file mode 100644
index 0000000..0cfa3c7
--- /dev/null
+++ b/src/SFML/Graphics/CircleShape.cpp
@@ -0,0 +1,84 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/CircleShape.hpp>
+#include <cmath>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+CircleShape::CircleShape(float radius, std::size_t pointCount) :
+m_radius (radius),
+m_pointCount(pointCount)
+{
+ update();
+}
+
+
+////////////////////////////////////////////////////////////
+void CircleShape::setRadius(float radius)
+{
+ m_radius = radius;
+ update();
+}
+
+
+////////////////////////////////////////////////////////////
+float CircleShape::getRadius() const
+{
+ return m_radius;
+}
+
+
+////////////////////////////////////////////////////////////
+void CircleShape::setPointCount(std::size_t count)
+{
+ m_pointCount = count;
+ update();
+}
+
+////////////////////////////////////////////////////////////
+std::size_t CircleShape::getPointCount() const
+{
+ return m_pointCount;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f CircleShape::getPoint(std::size_t index) const
+{
+ static const float pi = 3.141592654f;
+
+ float angle = index * 2 * pi / m_pointCount - pi / 2;
+ float x = std::cos(angle) * m_radius;
+ float y = std::sin(angle) * m_radius;
+
+ return Vector2f(m_radius + x, m_radius + y);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Color.cpp b/src/SFML/Graphics/Color.cpp
new file mode 100644
index 0000000..03f99a4
--- /dev/null
+++ b/src/SFML/Graphics/Color.cpp
@@ -0,0 +1,155 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Color.hpp>
+#include <algorithm>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+// Static member data
+////////////////////////////////////////////////////////////
+const Color Color::Black(0, 0, 0);
+const Color Color::White(255, 255, 255);
+const Color Color::Red(255, 0, 0);
+const Color Color::Green(0, 255, 0);
+const Color Color::Blue(0, 0, 255);
+const Color Color::Yellow(255, 255, 0);
+const Color Color::Magenta(255, 0, 255);
+const Color Color::Cyan(0, 255, 255);
+const Color Color::Transparent(0, 0, 0, 0);
+
+
+////////////////////////////////////////////////////////////
+Color::Color() :
+r(0),
+g(0),
+b(0),
+a(255)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Color::Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha) :
+r(red),
+g(green),
+b(blue),
+a(alpha)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Color::Color(Uint32 color) :
+r((color & 0xff000000) >> 24),
+g((color & 0x00ff0000) >> 16),
+b((color & 0x0000ff00) >> 8 ),
+a((color & 0x000000ff) >> 0 )
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Uint32 Color::toInteger() const
+{
+ return (r << 24) | (g << 16) | (b << 8) | a;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const Color& left, const Color& right)
+{
+ return (left.r == right.r) &&
+ (left.g == right.g) &&
+ (left.b == right.b) &&
+ (left.a == right.a);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const Color& left, const Color& right)
+{
+ return !(left == right);
+}
+
+
+////////////////////////////////////////////////////////////
+Color operator +(const Color& left, const Color& right)
+{
+ return Color(Uint8(std::min(int(left.r) + right.r, 255)),
+ Uint8(std::min(int(left.g) + right.g, 255)),
+ Uint8(std::min(int(left.b) + right.b, 255)),
+ Uint8(std::min(int(left.a) + right.a, 255)));
+}
+
+
+////////////////////////////////////////////////////////////
+Color operator -(const Color& left, const Color& right)
+{
+ return Color(Uint8(std::max(int(left.r) - right.r, 0)),
+ Uint8(std::max(int(left.g) - right.g, 0)),
+ Uint8(std::max(int(left.b) - right.b, 0)),
+ Uint8(std::max(int(left.a) - right.a, 0)));
+}
+
+
+////////////////////////////////////////////////////////////
+Color operator *(const Color& left, const Color& right)
+{
+ return Color(Uint8(int(left.r) * right.r / 255),
+ Uint8(int(left.g) * right.g / 255),
+ Uint8(int(left.b) * right.b / 255),
+ Uint8(int(left.a) * right.a / 255));
+}
+
+
+////////////////////////////////////////////////////////////
+Color& operator +=(Color& left, const Color& right)
+{
+ return left = left + right;
+}
+
+
+////////////////////////////////////////////////////////////
+Color& operator -=(Color& left, const Color& right)
+{
+ return left = left - right;
+}
+
+
+////////////////////////////////////////////////////////////
+Color& operator *=(Color& left, const Color& right)
+{
+ return left = left * right;
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/ConvexShape.cpp b/src/SFML/Graphics/ConvexShape.cpp
new file mode 100644
index 0000000..56aa787
--- /dev/null
+++ b/src/SFML/Graphics/ConvexShape.cpp
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/ConvexShape.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+ConvexShape::ConvexShape(std::size_t pointCount)
+{
+ setPointCount(pointCount);
+}
+
+
+////////////////////////////////////////////////////////////
+void ConvexShape::setPointCount(std::size_t count)
+{
+ m_points.resize(count);
+ update();
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t ConvexShape::getPointCount() const
+{
+ return m_points.size();
+}
+
+
+////////////////////////////////////////////////////////////
+void ConvexShape::setPoint(std::size_t index, const Vector2f& point)
+{
+ m_points[index] = point;
+ update();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f ConvexShape::getPoint(std::size_t index) const
+{
+ return m_points[index];
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp
new file mode 100644
index 0000000..308070a
--- /dev/null
+++ b/src/SFML/Graphics/Font.cpp
@@ -0,0 +1,817 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Font.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#ifdef SFML_SYSTEM_ANDROID
+ #include <SFML/System/Android/ResourceStream.hpp>
+#endif
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Err.hpp>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_BITMAP_H
+#include FT_STROKER_H
+#include <cstdlib>
+#include <cstring>
+
+
+namespace
+{
+ // FreeType callbacks that operate on a sf::InputStream
+ unsigned long read(FT_Stream rec, unsigned long offset, unsigned char* buffer, unsigned long count)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(rec->descriptor.pointer);
+ if (static_cast<unsigned long>(stream->seek(offset)) == offset)
+ {
+ if (count > 0)
+ return static_cast<unsigned long>(stream->read(reinterpret_cast<char*>(buffer), count));
+ else
+ return 0;
+ }
+ else
+ return count > 0 ? 0 : 1; // error code is 0 if we're reading, or nonzero if we're seeking
+ }
+ void close(FT_Stream)
+ {
+ }
+
+ // Helper to intepret memory as a specific type
+ template <typename T, typename U>
+ inline T reinterpret(const U& input)
+ {
+ T output;
+ std::memcpy(&output, &input, sizeof(U));
+ return output;
+ }
+
+ // Combine outline thickness, boldness and font glyph index into a single 64-bit key
+ sf::Uint64 combine(float outlineThickness, bool bold, sf::Uint32 index)
+ {
+ return (static_cast<sf::Uint64>(reinterpret<sf::Uint32>(outlineThickness)) << 32) | (static_cast<sf::Uint64>(bold) << 31) | index;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Font::Font() :
+m_library (NULL),
+m_face (NULL),
+m_streamRec(NULL),
+m_stroker (NULL),
+m_refCount (NULL),
+m_info ()
+{
+ #ifdef SFML_SYSTEM_ANDROID
+ m_stream = NULL;
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+Font::Font(const Font& copy) :
+m_library (copy.m_library),
+m_face (copy.m_face),
+m_streamRec (copy.m_streamRec),
+m_stroker (copy.m_stroker),
+m_refCount (copy.m_refCount),
+m_info (copy.m_info),
+m_pages (copy.m_pages),
+m_pixelBuffer(copy.m_pixelBuffer)
+{
+ #ifdef SFML_SYSTEM_ANDROID
+ m_stream = NULL;
+ #endif
+
+ // Note: as FreeType doesn't provide functions for copying/cloning,
+ // we must share all the FreeType pointers
+
+ if (m_refCount)
+ (*m_refCount)++;
+}
+
+
+////////////////////////////////////////////////////////////
+Font::~Font()
+{
+ cleanup();
+
+ #ifdef SFML_SYSTEM_ANDROID
+
+ if (m_stream)
+ delete (priv::ResourceStream*)m_stream;
+
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+bool Font::loadFromFile(const std::string& filename)
+{
+ #ifndef SFML_SYSTEM_ANDROID
+
+ // Cleanup the previous resources
+ cleanup();
+ m_refCount = new int(1);
+
+ // Initialize FreeType
+ // Note: we initialize FreeType for every font instance in order to avoid having a single
+ // global manager that would create a lot of issues regarding creation and destruction order.
+ FT_Library library;
+ if (FT_Init_FreeType(&library) != 0)
+ {
+ err() << "Failed to load font \"" << filename << "\" (failed to initialize FreeType)" << std::endl;
+ return false;
+ }
+ m_library = library;
+
+ // Load the new font face from the specified file
+ FT_Face face;
+ if (FT_New_Face(static_cast<FT_Library>(m_library), filename.c_str(), 0, &face) != 0)
+ {
+ err() << "Failed to load font \"" << filename << "\" (failed to create the font face)" << std::endl;
+ return false;
+ }
+
+ // Load the stroker that will be used to outline the font
+ FT_Stroker stroker;
+ if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
+ {
+ err() << "Failed to load font \"" << filename << "\" (failed to create the stroker)" << std::endl;
+ FT_Done_Face(face);
+ return false;
+ }
+
+ // Select the unicode character map
+ if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
+ {
+ err() << "Failed to load font \"" << filename << "\" (failed to set the Unicode character set)" << std::endl;
+ FT_Stroker_Done(stroker);
+ FT_Done_Face(face);
+ return false;
+ }
+
+ // Store the loaded font in our ugly void* :)
+ m_stroker = stroker;
+ m_face = face;
+
+ // Store the font information
+ m_info.family = face->family_name ? face->family_name : std::string();
+
+ return true;
+
+ #else
+
+ if (m_stream)
+ delete (priv::ResourceStream*)m_stream;
+
+ m_stream = new priv::ResourceStream(filename);
+ return loadFromStream(*(priv::ResourceStream*)m_stream);
+
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
+{
+ // Cleanup the previous resources
+ cleanup();
+ m_refCount = new int(1);
+
+ // Initialize FreeType
+ // Note: we initialize FreeType for every font instance in order to avoid having a single
+ // global manager that would create a lot of issues regarding creation and destruction order.
+ FT_Library library;
+ if (FT_Init_FreeType(&library) != 0)
+ {
+ err() << "Failed to load font from memory (failed to initialize FreeType)" << std::endl;
+ return false;
+ }
+ m_library = library;
+
+ // Load the new font face from the specified file
+ FT_Face face;
+ if (FT_New_Memory_Face(static_cast<FT_Library>(m_library), reinterpret_cast<const FT_Byte*>(data), static_cast<FT_Long>(sizeInBytes), 0, &face) != 0)
+ {
+ err() << "Failed to load font from memory (failed to create the font face)" << std::endl;
+ return false;
+ }
+
+ // Load the stroker that will be used to outline the font
+ FT_Stroker stroker;
+ if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
+ {
+ err() << "Failed to load font from memory (failed to create the stroker)" << std::endl;
+ FT_Done_Face(face);
+ return false;
+ }
+
+ // Select the Unicode character map
+ if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
+ {
+ err() << "Failed to load font from memory (failed to set the Unicode character set)" << std::endl;
+ FT_Stroker_Done(stroker);
+ FT_Done_Face(face);
+ return false;
+ }
+
+ // Store the loaded font in our ugly void* :)
+ m_stroker = stroker;
+ m_face = face;
+
+ // Store the font information
+ m_info.family = face->family_name ? face->family_name : std::string();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Font::loadFromStream(InputStream& stream)
+{
+ // Cleanup the previous resources
+ cleanup();
+ m_refCount = new int(1);
+
+ // Initialize FreeType
+ // Note: we initialize FreeType for every font instance in order to avoid having a single
+ // global manager that would create a lot of issues regarding creation and destruction order.
+ FT_Library library;
+ if (FT_Init_FreeType(&library) != 0)
+ {
+ err() << "Failed to load font from stream (failed to initialize FreeType)" << std::endl;
+ return false;
+ }
+ m_library = library;
+
+ // Make sure that the stream's reading position is at the beginning
+ stream.seek(0);
+
+ // Prepare a wrapper for our stream, that we'll pass to FreeType callbacks
+ FT_StreamRec* rec = new FT_StreamRec;
+ std::memset(rec, 0, sizeof(*rec));
+ rec->base = NULL;
+ rec->size = static_cast<unsigned long>(stream.getSize());
+ rec->pos = 0;
+ rec->descriptor.pointer = &stream;
+ rec->read = &read;
+ rec->close = &close;
+
+ // Setup the FreeType callbacks that will read our stream
+ FT_Open_Args args;
+ args.flags = FT_OPEN_STREAM;
+ args.stream = rec;
+ args.driver = 0;
+
+ // Load the new font face from the specified stream
+ FT_Face face;
+ if (FT_Open_Face(static_cast<FT_Library>(m_library), &args, 0, &face) != 0)
+ {
+ err() << "Failed to load font from stream (failed to create the font face)" << std::endl;
+ delete rec;
+ return false;
+ }
+
+ // Load the stroker that will be used to outline the font
+ FT_Stroker stroker;
+ if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
+ {
+ err() << "Failed to load font from stream (failed to create the stroker)" << std::endl;
+ FT_Done_Face(face);
+ delete rec;
+ return false;
+ }
+
+ // Select the Unicode character map
+ if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
+ {
+ err() << "Failed to load font from stream (failed to set the Unicode character set)" << std::endl;
+ FT_Done_Face(face);
+ FT_Stroker_Done(stroker);
+ delete rec;
+ return false;
+ }
+
+ // Store the loaded font in our ugly void* :)
+ m_stroker = stroker;
+ m_face = face;
+ m_streamRec = rec;
+
+ // Store the font information
+ m_info.family = face->family_name ? face->family_name : std::string();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+const Font::Info& Font::getInfo() const
+{
+ return m_info;
+}
+
+
+////////////////////////////////////////////////////////////
+const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
+{
+ // Get the page corresponding to the character size
+ GlyphTable& glyphs = m_pages[characterSize].glyphs;
+
+ // Build the key by combining the glyph index (based on code point), bold flag, and outline thickness
+ Uint64 key = combine(outlineThickness, bold, FT_Get_Char_Index(static_cast<FT_Face>(m_face), codePoint));
+
+ // Search the glyph into the cache
+ GlyphTable::const_iterator it = glyphs.find(key);
+ if (it != glyphs.end())
+ {
+ // Found: just return it
+ return it->second;
+ }
+ else
+ {
+ // Not found: we have to load it
+ Glyph glyph = loadGlyph(codePoint, characterSize, bold, outlineThickness);
+ return glyphs.insert(std::make_pair(key, glyph)).first->second;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+float Font::getKerning(Uint32 first, Uint32 second, unsigned int characterSize) const
+{
+ // Special case where first or second is 0 (null character)
+ if (first == 0 || second == 0)
+ return 0.f;
+
+ FT_Face face = static_cast<FT_Face>(m_face);
+
+ if (face && FT_HAS_KERNING(face) && setCurrentSize(characterSize))
+ {
+ // Convert the characters to indices
+ FT_UInt index1 = FT_Get_Char_Index(face, first);
+ FT_UInt index2 = FT_Get_Char_Index(face, second);
+
+ // Get the kerning vector
+ FT_Vector kerning;
+ FT_Get_Kerning(face, index1, index2, FT_KERNING_DEFAULT, &kerning);
+
+ // X advance is already in pixels for bitmap fonts
+ if (!FT_IS_SCALABLE(face))
+ return static_cast<float>(kerning.x);
+
+ // Return the X advance
+ return static_cast<float>(kerning.x) / static_cast<float>(1 << 6);
+ }
+ else
+ {
+ // Invalid font, or no kerning
+ return 0.f;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+float Font::getLineSpacing(unsigned int characterSize) const
+{
+ FT_Face face = static_cast<FT_Face>(m_face);
+
+ if (face && setCurrentSize(characterSize))
+ {
+ return static_cast<float>(face->size->metrics.height) / static_cast<float>(1 << 6);
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+float Font::getUnderlinePosition(unsigned int characterSize) const
+{
+ FT_Face face = static_cast<FT_Face>(m_face);
+
+ if (face && setCurrentSize(characterSize))
+ {
+ // Return a fixed position if font is a bitmap font
+ if (!FT_IS_SCALABLE(face))
+ return characterSize / 10.f;
+
+ return -static_cast<float>(FT_MulFix(face->underline_position, face->size->metrics.y_scale)) / static_cast<float>(1 << 6);
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+float Font::getUnderlineThickness(unsigned int characterSize) const
+{
+ FT_Face face = static_cast<FT_Face>(m_face);
+
+ if (face && setCurrentSize(characterSize))
+ {
+ // Return a fixed thickness if font is a bitmap font
+ if (!FT_IS_SCALABLE(face))
+ return characterSize / 14.f;
+
+ return static_cast<float>(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)) / static_cast<float>(1 << 6);
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const Texture& Font::getTexture(unsigned int characterSize) const
+{
+ return m_pages[characterSize].texture;
+}
+
+
+////////////////////////////////////////////////////////////
+Font& Font::operator =(const Font& right)
+{
+ Font temp(right);
+
+ std::swap(m_library, temp.m_library);
+ std::swap(m_face, temp.m_face);
+ std::swap(m_streamRec, temp.m_streamRec);
+ std::swap(m_stroker, temp.m_stroker);
+ std::swap(m_refCount, temp.m_refCount);
+ std::swap(m_info, temp.m_info);
+ std::swap(m_pages, temp.m_pages);
+ std::swap(m_pixelBuffer, temp.m_pixelBuffer);
+
+ #ifdef SFML_SYSTEM_ANDROID
+ std::swap(m_stream, temp.m_stream);
+ #endif
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+void Font::cleanup()
+{
+ // Check if we must destroy the FreeType pointers
+ if (m_refCount)
+ {
+ // Decrease the reference counter
+ (*m_refCount)--;
+
+ // Free the resources only if we are the last owner
+ if (*m_refCount == 0)
+ {
+ // Delete the reference counter
+ delete m_refCount;
+
+ // Destroy the stroker
+ if (m_stroker)
+ FT_Stroker_Done(static_cast<FT_Stroker>(m_stroker));
+
+ // Destroy the font face
+ if (m_face)
+ FT_Done_Face(static_cast<FT_Face>(m_face));
+
+ // Destroy the stream rec instance, if any (must be done after FT_Done_Face!)
+ if (m_streamRec)
+ delete static_cast<FT_StreamRec*>(m_streamRec);
+
+ // Close the library
+ if (m_library)
+ FT_Done_FreeType(static_cast<FT_Library>(m_library));
+ }
+ }
+
+ // Reset members
+ m_library = NULL;
+ m_face = NULL;
+ m_stroker = NULL;
+ m_streamRec = NULL;
+ m_refCount = NULL;
+ m_pages.clear();
+ std::vector<Uint8>().swap(m_pixelBuffer);
+}
+
+
+////////////////////////////////////////////////////////////
+Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
+{
+ // The glyph to return
+ Glyph glyph;
+
+ // First, transform our ugly void* to a FT_Face
+ FT_Face face = static_cast<FT_Face>(m_face);
+ if (!face)
+ return glyph;
+
+ // Set the character size
+ if (!setCurrentSize(characterSize))
+ return glyph;
+
+ // Load the glyph corresponding to the code point
+ FT_Int32 flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT;
+ if (outlineThickness != 0)
+ flags |= FT_LOAD_NO_BITMAP;
+ if (FT_Load_Char(face, codePoint, flags) != 0)
+ return glyph;
+
+ // Retrieve the glyph
+ FT_Glyph glyphDesc;
+ if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
+ return glyph;
+
+ // Apply bold and outline (there is no fallback for outline) if necessary -- first technique using outline (highest quality)
+ FT_Pos weight = 1 << 6;
+ bool outline = (glyphDesc->format == FT_GLYPH_FORMAT_OUTLINE);
+ if (outline)
+ {
+ if (bold)
+ {
+ FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
+ FT_Outline_Embolden(&outlineGlyph->outline, weight);
+ }
+
+ if (outlineThickness != 0)
+ {
+ FT_Stroker stroker = static_cast<FT_Stroker>(m_stroker);
+
+ FT_Stroker_Set(stroker, static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+ FT_Glyph_Stroke(&glyphDesc, stroker, true);
+ }
+ }
+
+ // Convert the glyph to a bitmap (i.e. rasterize it)
+ FT_Glyph_To_Bitmap(&glyphDesc, FT_RENDER_MODE_NORMAL, 0, 1);
+ FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>(glyphDesc)->bitmap;
+
+ // Apply bold if necessary -- fallback technique using bitmap (lower quality)
+ if (!outline)
+ {
+ if (bold)
+ FT_Bitmap_Embolden(static_cast<FT_Library>(m_library), &bitmap, weight, weight);
+
+ if (outlineThickness != 0)
+ err() << "Failed to outline glyph (no fallback available)" << std::endl;
+ }
+
+ // Compute the glyph's advance offset
+ glyph.advance = static_cast<float>(face->glyph->metrics.horiAdvance) / static_cast<float>(1 << 6);
+ if (bold)
+ glyph.advance += static_cast<float>(weight) / static_cast<float>(1 << 6);
+
+ int width = bitmap.width;
+ int height = bitmap.rows;
+
+ if ((width > 0) && (height > 0))
+ {
+ // Leave a small padding around characters, so that filtering doesn't
+ // pollute them with pixels from neighbors
+ const unsigned int padding = 1;
+
+ width += 2 * padding;
+ height += 2 * padding;
+
+ // Get the glyphs page corresponding to the character size
+ Page& page = m_pages[characterSize];
+
+ // Find a good position for the new glyph into the texture
+ glyph.textureRect = findGlyphRect(page, width, height);
+
+ // Make sure the texture data is positioned in the center
+ // of the allocated texture rectangle
+ glyph.textureRect.left += padding;
+ glyph.textureRect.top += padding;
+ glyph.textureRect.width -= 2 * padding;
+ glyph.textureRect.height -= 2 * padding;
+
+ // Compute the glyph's bounding box
+ glyph.bounds.left = static_cast<float>(face->glyph->metrics.horiBearingX) / static_cast<float>(1 << 6);
+ glyph.bounds.top = -static_cast<float>(face->glyph->metrics.horiBearingY) / static_cast<float>(1 << 6);
+ glyph.bounds.width = static_cast<float>(face->glyph->metrics.width) / static_cast<float>(1 << 6) + outlineThickness * 2;
+ glyph.bounds.height = static_cast<float>(face->glyph->metrics.height) / static_cast<float>(1 << 6) + outlineThickness * 2;
+
+ // Resize the pixel buffer to the new size and fill it with transparent white pixels
+ m_pixelBuffer.resize(width * height * 4);
+
+ Uint8* current = &m_pixelBuffer[0];
+ Uint8* end = current + width * height * 4;
+
+ while (current != end)
+ {
+ (*current++) = 255;
+ (*current++) = 255;
+ (*current++) = 255;
+ (*current++) = 0;
+ }
+
+ // Extract the glyph's pixels from the bitmap
+ const Uint8* pixels = bitmap.buffer;
+ if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
+ {
+ // Pixels are 1 bit monochrome values
+ for (unsigned int y = padding; y < height - padding; ++y)
+ {
+ for (unsigned int x = padding; x < width - padding; ++x)
+ {
+ // The color channels remain white, just fill the alpha channel
+ std::size_t index = x + y * width;
+ m_pixelBuffer[index * 4 + 3] = ((pixels[(x - padding) / 8]) & (1 << (7 - ((x - padding) % 8)))) ? 255 : 0;
+ }
+ pixels += bitmap.pitch;
+ }
+ }
+ else
+ {
+ // Pixels are 8 bits gray levels
+ for (unsigned int y = padding; y < height - padding; ++y)
+ {
+ for (unsigned int x = padding; x < width - padding; ++x)
+ {
+ // The color channels remain white, just fill the alpha channel
+ std::size_t index = x + y * width;
+ m_pixelBuffer[index * 4 + 3] = pixels[x - padding];
+ }
+ pixels += bitmap.pitch;
+ }
+ }
+
+ // Write the pixels to the texture
+ unsigned int x = glyph.textureRect.left - padding;
+ unsigned int y = glyph.textureRect.top - padding;
+ unsigned int w = glyph.textureRect.width + 2 * padding;
+ unsigned int h = glyph.textureRect.height + 2 * padding;
+ page.texture.update(&m_pixelBuffer[0], w, h, x, y);
+ }
+
+ // Delete the FT glyph
+ FT_Done_Glyph(glyphDesc);
+
+ // Done :)
+ return glyph;
+}
+
+
+////////////////////////////////////////////////////////////
+IntRect Font::findGlyphRect(Page& page, unsigned int width, unsigned int height) const
+{
+ // Find the line that fits well the glyph
+ Row* row = NULL;
+ float bestRatio = 0;
+ for (std::vector<Row>::iterator it = page.rows.begin(); it != page.rows.end() && !row; ++it)
+ {
+ float ratio = static_cast<float>(height) / it->height;
+
+ // Ignore rows that are either too small or too high
+ if ((ratio < 0.7f) || (ratio > 1.f))
+ continue;
+
+ // Check if there's enough horizontal space left in the row
+ if (width > page.texture.getSize().x - it->width)
+ continue;
+
+ // Make sure that this new row is the best found so far
+ if (ratio < bestRatio)
+ continue;
+
+ // The current row passed all the tests: we can select it
+ row = &*it;
+ bestRatio = ratio;
+ }
+
+ // If we didn't find a matching row, create a new one (10% taller than the glyph)
+ if (!row)
+ {
+ int rowHeight = height + height / 10;
+ while ((page.nextRow + rowHeight >= page.texture.getSize().y) || (width >= page.texture.getSize().x))
+ {
+ // Not enough space: resize the texture if possible
+ unsigned int textureWidth = page.texture.getSize().x;
+ unsigned int textureHeight = page.texture.getSize().y;
+ if ((textureWidth * 2 <= Texture::getMaximumSize()) && (textureHeight * 2 <= Texture::getMaximumSize()))
+ {
+ // Make the texture 2 times bigger
+ Texture newTexture;
+ newTexture.create(textureWidth * 2, textureHeight * 2);
+ newTexture.setSmooth(true);
+ newTexture.update(page.texture);
+ page.texture.swap(newTexture);
+ }
+ else
+ {
+ // Oops, we've reached the maximum texture size...
+ err() << "Failed to add a new character to the font: the maximum texture size has been reached" << std::endl;
+ return IntRect(0, 0, 2, 2);
+ }
+ }
+
+ // We can now create the new row
+ page.rows.push_back(Row(page.nextRow, rowHeight));
+ page.nextRow += rowHeight;
+ row = &page.rows.back();
+ }
+
+ // Find the glyph's rectangle on the selected row
+ IntRect rect(row->width, row->top, width, height);
+
+ // Update the row informations
+ row->width += width;
+
+ return rect;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Font::setCurrentSize(unsigned int characterSize) const
+{
+ // FT_Set_Pixel_Sizes is an expensive function, so we must call it
+ // only when necessary to avoid killing performances
+
+ FT_Face face = static_cast<FT_Face>(m_face);
+ FT_UShort currentSize = face->size->metrics.x_ppem;
+
+ if (currentSize != characterSize)
+ {
+ FT_Error result = FT_Set_Pixel_Sizes(face, 0, characterSize);
+
+ if (result == FT_Err_Invalid_Pixel_Size)
+ {
+ // In the case of bitmap fonts, resizing can
+ // fail if the requested size is not available
+ if (!FT_IS_SCALABLE(face))
+ {
+ err() << "Failed to set bitmap font size to " << characterSize << std::endl;
+ err() << "Available sizes are: ";
+ for (int i = 0; i < face->num_fixed_sizes; ++i)
+ {
+ const unsigned int size = (face->available_sizes[i].y_ppem + 32) >> 6;
+ err() << size << " ";
+ }
+ err() << std::endl;
+ }
+ else
+ {
+ err() << "Failed to set font size to " << characterSize << std::endl;
+ }
+ }
+
+ return result == FT_Err_Ok;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Font::Page::Page() :
+nextRow(3)
+{
+ // Make sure that the texture is initialized by default
+ sf::Image image;
+ image.create(128, 128, Color(255, 255, 255, 0));
+
+ // Reserve a 2x2 white square for texturing underlines
+ for (int x = 0; x < 2; ++x)
+ for (int y = 0; y < 2; ++y)
+ image.setPixel(x, y, Color(255, 255, 255, 255));
+
+ // Create the texture
+ texture.loadFromImage(image);
+ texture.setSmooth(true);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/GLCheck.cpp b/src/SFML/Graphics/GLCheck.cpp
new file mode 100644
index 0000000..580e838
--- /dev/null
+++ b/src/SFML/Graphics/GLCheck.cpp
@@ -0,0 +1,114 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/System/Err.hpp>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void glCheckError(const char* file, unsigned int line, const char* expression)
+{
+ // Get the last error
+ GLenum errorCode = glGetError();
+
+ if (errorCode != GL_NO_ERROR)
+ {
+ std::string fileString = file;
+ std::string error = "Unknown error";
+ std::string description = "No description";
+
+ // Decode the error code
+ switch (errorCode)
+ {
+ case GL_INVALID_ENUM:
+ {
+ error = "GL_INVALID_ENUM";
+ description = "An unacceptable value has been specified for an enumerated argument.";
+ break;
+ }
+
+ case GL_INVALID_VALUE:
+ {
+ error = "GL_INVALID_VALUE";
+ description = "A numeric argument is out of range.";
+ break;
+ }
+
+ case GL_INVALID_OPERATION:
+ {
+ error = "GL_INVALID_OPERATION";
+ description = "The specified operation is not allowed in the current state.";
+ break;
+ }
+
+ case GL_STACK_OVERFLOW:
+ {
+ error = "GL_STACK_OVERFLOW";
+ description = "This command would cause a stack overflow.";
+ break;
+ }
+
+ case GL_STACK_UNDERFLOW:
+ {
+ error = "GL_STACK_UNDERFLOW";
+ description = "This command would cause a stack underflow.";
+ break;
+ }
+
+ case GL_OUT_OF_MEMORY:
+ {
+ error = "GL_OUT_OF_MEMORY";
+ description = "There is not enough memory left to execute the command.";
+ break;
+ }
+
+ case GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION:
+ {
+ error = "GL_INVALID_FRAMEBUFFER_OPERATION";
+ description = "The object bound to FRAMEBUFFER_BINDING is not \"framebuffer complete\".";
+ break;
+ }
+ }
+
+ // Log the error
+ err() << "An internal OpenGL call failed in "
+ << fileString.substr(fileString.find_last_of("\\/") + 1) << "(" << line << ")."
+ << "\nExpression:\n " << expression
+ << "\nError description:\n " << error << "\n " << description << "\n"
+ << std::endl;
+ }
+}
+
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/GLCheck.hpp b/src/SFML/Graphics/GLCheck.hpp
new file mode 100644
index 0000000..86b96de
--- /dev/null
+++ b/src/SFML/Graphics/GLCheck.hpp
@@ -0,0 +1,70 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GLCHECK_HPP
+#define SFML_GLCHECK_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/Graphics/GLExtensions.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// Let's define a macro to quickly check every OpenGL API call
+////////////////////////////////////////////////////////////
+#ifdef SFML_DEBUG
+
+ // In debug mode, perform a test on every OpenGL call
+ // The do-while loop is needed so that glCheck can be used as a single statement in if/else branches
+ #define glCheck(expr) do { expr; sf::priv::glCheckError(__FILE__, __LINE__, #expr); } while (false)
+
+#else
+
+ // Else, we don't add any overhead
+ #define glCheck(expr) (expr)
+
+#endif
+
+////////////////////////////////////////////////////////////
+/// \brief Check the last OpenGL error
+///
+/// \param file Source file where the call is located
+/// \param line Line number of the source file where the call is located
+/// \param expression The evaluated expression as a string
+///
+////////////////////////////////////////////////////////////
+void glCheckError(const char* file, unsigned int line, const char* expression);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_GLCHECK_HPP
diff --git a/src/SFML/Graphics/GLExtensions.cpp b/src/SFML/Graphics/GLExtensions.cpp
new file mode 100644
index 0000000..fff712d
--- /dev/null
+++ b/src/SFML/Graphics/GLExtensions.cpp
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/GLExtensions.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/System/Err.hpp>
+
+#if !defined(GL_MAJOR_VERSION)
+ #define GL_MAJOR_VERSION 0x821B
+#endif
+
+#if !defined(GL_MINOR_VERSION)
+ #define GL_MINOR_VERSION 0x821C
+#endif
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void ensureExtensionsInit()
+{
+#if !defined(SFML_OPENGL_ES)
+ static bool initialized = false;
+ if (!initialized)
+ {
+ initialized = true;
+
+ sfogl_LoadFunctions();
+
+ // Retrieve the context version number
+ int majorVersion = 0;
+ int minorVersion = 0;
+
+ // Try the new way first
+ glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
+ glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
+
+ if (glGetError() == GL_INVALID_ENUM)
+ {
+ // Try the old way
+ const GLubyte* version = glGetString(GL_VERSION);
+ if (version)
+ {
+ // The beginning of the returned string is "major.minor" (this is standard)
+ majorVersion = version[0] - '0';
+ minorVersion = version[2] - '0';
+ }
+ else
+ {
+ // Can't get the version number, assume 1.1
+ majorVersion = 1;
+ minorVersion = 1;
+ }
+ }
+
+ if ((majorVersion < 1) || ((majorVersion == 1) && (minorVersion < 1)))
+ {
+ err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl;
+ err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
+ }
+ }
+#endif
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp
new file mode 100644
index 0000000..687cf37
--- /dev/null
+++ b/src/SFML/Graphics/GLExtensions.hpp
@@ -0,0 +1,333 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GLEXTENSIONS_HPP
+#define SFML_GLEXTENSIONS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#ifdef SFML_OPENGL_ES
+
+ #include <SFML/OpenGL.hpp>
+
+ // SFML requires at a bare minimum OpenGL ES 1.0 capability
+ // Some extensions only incorporated by 2.0 are also required
+ // OpenGL ES 1.0 is defined relative to OpenGL 1.3
+ // OpenGL ES 1.1 is defined relative to OpenGL 1.5
+ // OpenGL ES 2.0 is defined relative to OpenGL 2.0
+ // All functionality beyond that is optional
+ // and has to be checked for prior to use
+
+ // Core since 1.0
+ #define GLEXT_multitexture true
+ #define GLEXT_texture_edge_clamp true
+ #define GLEXT_EXT_texture_edge_clamp true
+ #define GLEXT_blend_minmax true
+ #define GLEXT_glClientActiveTexture glClientActiveTexture
+ #define GLEXT_glActiveTexture glActiveTexture
+ #define GLEXT_GL_TEXTURE0 GL_TEXTURE0
+ #define GLEXT_GL_CLAMP GL_CLAMP_TO_EDGE
+ #define GLEXT_GL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE
+
+ // Core since 1.1
+ // 1.1 does not support GL_STREAM_DRAW so we just define it to GL_DYNAMIC_DRAW
+ #define GLEXT_vertex_buffer_object true
+ #define GLEXT_GL_ARRAY_BUFFER GL_ARRAY_BUFFER
+ #define GLEXT_GL_DYNAMIC_DRAW GL_DYNAMIC_DRAW
+ #define GLEXT_GL_STATIC_DRAW GL_STATIC_DRAW
+ #define GLEXT_GL_STREAM_DRAW GL_DYNAMIC_DRAW
+ #define GLEXT_glBindBuffer glBindBuffer
+ #define GLEXT_glBufferData glBufferData
+ #define GLEXT_glBufferSubData glBufferSubData
+ #define GLEXT_glDeleteBuffers glDeleteBuffers
+ #define GLEXT_glGenBuffers glGenBuffers
+
+ // The following extensions are listed chronologically
+ // Extension macro first, followed by tokens then
+ // functions according to the corresponding specification
+
+ // The following extensions are required.
+
+ // Core since 2.0 - OES_blend_subtract
+ #define GLEXT_blend_subtract GL_OES_blend_subtract
+ #define GLEXT_glBlendEquation glBlendEquationOES
+ #define GLEXT_GL_FUNC_ADD GL_FUNC_ADD_OES
+ #define GLEXT_GL_FUNC_SUBTRACT GL_FUNC_SUBTRACT_OES
+ #define GLEXT_GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_OES
+
+ // The following extensions are optional.
+
+ // Core since 2.0 - OES_blend_func_separate
+ #ifdef SFML_SYSTEM_ANDROID
+ // Hack to make transparency working on some Android devices
+ #define GLEXT_blend_func_separate false
+ #else
+ #define GLEXT_blend_func_separate GL_OES_blend_func_separate
+ #endif
+ #define GLEXT_glBlendFuncSeparate glBlendFuncSeparateOES
+
+ // Core since 2.0 - OES_blend_equation_separate
+ #ifdef SFML_SYSTEM_ANDROID
+ // Hack to make transparency working on some Android devices
+ #define GLEXT_blend_equation_separate false
+ #else
+ #define GLEXT_blend_equation_separate GL_OES_blend_equation_separate
+ #endif
+ #define GLEXT_glBlendEquationSeparate glBlendEquationSeparateOES
+
+ // Core since 2.0 - OES_texture_npot
+ #define GLEXT_texture_non_power_of_two false
+
+ // Core since 2.0 - OES_framebuffer_object
+ #define GLEXT_framebuffer_object GL_OES_framebuffer_object
+ #define GLEXT_glBindRenderbuffer glBindRenderbufferOES
+ #define GLEXT_glDeleteRenderbuffers glDeleteRenderbuffersOES
+ #define GLEXT_glGenRenderbuffers glGenRenderbuffersOES
+ #define GLEXT_glRenderbufferStorage glRenderbufferStorageOES
+ #define GLEXT_glBindFramebuffer glBindFramebufferOES
+ #define GLEXT_glDeleteFramebuffers glDeleteFramebuffersOES
+ #define GLEXT_glGenFramebuffers glGenFramebuffersOES
+ #define GLEXT_glCheckFramebufferStatus glCheckFramebufferStatusOES
+ #define GLEXT_glFramebufferTexture2D glFramebufferTexture2DOES
+ #define GLEXT_glFramebufferRenderbuffer glFramebufferRenderbufferOES
+ #define GLEXT_glGenerateMipmap glGenerateMipmapOES
+ #define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
+ #define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_OES
+ #define GLEXT_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16_OES
+ #define GLEXT_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES
+ #define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
+ #define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
+ #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES
+ #define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_OES
+
+ // Core since 3.0
+ #define GLEXT_packed_depth_stencil false
+
+ // Core since 3.0
+ #define GLEXT_framebuffer_blit false
+
+ // Core since 3.0
+ #define GLEXT_framebuffer_multisample false
+
+ // Core since 3.0 - NV_copy_buffer
+ #define GLEXT_copy_buffer false
+
+ // Core since 3.0 - EXT_sRGB
+ #ifdef GL_EXT_sRGB
+ #define GLEXT_texture_sRGB GL_EXT_sRGB
+ #define GLEXT_GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT
+ #else
+ #define GLEXT_texture_sRGB false
+ #define GLEXT_GL_SRGB8_ALPHA8 0
+ #endif
+
+#else
+
+ #include <SFML/Graphics/GLLoader.hpp>
+
+ // SFML requires at a bare minimum OpenGL 1.1 capability
+ // All functionality beyond that is optional
+ // and has to be checked for prior to use
+
+ // Core since 1.1
+ #define GLEXT_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT
+ #define GLEXT_GL_CLAMP GL_CLAMP
+
+ // The following extensions are listed chronologically
+ // Extension macro first, followed by tokens then
+ // functions according to the corresponding specification
+
+ // The following extensions are optional.
+
+ // Core since 1.2 - SGIS_texture_edge_clamp
+ #define GLEXT_texture_edge_clamp sfogl_ext_SGIS_texture_edge_clamp
+ #define GLEXT_GL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE_SGIS
+
+ // Core since 1.2 - EXT_texture_edge_clamp
+ #define GLEXT_EXT_texture_edge_clamp sfogl_ext_EXT_texture_edge_clamp
+
+ // Core since 1.2 - EXT_blend_minmax
+ #define GLEXT_blend_minmax sfogl_ext_EXT_blend_minmax
+ #define GLEXT_glBlendEquation glBlendEquationEXT
+ #define GLEXT_GL_FUNC_ADD GL_FUNC_ADD_EXT
+
+ // Core since 1.2 - EXT_blend_subtract
+ #define GLEXT_blend_subtract sfogl_ext_EXT_blend_subtract
+ #define GLEXT_GL_FUNC_SUBTRACT GL_FUNC_SUBTRACT_EXT
+ #define GLEXT_GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_EXT
+
+ // Core since 1.3 - ARB_multitexture
+ #define GLEXT_multitexture sfogl_ext_ARB_multitexture
+ #define GLEXT_glClientActiveTexture glClientActiveTextureARB
+ #define GLEXT_glActiveTexture glActiveTextureARB
+ #define GLEXT_GL_TEXTURE0 GL_TEXTURE0_ARB
+
+ // Core since 1.4 - EXT_blend_func_separate
+ #define GLEXT_blend_func_separate sfogl_ext_EXT_blend_func_separate
+ #define GLEXT_glBlendFuncSeparate glBlendFuncSeparateEXT
+
+ // Core since 1.5 - ARB_vertex_buffer_object
+ #define GLEXT_vertex_buffer_object sfogl_ext_ARB_vertex_buffer_object
+ #define GLEXT_GL_ARRAY_BUFFER GL_ARRAY_BUFFER_ARB
+ #define GLEXT_GL_DYNAMIC_DRAW GL_DYNAMIC_DRAW_ARB
+ #define GLEXT_GL_READ_ONLY GL_READ_ONLY_ARB
+ #define GLEXT_GL_STATIC_DRAW GL_STATIC_DRAW_ARB
+ #define GLEXT_GL_STREAM_DRAW GL_STREAM_DRAW_ARB
+ #define GLEXT_GL_WRITE_ONLY GL_WRITE_ONLY_ARB
+ #define GLEXT_glBindBuffer glBindBufferARB
+ #define GLEXT_glBufferData glBufferDataARB
+ #define GLEXT_glBufferSubData glBufferSubDataARB
+ #define GLEXT_glDeleteBuffers glDeleteBuffersARB
+ #define GLEXT_glGenBuffers glGenBuffersARB
+ #define GLEXT_glMapBuffer glMapBufferARB
+ #define GLEXT_glUnmapBuffer glUnmapBufferARB
+
+ // Core since 2.0 - ARB_shading_language_100
+ #define GLEXT_shading_language_100 sfogl_ext_ARB_shading_language_100
+
+ // Core since 2.0 - ARB_shader_objects
+ #define GLEXT_shader_objects sfogl_ext_ARB_shader_objects
+ #define GLEXT_glDeleteObject glDeleteObjectARB
+ #define GLEXT_glGetHandle glGetHandleARB
+ #define GLEXT_glCreateShaderObject glCreateShaderObjectARB
+ #define GLEXT_glShaderSource glShaderSourceARB
+ #define GLEXT_glCompileShader glCompileShaderARB
+ #define GLEXT_glCreateProgramObject glCreateProgramObjectARB
+ #define GLEXT_glAttachObject glAttachObjectARB
+ #define GLEXT_glLinkProgram glLinkProgramARB
+ #define GLEXT_glUseProgramObject glUseProgramObjectARB
+ #define GLEXT_glUniform1f glUniform1fARB
+ #define GLEXT_glUniform2f glUniform2fARB
+ #define GLEXT_glUniform3f glUniform3fARB
+ #define GLEXT_glUniform4f glUniform4fARB
+ #define GLEXT_glUniform1i glUniform1iARB
+ #define GLEXT_glUniform2i glUniform2iARB
+ #define GLEXT_glUniform3i glUniform3iARB
+ #define GLEXT_glUniform4i glUniform4iARB
+ #define GLEXT_glUniform1fv glUniform1fvARB
+ #define GLEXT_glUniform2fv glUniform2fvARB
+ #define GLEXT_glUniform2iv glUniform2ivARB
+ #define GLEXT_glUniform3fv glUniform3fvARB
+ #define GLEXT_glUniform4fv glUniform4fvARB
+ #define GLEXT_glUniformMatrix3fv glUniformMatrix3fvARB
+ #define GLEXT_glUniformMatrix4fv glUniformMatrix4fvARB
+ #define GLEXT_glGetObjectParameteriv glGetObjectParameterivARB
+ #define GLEXT_glGetInfoLog glGetInfoLogARB
+ #define GLEXT_glGetUniformLocation glGetUniformLocationARB
+ #define GLEXT_GL_PROGRAM_OBJECT GL_PROGRAM_OBJECT_ARB
+ #define GLEXT_GL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS_ARB
+ #define GLEXT_GL_OBJECT_LINK_STATUS GL_OBJECT_LINK_STATUS_ARB
+ #define GLEXT_GLhandle GLhandleARB
+
+ // Core since 2.0 - ARB_vertex_shader
+ #define GLEXT_vertex_shader sfogl_ext_ARB_vertex_shader
+ #define GLEXT_GL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
+ #define GLEXT_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB
+
+ // Core since 2.0 - ARB_fragment_shader
+ #define GLEXT_fragment_shader sfogl_ext_ARB_fragment_shader
+ #define GLEXT_GL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB
+
+ // Core since 2.0 - ARB_texture_non_power_of_two
+ #define GLEXT_texture_non_power_of_two sfogl_ext_ARB_texture_non_power_of_two
+
+ // Core since 2.0 - EXT_blend_equation_separate
+ #define GLEXT_blend_equation_separate sfogl_ext_EXT_blend_equation_separate
+ #define GLEXT_glBlendEquationSeparate glBlendEquationSeparateEXT
+
+ // Core since 2.1 - EXT_texture_sRGB
+ #define GLEXT_texture_sRGB sfogl_ext_EXT_texture_sRGB
+ #define GLEXT_GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT
+
+ // Core since 3.0 - EXT_framebuffer_object
+ #define GLEXT_framebuffer_object sfogl_ext_EXT_framebuffer_object
+ #define GLEXT_glBindRenderbuffer glBindRenderbufferEXT
+ #define GLEXT_glDeleteRenderbuffers glDeleteRenderbuffersEXT
+ #define GLEXT_glGenRenderbuffers glGenRenderbuffersEXT
+ #define GLEXT_glRenderbufferStorage glRenderbufferStorageEXT
+ #define GLEXT_glBindFramebuffer glBindFramebufferEXT
+ #define GLEXT_glDeleteFramebuffers glDeleteFramebuffersEXT
+ #define GLEXT_glGenFramebuffers glGenFramebuffersEXT
+ #define GLEXT_glCheckFramebufferStatus glCheckFramebufferStatusEXT
+ #define GLEXT_glFramebufferTexture2D glFramebufferTexture2DEXT
+ #define GLEXT_glFramebufferRenderbuffer glFramebufferRenderbufferEXT
+ #define GLEXT_glGenerateMipmap glGenerateMipmapEXT
+ #define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
+ #define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
+ #define GLEXT_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
+ #define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
+ #define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
+ #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
+ #define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+ #define GLEXT_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
+
+ // Core since 3.0 - EXT_packed_depth_stencil
+ #define GLEXT_packed_depth_stencil sfogl_ext_EXT_packed_depth_stencil
+ #define GLEXT_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
+
+ // Core since 3.0 - EXT_framebuffer_blit
+ #define GLEXT_framebuffer_blit sfogl_ext_EXT_framebuffer_blit
+ #define GLEXT_glBlitFramebuffer glBlitFramebufferEXT
+ #define GLEXT_GL_READ_FRAMEBUFFER GL_READ_FRAMEBUFFER_EXT
+ #define GLEXT_GL_DRAW_FRAMEBUFFER GL_DRAW_FRAMEBUFFER_EXT
+ #define GLEXT_GL_DRAW_FRAMEBUFFER_BINDING GL_DRAW_FRAMEBUFFER_BINDING_EXT
+ #define GLEXT_GL_READ_FRAMEBUFFER_BINDING GL_READ_FRAMEBUFFER_BINDING_EXT
+
+ // Core since 3.0 - EXT_framebuffer_multisample
+ #define GLEXT_framebuffer_multisample sfogl_ext_EXT_framebuffer_multisample
+ #define GLEXT_glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
+ #define GLEXT_GL_MAX_SAMPLES GL_MAX_SAMPLES_EXT
+
+ // Core since 3.1 - ARB_copy_buffer
+ #define GLEXT_copy_buffer sfogl_ext_ARB_copy_buffer
+ #define GLEXT_GL_COPY_READ_BUFFER GL_COPY_READ_BUFFER
+ #define GLEXT_GL_COPY_WRITE_BUFFER GL_COPY_WRITE_BUFFER
+ #define GLEXT_glCopyBufferSubData glCopyBufferSubData
+
+ // Core since 3.2 - ARB_geometry_shader4
+ #define GLEXT_geometry_shader4 sfogl_ext_ARB_geometry_shader4
+ #define GLEXT_GL_GEOMETRY_SHADER GL_GEOMETRY_SHADER_ARB
+
+#endif
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// \brief Make sure that extensions are initialized
+///
+////////////////////////////////////////////////////////////
+void ensureExtensionsInit();
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_GLEXTENSIONS_HPP
diff --git a/src/SFML/Graphics/GLExtensions.txt b/src/SFML/Graphics/GLExtensions.txt
new file mode 100644
index 0000000..e12e809
--- /dev/null
+++ b/src/SFML/Graphics/GLExtensions.txt
@@ -0,0 +1,23 @@
+// Created with:
+// lua LoadGen.lua
+
+SGIS_texture_edge_clamp
+EXT_texture_edge_clamp
+EXT_blend_minmax
+EXT_blend_subtract
+ARB_multitexture
+EXT_blend_func_separate
+ARB_vertex_buffer_object
+ARB_shading_language_100
+ARB_shader_objects
+ARB_vertex_shader
+ARB_fragment_shader
+ARB_texture_non_power_of_two
+EXT_blend_equation_separate
+EXT_texture_sRGB
+EXT_framebuffer_object
+EXT_packed_depth_stencil
+EXT_framebuffer_blit
+EXT_framebuffer_multisample
+ARB_copy_buffer
+ARB_geometry_shader4
diff --git a/src/SFML/Graphics/GLLoader.cpp b/src/SFML/Graphics/GLLoader.cpp
new file mode 100644
index 0000000..85f6d7e
--- /dev/null
+++ b/src/SFML/Graphics/GLLoader.cpp
@@ -0,0 +1,1019 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/GLLoader.hpp>
+#include <SFML/Window/Context.hpp>
+
+static sf::GlFunctionPointer glLoaderGetProcAddress(const char* name)
+{
+ return sf::Context::getFunction(name);
+}
+
+int sfogl_ext_SGIS_texture_edge_clamp = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_texture_edge_clamp = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_blend_minmax = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_blend_func_separate = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_vertex_buffer_object = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_shading_language_100 = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_shader_objects = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_vertex_shader = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_fragment_shader = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_packed_depth_stencil = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_framebuffer_multisample = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED;
+int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
+
+void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL;
+
+static int Load_EXT_blend_minmax()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBlendEquationEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glBlendEquationEXT"));
+ if (!sf_ptrc_glBlendEquationEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glActiveTextureARB)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glClientActiveTextureARB)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1dARB)(GLenum, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1dvARB)(GLenum, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1fARB)(GLenum, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1fvARB)(GLenum, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1iARB)(GLenum, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1ivARB)(GLenum, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1sARB)(GLenum, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1svARB)(GLenum, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2dARB)(GLenum, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2dvARB)(GLenum, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2fARB)(GLenum, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2fvARB)(GLenum, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2iARB)(GLenum, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2ivARB)(GLenum, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2sARB)(GLenum, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2svARB)(GLenum, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3dARB)(GLenum, GLdouble, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3dvARB)(GLenum, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3fARB)(GLenum, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3fvARB)(GLenum, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3iARB)(GLenum, GLint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3ivARB)(GLenum, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3sARB)(GLenum, GLshort, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3svARB)(GLenum, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4dARB)(GLenum, GLdouble, GLdouble, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4dvARB)(GLenum, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4fARB)(GLenum, GLfloat, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4fvARB)(GLenum, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4iARB)(GLenum, GLint, GLint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4ivARB)(GLenum, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4sARB)(GLenum, GLshort, GLshort, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4svARB)(GLenum, const GLshort*) = NULL;
+
+static int Load_ARB_multitexture()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glActiveTextureARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glActiveTextureARB"));
+ if (!sf_ptrc_glActiveTextureARB)
+ numFailed++;
+
+ sf_ptrc_glClientActiveTextureARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glClientActiveTextureARB"));
+ if (!sf_ptrc_glClientActiveTextureARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLdouble)>(glLoaderGetProcAddress("glMultiTexCoord1dARB"));
+ if (!sf_ptrc_glMultiTexCoord1dARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLdouble*)>(glLoaderGetProcAddress("glMultiTexCoord1dvARB"));
+ if (!sf_ptrc_glMultiTexCoord1dvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLfloat)>(glLoaderGetProcAddress("glMultiTexCoord1fARB"));
+ if (!sf_ptrc_glMultiTexCoord1fARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLfloat*)>(glLoaderGetProcAddress("glMultiTexCoord1fvARB"));
+ if (!sf_ptrc_glMultiTexCoord1fvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLint)>(glLoaderGetProcAddress("glMultiTexCoord1iARB"));
+ if (!sf_ptrc_glMultiTexCoord1iARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLint*)>(glLoaderGetProcAddress("glMultiTexCoord1ivARB"));
+ if (!sf_ptrc_glMultiTexCoord1ivARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLshort)>(glLoaderGetProcAddress("glMultiTexCoord1sARB"));
+ if (!sf_ptrc_glMultiTexCoord1sARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord1svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLshort*)>(glLoaderGetProcAddress("glMultiTexCoord1svARB"));
+ if (!sf_ptrc_glMultiTexCoord1svARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLdouble, GLdouble)>(glLoaderGetProcAddress("glMultiTexCoord2dARB"));
+ if (!sf_ptrc_glMultiTexCoord2dARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLdouble*)>(glLoaderGetProcAddress("glMultiTexCoord2dvARB"));
+ if (!sf_ptrc_glMultiTexCoord2dvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLfloat, GLfloat)>(glLoaderGetProcAddress("glMultiTexCoord2fARB"));
+ if (!sf_ptrc_glMultiTexCoord2fARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLfloat*)>(glLoaderGetProcAddress("glMultiTexCoord2fvARB"));
+ if (!sf_ptrc_glMultiTexCoord2fvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLint, GLint)>(glLoaderGetProcAddress("glMultiTexCoord2iARB"));
+ if (!sf_ptrc_glMultiTexCoord2iARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLint*)>(glLoaderGetProcAddress("glMultiTexCoord2ivARB"));
+ if (!sf_ptrc_glMultiTexCoord2ivARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLshort, GLshort)>(glLoaderGetProcAddress("glMultiTexCoord2sARB"));
+ if (!sf_ptrc_glMultiTexCoord2sARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord2svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLshort*)>(glLoaderGetProcAddress("glMultiTexCoord2svARB"));
+ if (!sf_ptrc_glMultiTexCoord2svARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLdouble, GLdouble, GLdouble)>(glLoaderGetProcAddress("glMultiTexCoord3dARB"));
+ if (!sf_ptrc_glMultiTexCoord3dARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLdouble*)>(glLoaderGetProcAddress("glMultiTexCoord3dvARB"));
+ if (!sf_ptrc_glMultiTexCoord3dvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glMultiTexCoord3fARB"));
+ if (!sf_ptrc_glMultiTexCoord3fARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLfloat*)>(glLoaderGetProcAddress("glMultiTexCoord3fvARB"));
+ if (!sf_ptrc_glMultiTexCoord3fvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLint, GLint, GLint)>(glLoaderGetProcAddress("glMultiTexCoord3iARB"));
+ if (!sf_ptrc_glMultiTexCoord3iARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLint*)>(glLoaderGetProcAddress("glMultiTexCoord3ivARB"));
+ if (!sf_ptrc_glMultiTexCoord3ivARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLshort, GLshort, GLshort)>(glLoaderGetProcAddress("glMultiTexCoord3sARB"));
+ if (!sf_ptrc_glMultiTexCoord3sARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord3svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLshort*)>(glLoaderGetProcAddress("glMultiTexCoord3svARB"));
+ if (!sf_ptrc_glMultiTexCoord3svARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLdouble, GLdouble, GLdouble, GLdouble)>(glLoaderGetProcAddress("glMultiTexCoord4dARB"));
+ if (!sf_ptrc_glMultiTexCoord4dARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLdouble*)>(glLoaderGetProcAddress("glMultiTexCoord4dvARB"));
+ if (!sf_ptrc_glMultiTexCoord4dvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLfloat, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glMultiTexCoord4fARB"));
+ if (!sf_ptrc_glMultiTexCoord4fARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLfloat*)>(glLoaderGetProcAddress("glMultiTexCoord4fvARB"));
+ if (!sf_ptrc_glMultiTexCoord4fvARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLint, GLint, GLint, GLint)>(glLoaderGetProcAddress("glMultiTexCoord4iARB"));
+ if (!sf_ptrc_glMultiTexCoord4iARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLint*)>(glLoaderGetProcAddress("glMultiTexCoord4ivARB"));
+ if (!sf_ptrc_glMultiTexCoord4ivARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLshort, GLshort, GLshort, GLshort)>(glLoaderGetProcAddress("glMultiTexCoord4sARB"));
+ if (!sf_ptrc_glMultiTexCoord4sARB)
+ numFailed++;
+
+ sf_ptrc_glMultiTexCoord4svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, const GLshort*)>(glLoaderGetProcAddress("glMultiTexCoord4svARB"));
+ if (!sf_ptrc_glMultiTexCoord4svARB)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL;
+
+static int Load_EXT_blend_func_separate()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBlendFuncSeparateEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLenum)>(glLoaderGetProcAddress("glBlendFuncSeparateEXT"));
+ if (!sf_ptrc_glBlendFuncSeparateEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBindBufferARB)(GLenum, GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glBufferDataARB)(GLenum, GLsizeiptrARB, const void*, GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, const void*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDeleteBuffersARB)(GLsizei, const GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGenBuffersARB)(GLsizei, GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetBufferParameterivARB)(GLenum, GLenum, GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetBufferPointervARB)(GLenum, GLenum, void**) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, void*) = NULL;
+GLboolean (GL_FUNCPTR *sf_ptrc_glIsBufferARB)(GLuint) = NULL;
+void* (GL_FUNCPTR *sf_ptrc_glMapBufferARB)(GLenum, GLenum) = NULL;
+GLboolean (GL_FUNCPTR *sf_ptrc_glUnmapBufferARB)(GLenum) = NULL;
+
+static int Load_ARB_vertex_buffer_object()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBindBufferARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLuint)>(glLoaderGetProcAddress("glBindBufferARB"));
+ if (!sf_ptrc_glBindBufferARB)
+ numFailed++;
+
+ sf_ptrc_glBufferDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLsizeiptrARB, const void*, GLenum)>(glLoaderGetProcAddress("glBufferDataARB"));
+ if (!sf_ptrc_glBufferDataARB)
+ numFailed++;
+
+ sf_ptrc_glBufferSubDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLintptrARB, GLsizeiptrARB, const void*)>(glLoaderGetProcAddress("glBufferSubDataARB"));
+ if (!sf_ptrc_glBufferSubDataARB)
+ numFailed++;
+
+ sf_ptrc_glDeleteBuffersARB = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, const GLuint*)>(glLoaderGetProcAddress("glDeleteBuffersARB"));
+ if (!sf_ptrc_glDeleteBuffersARB)
+ numFailed++;
+
+ sf_ptrc_glGenBuffersARB = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, GLuint*)>(glLoaderGetProcAddress("glGenBuffersARB"));
+ if (!sf_ptrc_glGenBuffersARB)
+ numFailed++;
+
+ sf_ptrc_glGetBufferParameterivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLint*)>(glLoaderGetProcAddress("glGetBufferParameterivARB"));
+ if (!sf_ptrc_glGetBufferParameterivARB)
+ numFailed++;
+
+ sf_ptrc_glGetBufferPointervARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, void**)>(glLoaderGetProcAddress("glGetBufferPointervARB"));
+ if (!sf_ptrc_glGetBufferPointervARB)
+ numFailed++;
+
+ sf_ptrc_glGetBufferSubDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLintptrARB, GLsizeiptrARB, void*)>(glLoaderGetProcAddress("glGetBufferSubDataARB"));
+ if (!sf_ptrc_glGetBufferSubDataARB)
+ numFailed++;
+
+ sf_ptrc_glIsBufferARB = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glIsBufferARB"));
+ if (!sf_ptrc_glIsBufferARB)
+ numFailed++;
+
+ sf_ptrc_glMapBufferARB = reinterpret_cast<void* (GL_FUNCPTR *)(GLenum, GLenum)>(glLoaderGetProcAddress("glMapBufferARB"));
+ if (!sf_ptrc_glMapBufferARB)
+ numFailed++;
+
+ sf_ptrc_glUnmapBufferARB = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glUnmapBufferARB"));
+ if (!sf_ptrc_glUnmapBufferARB)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glAttachObjectARB)(GLhandleARB, GLhandleARB) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glCompileShaderARB)(GLhandleARB) = NULL;
+GLhandleARB (GL_FUNCPTR *sf_ptrc_glCreateProgramObjectARB)() = NULL;
+GLhandleARB (GL_FUNCPTR *sf_ptrc_glCreateShaderObjectARB)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDeleteObjectARB)(GLhandleARB) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDetachObjectARB)(GLhandleARB, GLhandleARB) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetActiveUniformARB)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetAttachedObjectsARB)(GLhandleARB, GLsizei, GLsizei*, GLhandleARB*) = NULL;
+GLhandleARB (GL_FUNCPTR *sf_ptrc_glGetHandleARB)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetInfoLogARB)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetObjectParameterfvARB)(GLhandleARB, GLenum, GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetObjectParameterivARB)(GLhandleARB, GLenum, GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetShaderSourceARB)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*) = NULL;
+GLint (GL_FUNCPTR *sf_ptrc_glGetUniformLocationARB)(GLhandleARB, const GLcharARB*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetUniformfvARB)(GLhandleARB, GLint, GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetUniformivARB)(GLhandleARB, GLint, GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glLinkProgramARB)(GLhandleARB) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glShaderSourceARB)(GLhandleARB, GLsizei, const GLcharARB**, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform1fARB)(GLint, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform1fvARB)(GLint, GLsizei, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform1iARB)(GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform1ivARB)(GLint, GLsizei, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform2fARB)(GLint, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform2fvARB)(GLint, GLsizei, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform2iARB)(GLint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform2ivARB)(GLint, GLsizei, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform3fARB)(GLint, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform3fvARB)(GLint, GLsizei, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform3iARB)(GLint, GLint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform3ivARB)(GLint, GLsizei, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform4fARB)(GLint, GLfloat, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform4fvARB)(GLint, GLsizei, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform4iARB)(GLint, GLint, GLint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniform4ivARB)(GLint, GLsizei, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniformMatrix2fvARB)(GLint, GLsizei, GLboolean, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniformMatrix3fvARB)(GLint, GLsizei, GLboolean, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUniformMatrix4fvARB)(GLint, GLsizei, GLboolean, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glUseProgramObjectARB)(GLhandleARB) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glValidateProgramARB)(GLhandleARB) = NULL;
+
+static int Load_ARB_shader_objects()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glAttachObjectARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLhandleARB)>(glLoaderGetProcAddress("glAttachObjectARB"));
+ if (!sf_ptrc_glAttachObjectARB)
+ numFailed++;
+
+ sf_ptrc_glCompileShaderARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB)>(glLoaderGetProcAddress("glCompileShaderARB"));
+ if (!sf_ptrc_glCompileShaderARB)
+ numFailed++;
+
+ sf_ptrc_glCreateProgramObjectARB = reinterpret_cast<GLhandleARB (GL_FUNCPTR *)()>(glLoaderGetProcAddress("glCreateProgramObjectARB"));
+ if (!sf_ptrc_glCreateProgramObjectARB)
+ numFailed++;
+
+ sf_ptrc_glCreateShaderObjectARB = reinterpret_cast<GLhandleARB (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glCreateShaderObjectARB"));
+ if (!sf_ptrc_glCreateShaderObjectARB)
+ numFailed++;
+
+ sf_ptrc_glDeleteObjectARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB)>(glLoaderGetProcAddress("glDeleteObjectARB"));
+ if (!sf_ptrc_glDeleteObjectARB)
+ numFailed++;
+
+ sf_ptrc_glDetachObjectARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLhandleARB)>(glLoaderGetProcAddress("glDetachObjectARB"));
+ if (!sf_ptrc_glDetachObjectARB)
+ numFailed++;
+
+ sf_ptrc_glGetActiveUniformARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*)>(glLoaderGetProcAddress("glGetActiveUniformARB"));
+ if (!sf_ptrc_glGetActiveUniformARB)
+ numFailed++;
+
+ sf_ptrc_glGetAttachedObjectsARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLsizei, GLsizei*, GLhandleARB*)>(glLoaderGetProcAddress("glGetAttachedObjectsARB"));
+ if (!sf_ptrc_glGetAttachedObjectsARB)
+ numFailed++;
+
+ sf_ptrc_glGetHandleARB = reinterpret_cast<GLhandleARB (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glGetHandleARB"));
+ if (!sf_ptrc_glGetHandleARB)
+ numFailed++;
+
+ sf_ptrc_glGetInfoLogARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*)>(glLoaderGetProcAddress("glGetInfoLogARB"));
+ if (!sf_ptrc_glGetInfoLogARB)
+ numFailed++;
+
+ sf_ptrc_glGetObjectParameterfvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLenum, GLfloat*)>(glLoaderGetProcAddress("glGetObjectParameterfvARB"));
+ if (!sf_ptrc_glGetObjectParameterfvARB)
+ numFailed++;
+
+ sf_ptrc_glGetObjectParameterivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLenum, GLint*)>(glLoaderGetProcAddress("glGetObjectParameterivARB"));
+ if (!sf_ptrc_glGetObjectParameterivARB)
+ numFailed++;
+
+ sf_ptrc_glGetShaderSourceARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*)>(glLoaderGetProcAddress("glGetShaderSourceARB"));
+ if (!sf_ptrc_glGetShaderSourceARB)
+ numFailed++;
+
+ sf_ptrc_glGetUniformLocationARB = reinterpret_cast<GLint (GL_FUNCPTR *)(GLhandleARB, const GLcharARB*)>(glLoaderGetProcAddress("glGetUniformLocationARB"));
+ if (!sf_ptrc_glGetUniformLocationARB)
+ numFailed++;
+
+ sf_ptrc_glGetUniformfvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLint, GLfloat*)>(glLoaderGetProcAddress("glGetUniformfvARB"));
+ if (!sf_ptrc_glGetUniformfvARB)
+ numFailed++;
+
+ sf_ptrc_glGetUniformivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLint, GLint*)>(glLoaderGetProcAddress("glGetUniformivARB"));
+ if (!sf_ptrc_glGetUniformivARB)
+ numFailed++;
+
+ sf_ptrc_glLinkProgramARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB)>(glLoaderGetProcAddress("glLinkProgramARB"));
+ if (!sf_ptrc_glLinkProgramARB)
+ numFailed++;
+
+ sf_ptrc_glShaderSourceARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLsizei, const GLcharARB**, const GLint*)>(glLoaderGetProcAddress("glShaderSourceARB"));
+ if (!sf_ptrc_glShaderSourceARB)
+ numFailed++;
+
+ sf_ptrc_glUniform1fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLfloat)>(glLoaderGetProcAddress("glUniform1fARB"));
+ if (!sf_ptrc_glUniform1fARB)
+ numFailed++;
+
+ sf_ptrc_glUniform1fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLfloat*)>(glLoaderGetProcAddress("glUniform1fvARB"));
+ if (!sf_ptrc_glUniform1fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniform1iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint)>(glLoaderGetProcAddress("glUniform1iARB"));
+ if (!sf_ptrc_glUniform1iARB)
+ numFailed++;
+
+ sf_ptrc_glUniform1ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLint*)>(glLoaderGetProcAddress("glUniform1ivARB"));
+ if (!sf_ptrc_glUniform1ivARB)
+ numFailed++;
+
+ sf_ptrc_glUniform2fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLfloat, GLfloat)>(glLoaderGetProcAddress("glUniform2fARB"));
+ if (!sf_ptrc_glUniform2fARB)
+ numFailed++;
+
+ sf_ptrc_glUniform2fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLfloat*)>(glLoaderGetProcAddress("glUniform2fvARB"));
+ if (!sf_ptrc_glUniform2fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniform2iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint, GLint)>(glLoaderGetProcAddress("glUniform2iARB"));
+ if (!sf_ptrc_glUniform2iARB)
+ numFailed++;
+
+ sf_ptrc_glUniform2ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLint*)>(glLoaderGetProcAddress("glUniform2ivARB"));
+ if (!sf_ptrc_glUniform2ivARB)
+ numFailed++;
+
+ sf_ptrc_glUniform3fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glUniform3fARB"));
+ if (!sf_ptrc_glUniform3fARB)
+ numFailed++;
+
+ sf_ptrc_glUniform3fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLfloat*)>(glLoaderGetProcAddress("glUniform3fvARB"));
+ if (!sf_ptrc_glUniform3fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniform3iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint, GLint, GLint)>(glLoaderGetProcAddress("glUniform3iARB"));
+ if (!sf_ptrc_glUniform3iARB)
+ numFailed++;
+
+ sf_ptrc_glUniform3ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLint*)>(glLoaderGetProcAddress("glUniform3ivARB"));
+ if (!sf_ptrc_glUniform3ivARB)
+ numFailed++;
+
+ sf_ptrc_glUniform4fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLfloat, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glUniform4fARB"));
+ if (!sf_ptrc_glUniform4fARB)
+ numFailed++;
+
+ sf_ptrc_glUniform4fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLfloat*)>(glLoaderGetProcAddress("glUniform4fvARB"));
+ if (!sf_ptrc_glUniform4fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniform4iARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint, GLint, GLint, GLint)>(glLoaderGetProcAddress("glUniform4iARB"));
+ if (!sf_ptrc_glUniform4iARB)
+ numFailed++;
+
+ sf_ptrc_glUniform4ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, const GLint*)>(glLoaderGetProcAddress("glUniform4ivARB"));
+ if (!sf_ptrc_glUniform4ivARB)
+ numFailed++;
+
+ sf_ptrc_glUniformMatrix2fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, GLboolean, const GLfloat*)>(glLoaderGetProcAddress("glUniformMatrix2fvARB"));
+ if (!sf_ptrc_glUniformMatrix2fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniformMatrix3fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, GLboolean, const GLfloat*)>(glLoaderGetProcAddress("glUniformMatrix3fvARB"));
+ if (!sf_ptrc_glUniformMatrix3fvARB)
+ numFailed++;
+
+ sf_ptrc_glUniformMatrix4fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLsizei, GLboolean, const GLfloat*)>(glLoaderGetProcAddress("glUniformMatrix4fvARB"));
+ if (!sf_ptrc_glUniformMatrix4fvARB)
+ numFailed++;
+
+ sf_ptrc_glUseProgramObjectARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB)>(glLoaderGetProcAddress("glUseProgramObjectARB"));
+ if (!sf_ptrc_glUseProgramObjectARB)
+ numFailed++;
+
+ sf_ptrc_glValidateProgramARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB)>(glLoaderGetProcAddress("glValidateProgramARB"));
+ if (!sf_ptrc_glValidateProgramARB)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBindAttribLocationARB)(GLhandleARB, GLuint, const GLcharARB*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDisableVertexAttribArrayARB)(GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glEnableVertexAttribArrayARB)(GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetActiveAttribARB)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*) = NULL;
+GLint (GL_FUNCPTR *sf_ptrc_glGetAttribLocationARB)(GLhandleARB, const GLcharARB*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribPointervARB)(GLuint, GLenum, void**) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribdvARB)(GLuint, GLenum, GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribfvARB)(GLuint, GLenum, GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribivARB)(GLuint, GLenum, GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1dARB)(GLuint, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1dvARB)(GLuint, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1fARB)(GLuint, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1fvARB)(GLuint, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1sARB)(GLuint, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1svARB)(GLuint, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2dARB)(GLuint, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2dvARB)(GLuint, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2fARB)(GLuint, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2fvARB)(GLuint, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2sARB)(GLuint, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2svARB)(GLuint, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3dARB)(GLuint, GLdouble, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3dvARB)(GLuint, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3fARB)(GLuint, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3fvARB)(GLuint, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3sARB)(GLuint, GLshort, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3svARB)(GLuint, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NbvARB)(GLuint, const GLbyte*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NivARB)(GLuint, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NsvARB)(GLuint, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NubARB)(GLuint, GLubyte, GLubyte, GLubyte, GLubyte) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NubvARB)(GLuint, const GLubyte*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NuivARB)(GLuint, const GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NusvARB)(GLuint, const GLushort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4bvARB)(GLuint, const GLbyte*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4dARB)(GLuint, GLdouble, GLdouble, GLdouble, GLdouble) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4dvARB)(GLuint, const GLdouble*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4fARB)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4fvARB)(GLuint, const GLfloat*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4ivARB)(GLuint, const GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4sARB)(GLuint, GLshort, GLshort, GLshort, GLshort) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4svARB)(GLuint, const GLshort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4ubvARB)(GLuint, const GLubyte*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4uivARB)(GLuint, const GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4usvARB)(GLuint, const GLushort*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glVertexAttribPointerARB)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*) = NULL;
+
+static int Load_ARB_vertex_shader()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBindAttribLocationARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLuint, const GLcharARB*)>(glLoaderGetProcAddress("glBindAttribLocationARB"));
+ if (!sf_ptrc_glBindAttribLocationARB)
+ numFailed++;
+
+ sf_ptrc_glDisableVertexAttribArrayARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glDisableVertexAttribArrayARB"));
+ if (!sf_ptrc_glDisableVertexAttribArrayARB)
+ numFailed++;
+
+ sf_ptrc_glEnableVertexAttribArrayARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glEnableVertexAttribArrayARB"));
+ if (!sf_ptrc_glEnableVertexAttribArrayARB)
+ numFailed++;
+
+ sf_ptrc_glGetActiveAttribARB = reinterpret_cast<void (GL_FUNCPTR *)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*)>(glLoaderGetProcAddress("glGetActiveAttribARB"));
+ if (!sf_ptrc_glGetActiveAttribARB)
+ numFailed++;
+
+ sf_ptrc_glGetAttribLocationARB = reinterpret_cast<GLint (GL_FUNCPTR *)(GLhandleARB, const GLcharARB*)>(glLoaderGetProcAddress("glGetAttribLocationARB"));
+ if (!sf_ptrc_glGetAttribLocationARB)
+ numFailed++;
+
+ sf_ptrc_glGetVertexAttribPointervARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, void**)>(glLoaderGetProcAddress("glGetVertexAttribPointervARB"));
+ if (!sf_ptrc_glGetVertexAttribPointervARB)
+ numFailed++;
+
+ sf_ptrc_glGetVertexAttribdvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, GLdouble*)>(glLoaderGetProcAddress("glGetVertexAttribdvARB"));
+ if (!sf_ptrc_glGetVertexAttribdvARB)
+ numFailed++;
+
+ sf_ptrc_glGetVertexAttribfvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, GLfloat*)>(glLoaderGetProcAddress("glGetVertexAttribfvARB"));
+ if (!sf_ptrc_glGetVertexAttribfvARB)
+ numFailed++;
+
+ sf_ptrc_glGetVertexAttribivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, GLint*)>(glLoaderGetProcAddress("glGetVertexAttribivARB"));
+ if (!sf_ptrc_glGetVertexAttribivARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLdouble)>(glLoaderGetProcAddress("glVertexAttrib1dARB"));
+ if (!sf_ptrc_glVertexAttrib1dARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLdouble*)>(glLoaderGetProcAddress("glVertexAttrib1dvARB"));
+ if (!sf_ptrc_glVertexAttrib1dvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLfloat)>(glLoaderGetProcAddress("glVertexAttrib1fARB"));
+ if (!sf_ptrc_glVertexAttrib1fARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLfloat*)>(glLoaderGetProcAddress("glVertexAttrib1fvARB"));
+ if (!sf_ptrc_glVertexAttrib1fvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLshort)>(glLoaderGetProcAddress("glVertexAttrib1sARB"));
+ if (!sf_ptrc_glVertexAttrib1sARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib1svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLshort*)>(glLoaderGetProcAddress("glVertexAttrib1svARB"));
+ if (!sf_ptrc_glVertexAttrib1svARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLdouble, GLdouble)>(glLoaderGetProcAddress("glVertexAttrib2dARB"));
+ if (!sf_ptrc_glVertexAttrib2dARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLdouble*)>(glLoaderGetProcAddress("glVertexAttrib2dvARB"));
+ if (!sf_ptrc_glVertexAttrib2dvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLfloat, GLfloat)>(glLoaderGetProcAddress("glVertexAttrib2fARB"));
+ if (!sf_ptrc_glVertexAttrib2fARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLfloat*)>(glLoaderGetProcAddress("glVertexAttrib2fvARB"));
+ if (!sf_ptrc_glVertexAttrib2fvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLshort, GLshort)>(glLoaderGetProcAddress("glVertexAttrib2sARB"));
+ if (!sf_ptrc_glVertexAttrib2sARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib2svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLshort*)>(glLoaderGetProcAddress("glVertexAttrib2svARB"));
+ if (!sf_ptrc_glVertexAttrib2svARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLdouble, GLdouble, GLdouble)>(glLoaderGetProcAddress("glVertexAttrib3dARB"));
+ if (!sf_ptrc_glVertexAttrib3dARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLdouble*)>(glLoaderGetProcAddress("glVertexAttrib3dvARB"));
+ if (!sf_ptrc_glVertexAttrib3dvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glVertexAttrib3fARB"));
+ if (!sf_ptrc_glVertexAttrib3fARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLfloat*)>(glLoaderGetProcAddress("glVertexAttrib3fvARB"));
+ if (!sf_ptrc_glVertexAttrib3fvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLshort, GLshort, GLshort)>(glLoaderGetProcAddress("glVertexAttrib3sARB"));
+ if (!sf_ptrc_glVertexAttrib3sARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib3svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLshort*)>(glLoaderGetProcAddress("glVertexAttrib3svARB"));
+ if (!sf_ptrc_glVertexAttrib3svARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NbvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLbyte*)>(glLoaderGetProcAddress("glVertexAttrib4NbvARB"));
+ if (!sf_ptrc_glVertexAttrib4NbvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLint*)>(glLoaderGetProcAddress("glVertexAttrib4NivARB"));
+ if (!sf_ptrc_glVertexAttrib4NivARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NsvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLshort*)>(glLoaderGetProcAddress("glVertexAttrib4NsvARB"));
+ if (!sf_ptrc_glVertexAttrib4NsvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NubARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLubyte, GLubyte, GLubyte, GLubyte)>(glLoaderGetProcAddress("glVertexAttrib4NubARB"));
+ if (!sf_ptrc_glVertexAttrib4NubARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NubvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLubyte*)>(glLoaderGetProcAddress("glVertexAttrib4NubvARB"));
+ if (!sf_ptrc_glVertexAttrib4NubvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NuivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLuint*)>(glLoaderGetProcAddress("glVertexAttrib4NuivARB"));
+ if (!sf_ptrc_glVertexAttrib4NuivARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4NusvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLushort*)>(glLoaderGetProcAddress("glVertexAttrib4NusvARB"));
+ if (!sf_ptrc_glVertexAttrib4NusvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4bvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLbyte*)>(glLoaderGetProcAddress("glVertexAttrib4bvARB"));
+ if (!sf_ptrc_glVertexAttrib4bvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4dARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLdouble, GLdouble, GLdouble, GLdouble)>(glLoaderGetProcAddress("glVertexAttrib4dARB"));
+ if (!sf_ptrc_glVertexAttrib4dARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4dvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLdouble*)>(glLoaderGetProcAddress("glVertexAttrib4dvARB"));
+ if (!sf_ptrc_glVertexAttrib4dvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4fARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat)>(glLoaderGetProcAddress("glVertexAttrib4fARB"));
+ if (!sf_ptrc_glVertexAttrib4fARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4fvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLfloat*)>(glLoaderGetProcAddress("glVertexAttrib4fvARB"));
+ if (!sf_ptrc_glVertexAttrib4fvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4ivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLint*)>(glLoaderGetProcAddress("glVertexAttrib4ivARB"));
+ if (!sf_ptrc_glVertexAttrib4ivARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4sARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLshort, GLshort, GLshort, GLshort)>(glLoaderGetProcAddress("glVertexAttrib4sARB"));
+ if (!sf_ptrc_glVertexAttrib4sARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4svARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLshort*)>(glLoaderGetProcAddress("glVertexAttrib4svARB"));
+ if (!sf_ptrc_glVertexAttrib4svARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4ubvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLubyte*)>(glLoaderGetProcAddress("glVertexAttrib4ubvARB"));
+ if (!sf_ptrc_glVertexAttrib4ubvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4uivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLuint*)>(glLoaderGetProcAddress("glVertexAttrib4uivARB"));
+ if (!sf_ptrc_glVertexAttrib4uivARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttrib4usvARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, const GLushort*)>(glLoaderGetProcAddress("glVertexAttrib4usvARB"));
+ if (!sf_ptrc_glVertexAttrib4usvARB)
+ numFailed++;
+
+ sf_ptrc_glVertexAttribPointerARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*)>(glLoaderGetProcAddress("glVertexAttribPointerARB"));
+ if (!sf_ptrc_glVertexAttribPointerARB)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBlendEquationSeparateEXT)(GLenum, GLenum) = NULL;
+
+static int Load_EXT_blend_equation_separate()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBlendEquationSeparateEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum)>(glLoaderGetProcAddress("glBlendEquationSeparateEXT"));
+ if (!sf_ptrc_glBlendEquationSeparateEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBindFramebufferEXT)(GLenum, GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glBindRenderbufferEXT)(GLenum, GLuint) = NULL;
+GLenum (GL_FUNCPTR *sf_ptrc_glCheckFramebufferStatusEXT)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDeleteFramebuffersEXT)(GLsizei, const GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glDeleteRenderbuffersEXT)(GLsizei, const GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferRenderbufferEXT)(GLenum, GLenum, GLenum, GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture1DEXT)(GLenum, GLenum, GLenum, GLuint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture2DEXT)(GLenum, GLenum, GLenum, GLuint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture3DEXT)(GLenum, GLenum, GLenum, GLuint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGenFramebuffersEXT)(GLsizei, GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGenRenderbuffersEXT)(GLsizei, GLuint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGenerateMipmapEXT)(GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetFramebufferAttachmentParameterivEXT)(GLenum, GLenum, GLenum, GLint*) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glGetRenderbufferParameterivEXT)(GLenum, GLenum, GLint*) = NULL;
+GLboolean (GL_FUNCPTR *sf_ptrc_glIsFramebufferEXT)(GLuint) = NULL;
+GLboolean (GL_FUNCPTR *sf_ptrc_glIsRenderbufferEXT)(GLuint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsizei, GLsizei) = NULL;
+
+static int Load_EXT_framebuffer_object()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBindFramebufferEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLuint)>(glLoaderGetProcAddress("glBindFramebufferEXT"));
+ if (!sf_ptrc_glBindFramebufferEXT)
+ numFailed++;
+
+ sf_ptrc_glBindRenderbufferEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLuint)>(glLoaderGetProcAddress("glBindRenderbufferEXT"));
+ if (!sf_ptrc_glBindRenderbufferEXT)
+ numFailed++;
+
+ sf_ptrc_glCheckFramebufferStatusEXT = reinterpret_cast<GLenum (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glCheckFramebufferStatusEXT"));
+ if (!sf_ptrc_glCheckFramebufferStatusEXT)
+ numFailed++;
+
+ sf_ptrc_glDeleteFramebuffersEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, const GLuint*)>(glLoaderGetProcAddress("glDeleteFramebuffersEXT"));
+ if (!sf_ptrc_glDeleteFramebuffersEXT)
+ numFailed++;
+
+ sf_ptrc_glDeleteRenderbuffersEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, const GLuint*)>(glLoaderGetProcAddress("glDeleteRenderbuffersEXT"));
+ if (!sf_ptrc_glDeleteRenderbuffersEXT)
+ numFailed++;
+
+ sf_ptrc_glFramebufferRenderbufferEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLuint)>(glLoaderGetProcAddress("glFramebufferRenderbufferEXT"));
+ if (!sf_ptrc_glFramebufferRenderbufferEXT)
+ numFailed++;
+
+ sf_ptrc_glFramebufferTexture1DEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLuint, GLint)>(glLoaderGetProcAddress("glFramebufferTexture1DEXT"));
+ if (!sf_ptrc_glFramebufferTexture1DEXT)
+ numFailed++;
+
+ sf_ptrc_glFramebufferTexture2DEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLuint, GLint)>(glLoaderGetProcAddress("glFramebufferTexture2DEXT"));
+ if (!sf_ptrc_glFramebufferTexture2DEXT)
+ numFailed++;
+
+ sf_ptrc_glFramebufferTexture3DEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLuint, GLint, GLint)>(glLoaderGetProcAddress("glFramebufferTexture3DEXT"));
+ if (!sf_ptrc_glFramebufferTexture3DEXT)
+ numFailed++;
+
+ sf_ptrc_glGenFramebuffersEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, GLuint*)>(glLoaderGetProcAddress("glGenFramebuffersEXT"));
+ if (!sf_ptrc_glGenFramebuffersEXT)
+ numFailed++;
+
+ sf_ptrc_glGenRenderbuffersEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, GLuint*)>(glLoaderGetProcAddress("glGenRenderbuffersEXT"));
+ if (!sf_ptrc_glGenRenderbuffersEXT)
+ numFailed++;
+
+ sf_ptrc_glGenerateMipmapEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glGenerateMipmapEXT"));
+ if (!sf_ptrc_glGenerateMipmapEXT)
+ numFailed++;
+
+ sf_ptrc_glGetFramebufferAttachmentParameterivEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLenum, GLint*)>(glLoaderGetProcAddress("glGetFramebufferAttachmentParameterivEXT"));
+ if (!sf_ptrc_glGetFramebufferAttachmentParameterivEXT)
+ numFailed++;
+
+ sf_ptrc_glGetRenderbufferParameterivEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLint*)>(glLoaderGetProcAddress("glGetRenderbufferParameterivEXT"));
+ if (!sf_ptrc_glGetRenderbufferParameterivEXT)
+ numFailed++;
+
+ sf_ptrc_glIsFramebufferEXT = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glIsFramebufferEXT"));
+ if (!sf_ptrc_glIsFramebufferEXT)
+ numFailed++;
+
+ sf_ptrc_glIsRenderbufferEXT = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glIsRenderbufferEXT"));
+ if (!sf_ptrc_glIsRenderbufferEXT)
+ numFailed++;
+
+ sf_ptrc_glRenderbufferStorageEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLsizei, GLsizei)>(glLoaderGetProcAddress("glRenderbufferStorageEXT"));
+ if (!sf_ptrc_glRenderbufferStorageEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum) = NULL;
+
+static int Load_EXT_framebuffer_blit()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glBlitFramebufferEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)>(glLoaderGetProcAddress("glBlitFramebufferEXT"));
+ if (!sf_ptrc_glBlitFramebufferEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageMultisampleEXT)(GLenum, GLsizei, GLenum, GLsizei, GLsizei) = NULL;
+
+static int Load_EXT_framebuffer_multisample()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glRenderbufferStorageMultisampleEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLsizei, GLenum, GLsizei, GLsizei)>(glLoaderGetProcAddress("glRenderbufferStorageMultisampleEXT"));
+ if (!sf_ptrc_glRenderbufferStorageMultisampleEXT)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr) = NULL;
+
+static int Load_ARB_copy_buffer()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glCopyBufferSubData = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr)>(glLoaderGetProcAddress("glCopyBufferSubData"));
+ if (!sf_ptrc_glCopyBufferSubData)
+ numFailed++;
+
+ return numFailed;
+}
+
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint) = NULL;
+void (GL_FUNCPTR *sf_ptrc_glProgramParameteriARB)(GLuint, GLenum, GLint) = NULL;
+
+static int Load_ARB_geometry_shader4()
+{
+ int numFailed = 0;
+
+ sf_ptrc_glFramebufferTextureARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint)>(glLoaderGetProcAddress("glFramebufferTextureARB"));
+ if (!sf_ptrc_glFramebufferTextureARB)
+ numFailed++;
+
+ sf_ptrc_glFramebufferTextureFaceARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint, GLenum)>(glLoaderGetProcAddress("glFramebufferTextureFaceARB"));
+ if (!sf_ptrc_glFramebufferTextureFaceARB)
+ numFailed++;
+
+ sf_ptrc_glFramebufferTextureLayerARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint, GLint)>(glLoaderGetProcAddress("glFramebufferTextureLayerARB"));
+ if (!sf_ptrc_glFramebufferTextureLayerARB)
+ numFailed++;
+
+ sf_ptrc_glProgramParameteriARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, GLint)>(glLoaderGetProcAddress("glProgramParameteriARB"));
+ if (!sf_ptrc_glProgramParameteriARB)
+ numFailed++;
+
+ return numFailed;
+}
+
+typedef int (*PFN_LOADFUNCPOINTERS)();
+typedef struct sfogl_StrToExtMap_s
+{
+ const char* extensionName;
+ int* extensionVariable;
+ PFN_LOADFUNCPOINTERS LoadExtension;
+} sfogl_StrToExtMap;
+
+static sfogl_StrToExtMap ExtensionMap[20] = {
+ {"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL},
+ {"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
+ {"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax},
+ {"GL_EXT_blend_subtract", &sfogl_ext_EXT_blend_subtract, NULL},
+ {"GL_ARB_multitexture", &sfogl_ext_ARB_multitexture, Load_ARB_multitexture},
+ {"GL_EXT_blend_func_separate", &sfogl_ext_EXT_blend_func_separate, Load_EXT_blend_func_separate},
+ {"GL_ARB_vertex_buffer_object", &sfogl_ext_ARB_vertex_buffer_object, Load_ARB_vertex_buffer_object},
+ {"GL_ARB_shading_language_100", &sfogl_ext_ARB_shading_language_100, NULL},
+ {"GL_ARB_shader_objects", &sfogl_ext_ARB_shader_objects, Load_ARB_shader_objects},
+ {"GL_ARB_vertex_shader", &sfogl_ext_ARB_vertex_shader, Load_ARB_vertex_shader},
+ {"GL_ARB_fragment_shader", &sfogl_ext_ARB_fragment_shader, NULL},
+ {"GL_ARB_texture_non_power_of_two", &sfogl_ext_ARB_texture_non_power_of_two, NULL},
+ {"GL_EXT_blend_equation_separate", &sfogl_ext_EXT_blend_equation_separate, Load_EXT_blend_equation_separate},
+ {"GL_EXT_texture_sRGB", &sfogl_ext_EXT_texture_sRGB, NULL},
+ {"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object},
+ {"GL_EXT_packed_depth_stencil", &sfogl_ext_EXT_packed_depth_stencil, NULL},
+ {"GL_EXT_framebuffer_blit", &sfogl_ext_EXT_framebuffer_blit, Load_EXT_framebuffer_blit},
+ {"GL_EXT_framebuffer_multisample", &sfogl_ext_EXT_framebuffer_multisample, Load_EXT_framebuffer_multisample},
+ {"GL_ARB_copy_buffer", &sfogl_ext_ARB_copy_buffer, Load_ARB_copy_buffer},
+ {"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4}
+};
+
+static int g_extensionMapSize = 20;
+
+
+static void ClearExtensionVars()
+{
+ sfogl_ext_SGIS_texture_edge_clamp = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_texture_edge_clamp = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_blend_minmax = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_blend_func_separate = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_vertex_buffer_object = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_shading_language_100 = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_shader_objects = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_vertex_shader = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_fragment_shader = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_packed_depth_stencil = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
+ sfogl_ext_EXT_framebuffer_multisample = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED;
+ sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
+}
+
+
+static void LoadExtension(sfogl_StrToExtMap& extension)
+{
+ if (extension.LoadExtension)
+ {
+ *(extension.extensionVariable) = sfogl_LOAD_SUCCEEDED + extension.LoadExtension();
+ }
+ else
+ {
+ *(extension.extensionVariable) = sfogl_LOAD_SUCCEEDED;
+ }
+}
+
+
+void sfogl_LoadFunctions()
+{
+ ClearExtensionVars();
+
+ for (int i = 0; i < g_extensionMapSize; ++i)
+ {
+ if (sf::Context::isExtensionAvailable(ExtensionMap[i].extensionName))
+ LoadExtension(ExtensionMap[i]);
+ }
+}
diff --git a/src/SFML/Graphics/GLLoader.hpp b/src/SFML/Graphics/GLLoader.hpp
new file mode 100644
index 0000000..9fe4adb
--- /dev/null
+++ b/src/SFML/Graphics/GLLoader.hpp
@@ -0,0 +1,1706 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GLLOADER_HPP
+#define SFML_GLLOADER_HPP
+
+#if defined(__glew_h__) || defined(__GLEW_H__)
+#error Attempt to include auto-generated header after including glew.h
+#endif
+#if defined(__gl_h_) || defined(__GL_H__)
+#error Attempt to include auto-generated header after including gl.h
+#endif
+#if defined(__glext_h_) || defined(__GLEXT_H_)
+#error Attempt to include auto-generated header after including glext.h
+#endif
+#if defined(__gltypes_h_)
+#error Attempt to include auto-generated header after gltypes.h
+#endif
+#if defined(__gl_ATI_h_)
+#error Attempt to include auto-generated header after including glATI.h
+#endif
+
+#define __glew_h__
+#define __GLEW_H__
+#define __gl_h_
+#define __GL_H__
+#define __glext_h_
+#define __GLEXT_H_
+#define __gltypes_h_
+#define __gl_ATI_h_
+
+#ifndef APIENTRY
+ #if defined(__MINGW32__)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN 1
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include <windows.h>
+ #elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN 1
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include <windows.h>
+ #else
+ #define APIENTRY
+ #endif
+#endif // APIENTRY
+
+#ifndef GL_FUNCPTR
+ #define GL_REMOVE_FUNCPTR
+ #if defined(_WIN32)
+ #define GL_FUNCPTR APIENTRY
+ #else
+ #define GL_FUNCPTR
+ #endif
+#endif // GL_FUNCPTR
+
+#ifndef GLAPI
+ #define GLAPI extern
+#endif
+
+
+#include <stddef.h>
+#ifndef GLEXT_64_TYPES_DEFINED
+// This code block is duplicated in glxext.h, so must be protected
+#define GLEXT_64_TYPES_DEFINED
+// Define int32_t, int64_t, and uint64_t types for UST/MSC
+// (as used in the GL_EXT_timer_query extension).
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__) || defined(__digital__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif // __arch64__
+#endif // __STDC__
+#elif defined( __VMS ) || defined(__sgi)
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+// Fallback if nothing above works
+#include <inttypes.h>
+#endif
+#endif
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef int GLsizei;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef char GLchar;
+typedef char GLcharARB;
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef unsigned short GLhalfARB;
+typedef unsigned short GLhalf;
+typedef GLint GLfixed;
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+typedef int64_t GLint64;
+typedef uint64_t GLuint64;
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+typedef int64_t GLint64EXT;
+typedef uint64_t GLuint64EXT;
+typedef struct __GLsync *GLsync;
+struct _cl_context;
+struct _cl_event;
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
+typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
+typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar* message, void* userParam);
+typedef unsigned short GLhalfNV;
+typedef GLintptr GLvdpauSurfaceNV;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+extern int sfogl_ext_SGIS_texture_edge_clamp;
+extern int sfogl_ext_EXT_texture_edge_clamp;
+extern int sfogl_ext_EXT_blend_minmax;
+extern int sfogl_ext_EXT_blend_subtract;
+extern int sfogl_ext_ARB_multitexture;
+extern int sfogl_ext_EXT_blend_func_separate;
+extern int sfogl_ext_ARB_vertex_buffer_object;
+extern int sfogl_ext_ARB_shading_language_100;
+extern int sfogl_ext_ARB_shader_objects;
+extern int sfogl_ext_ARB_vertex_shader;
+extern int sfogl_ext_ARB_fragment_shader;
+extern int sfogl_ext_ARB_texture_non_power_of_two;
+extern int sfogl_ext_EXT_blend_equation_separate;
+extern int sfogl_ext_EXT_texture_sRGB;
+extern int sfogl_ext_EXT_framebuffer_object;
+extern int sfogl_ext_EXT_packed_depth_stencil;
+extern int sfogl_ext_EXT_framebuffer_blit;
+extern int sfogl_ext_EXT_framebuffer_multisample;
+extern int sfogl_ext_ARB_copy_buffer;
+extern int sfogl_ext_ARB_geometry_shader4;
+
+#define GL_CLAMP_TO_EDGE_SGIS 0x812F
+
+#define GL_CLAMP_TO_EDGE_EXT 0x812F
+
+#define GL_BLEND_EQUATION_EXT 0x8009
+#define GL_FUNC_ADD_EXT 0x8006
+#define GL_MAX_EXT 0x8008
+#define GL_MIN_EXT 0x8007
+
+#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B
+#define GL_FUNC_SUBTRACT_EXT 0x800A
+
+#define GL_ACTIVE_TEXTURE_ARB 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
+#define GL_TEXTURE0_ARB 0x84C0
+#define GL_TEXTURE10_ARB 0x84CA
+#define GL_TEXTURE11_ARB 0x84CB
+#define GL_TEXTURE12_ARB 0x84CC
+#define GL_TEXTURE13_ARB 0x84CD
+#define GL_TEXTURE14_ARB 0x84CE
+#define GL_TEXTURE15_ARB 0x84CF
+#define GL_TEXTURE16_ARB 0x84D0
+#define GL_TEXTURE17_ARB 0x84D1
+#define GL_TEXTURE18_ARB 0x84D2
+#define GL_TEXTURE19_ARB 0x84D3
+#define GL_TEXTURE1_ARB 0x84C1
+#define GL_TEXTURE20_ARB 0x84D4
+#define GL_TEXTURE21_ARB 0x84D5
+#define GL_TEXTURE22_ARB 0x84D6
+#define GL_TEXTURE23_ARB 0x84D7
+#define GL_TEXTURE24_ARB 0x84D8
+#define GL_TEXTURE25_ARB 0x84D9
+#define GL_TEXTURE26_ARB 0x84DA
+#define GL_TEXTURE27_ARB 0x84DB
+#define GL_TEXTURE28_ARB 0x84DC
+#define GL_TEXTURE29_ARB 0x84DD
+#define GL_TEXTURE2_ARB 0x84C2
+#define GL_TEXTURE30_ARB 0x84DE
+#define GL_TEXTURE31_ARB 0x84DF
+#define GL_TEXTURE3_ARB 0x84C3
+#define GL_TEXTURE4_ARB 0x84C4
+#define GL_TEXTURE5_ARB 0x84C5
+#define GL_TEXTURE6_ARB 0x84C6
+#define GL_TEXTURE7_ARB 0x84C7
+#define GL_TEXTURE8_ARB 0x84C8
+#define GL_TEXTURE9_ARB 0x84C9
+
+#define GL_BLEND_DST_ALPHA_EXT 0x80CA
+#define GL_BLEND_DST_RGB_EXT 0x80C8
+#define GL_BLEND_SRC_ALPHA_EXT 0x80CB
+#define GL_BLEND_SRC_RGB_EXT 0x80C9
+
+#define GL_ARRAY_BUFFER_ARB 0x8892
+#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
+#define GL_BUFFER_ACCESS_ARB 0x88BB
+#define GL_BUFFER_MAPPED_ARB 0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
+#define GL_BUFFER_SIZE_ARB 0x8764
+#define GL_BUFFER_USAGE_ARB 0x8765
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_DYNAMIC_COPY_ARB 0x88EA
+#define GL_DYNAMIC_DRAW_ARB 0x88E8
+#define GL_DYNAMIC_READ_ARB 0x88E9
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_READ_ONLY_ARB 0x88B8
+#define GL_READ_WRITE_ARB 0x88BA
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_STATIC_COPY_ARB 0x88E6
+#define GL_STATIC_DRAW_ARB 0x88E4
+#define GL_STATIC_READ_ARB 0x88E5
+#define GL_STREAM_COPY_ARB 0x88E2
+#define GL_STREAM_DRAW_ARB 0x88E0
+#define GL_STREAM_READ_ARB 0x88E1
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_WRITE_ONLY_ARB 0x88B9
+
+#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
+
+#define GL_BOOL_ARB 0x8B56
+#define GL_BOOL_VEC2_ARB 0x8B57
+#define GL_BOOL_VEC3_ARB 0x8B58
+#define GL_BOOL_VEC4_ARB 0x8B59
+#define GL_FLOAT_MAT2_ARB 0x8B5A
+#define GL_FLOAT_MAT3_ARB 0x8B5B
+#define GL_FLOAT_MAT4_ARB 0x8B5C
+#define GL_FLOAT_VEC2_ARB 0x8B50
+#define GL_FLOAT_VEC3_ARB 0x8B51
+#define GL_FLOAT_VEC4_ARB 0x8B52
+#define GL_INT_VEC2_ARB 0x8B53
+#define GL_INT_VEC3_ARB 0x8B54
+#define GL_INT_VEC4_ARB 0x8B55
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85
+#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#define GL_OBJECT_SUBTYPE_ARB 0x8B4F
+#define GL_OBJECT_TYPE_ARB 0x8B4E
+#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83
+#define GL_PROGRAM_OBJECT_ARB 0x8B40
+#define GL_SAMPLER_1D_ARB 0x8B5D
+#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61
+#define GL_SAMPLER_2D_ARB 0x8B5E
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64
+#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62
+#define GL_SAMPLER_3D_ARB 0x8B5F
+#define GL_SAMPLER_CUBE_ARB 0x8B60
+#define GL_SHADER_OBJECT_ARB 0x8B48
+
+#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626
+#define GL_FLOAT 0x1406
+// Copied GL_FLOAT_MAT2_ARB From: ARB_shader_objects
+// Copied GL_FLOAT_MAT3_ARB From: ARB_shader_objects
+// Copied GL_FLOAT_MAT4_ARB From: ARB_shader_objects
+// Copied GL_FLOAT_VEC2_ARB From: ARB_shader_objects
+// Copied GL_FLOAT_VEC3_ARB From: ARB_shader_objects
+// Copied GL_FLOAT_VEC4_ARB From: ARB_shader_objects
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
+#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
+#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643
+#define GL_VERTEX_SHADER_ARB 0x8B31
+
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+
+#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D
+#define GL_BLEND_EQUATION_RGB_EXT 0x8009
+
+#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
+#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
+#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#define GL_COMPRESSED_SRGB_EXT 0x8C48
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
+#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45
+#define GL_SLUMINANCE8_EXT 0x8C47
+#define GL_SLUMINANCE_ALPHA_EXT 0x8C44
+#define GL_SLUMINANCE_EXT 0x8C46
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_SRGB8_EXT 0x8C41
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB_EXT 0x8C40
+
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
+#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
+#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
+#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
+#define GL_STENCIL_INDEX16_EXT 0x8D49
+#define GL_STENCIL_INDEX1_EXT 0x8D46
+#define GL_STENCIL_INDEX4_EXT 0x8D47
+#define GL_STENCIL_INDEX8_EXT 0x8D48
+
+#define GL_DEPTH24_STENCIL8_EXT 0x88F0
+#define GL_DEPTH_STENCIL_EXT 0x84F9
+#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
+#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
+
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
+#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
+
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8
+#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC
+#define GL_GEOMETRY_SHADER_ARB 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA
+#define GL_LINES_ADJACENCY_ARB 0x000A
+#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE
+#define GL_PROGRAM_POINT_SIZE_ARB 0x8642
+#define GL_TRIANGLES_ADJACENCY_ARB 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D
+
+#define GL_2D 0x0600
+#define GL_2_BYTES 0x1407
+#define GL_3D 0x0601
+#define GL_3D_COLOR 0x0602
+#define GL_3D_COLOR_TEXTURE 0x0603
+#define GL_3_BYTES 0x1408
+#define GL_4D_COLOR_TEXTURE 0x0604
+#define GL_4_BYTES 0x1409
+#define GL_ACCUM 0x0100
+#define GL_ACCUM_ALPHA_BITS 0x0D5B
+#define GL_ACCUM_BLUE_BITS 0x0D5A
+#define GL_ACCUM_BUFFER_BIT 0x00000200
+#define GL_ACCUM_CLEAR_VALUE 0x0B80
+#define GL_ACCUM_GREEN_BITS 0x0D59
+#define GL_ACCUM_RED_BITS 0x0D58
+#define GL_ADD 0x0104
+#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF
+#define GL_ALPHA 0x1906
+#define GL_ALPHA12 0x803D
+#define GL_ALPHA16 0x803E
+#define GL_ALPHA4 0x803B
+#define GL_ALPHA8 0x803C
+#define GL_ALPHA_BIAS 0x0D1D
+#define GL_ALPHA_BITS 0x0D55
+#define GL_ALPHA_SCALE 0x0D1C
+#define GL_ALPHA_TEST 0x0BC0
+#define GL_ALPHA_TEST_FUNC 0x0BC1
+#define GL_ALPHA_TEST_REF 0x0BC2
+#define GL_ALWAYS 0x0207
+#define GL_AMBIENT 0x1200
+#define GL_AMBIENT_AND_DIFFUSE 0x1602
+#define GL_AND 0x1501
+#define GL_AND_INVERTED 0x1504
+#define GL_AND_REVERSE 0x1502
+#define GL_ATTRIB_STACK_DEPTH 0x0BB0
+#define GL_AUTO_NORMAL 0x0D80
+#define GL_AUX0 0x0409
+#define GL_AUX1 0x040A
+#define GL_AUX2 0x040B
+#define GL_AUX3 0x040C
+#define GL_AUX_BUFFERS 0x0C00
+#define GL_BACK 0x0405
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_BITMAP 0x1A00
+#define GL_BITMAP_TOKEN 0x0704
+#define GL_BLEND 0x0BE2
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLUE 0x1905
+#define GL_BLUE_BIAS 0x0D1B
+#define GL_BLUE_BITS 0x0D54
+#define GL_BLUE_SCALE 0x0D1A
+#define GL_BYTE 0x1400
+#define GL_C3F_V3F 0x2A24
+#define GL_C4F_N3F_V3F 0x2A26
+#define GL_C4UB_V2F 0x2A22
+#define GL_C4UB_V3F 0x2A23
+#define GL_CCW 0x0901
+#define GL_CLAMP 0x2900
+#define GL_CLEAR 0x1500
+#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF
+#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
+#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001
+#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+#define GL_COEFF 0x0A00
+#define GL_COLOR 0x1800
+#define GL_COLOR_ARRAY 0x8076
+#define GL_COLOR_ARRAY_POINTER 0x8090
+#define GL_COLOR_ARRAY_SIZE 0x8081
+#define GL_COLOR_ARRAY_STRIDE 0x8083
+#define GL_COLOR_ARRAY_TYPE 0x8082
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_INDEX 0x1900
+#define GL_COLOR_INDEXES 0x1603
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_COLOR_MATERIAL 0x0B57
+#define GL_COLOR_MATERIAL_FACE 0x0B55
+#define GL_COLOR_MATERIAL_PARAMETER 0x0B56
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_COMPILE 0x1300
+#define GL_COMPILE_AND_EXECUTE 0x1301
+#define GL_CONSTANT_ATTENUATION 0x1207
+#define GL_COPY 0x1503
+#define GL_COPY_INVERTED 0x150C
+#define GL_COPY_PIXEL_TOKEN 0x0706
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_CURRENT_BIT 0x00000001
+#define GL_CURRENT_COLOR 0x0B00
+#define GL_CURRENT_INDEX 0x0B01
+#define GL_CURRENT_NORMAL 0x0B02
+#define GL_CURRENT_RASTER_COLOR 0x0B04
+#define GL_CURRENT_RASTER_DISTANCE 0x0B09
+#define GL_CURRENT_RASTER_INDEX 0x0B05
+#define GL_CURRENT_RASTER_POSITION 0x0B07
+#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08
+#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06
+#define GL_CURRENT_TEXTURE_COORDS 0x0B03
+#define GL_CW 0x0900
+#define GL_DECAL 0x2101
+#define GL_DECR 0x1E03
+#define GL_DEPTH 0x1801
+#define GL_DEPTH_BIAS 0x0D1F
+#define GL_DEPTH_BITS 0x0D56
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_SCALE 0x0D1E
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DIFFUSE 0x1201
+#define GL_DITHER 0x0BD0
+#define GL_DOMAIN 0x0A02
+#define GL_DONT_CARE 0x1100
+#define GL_DOUBLE 0x140A
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_DRAW_PIXEL_TOKEN 0x0705
+#define GL_DST_ALPHA 0x0304
+#define GL_DST_COLOR 0x0306
+#define GL_EDGE_FLAG 0x0B43
+#define GL_EDGE_FLAG_ARRAY 0x8079
+#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093
+#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C
+#define GL_EMISSION 0x1600
+#define GL_ENABLE_BIT 0x00002000
+#define GL_EQUAL 0x0202
+#define GL_EQUIV 0x1509
+#define GL_EVAL_BIT 0x00010000
+#define GL_EXP 0x0800
+#define GL_EXP2 0x0801
+#define GL_EXTENSIONS 0x1F03
+#define GL_EYE_LINEAR 0x2400
+#define GL_EYE_PLANE 0x2502
+#define GL_FALSE 0
+#define GL_FASTEST 0x1101
+#define GL_FEEDBACK 0x1C01
+#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0
+#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1
+#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2
+#define GL_FILL 0x1B02
+#define GL_FLAT 0x1D00
+// Copied GL_FLOAT From: ARB_vertex_shader
+#define GL_FOG 0x0B60
+#define GL_FOG_BIT 0x00000080
+#define GL_FOG_COLOR 0x0B66
+#define GL_FOG_DENSITY 0x0B62
+#define GL_FOG_END 0x0B64
+#define GL_FOG_HINT 0x0C54
+#define GL_FOG_INDEX 0x0B61
+#define GL_FOG_MODE 0x0B65
+#define GL_FOG_START 0x0B63
+#define GL_FRONT 0x0404
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_FRONT_FACE 0x0B46
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_GEQUAL 0x0206
+#define GL_GREATER 0x0204
+#define GL_GREEN 0x1904
+#define GL_GREEN_BIAS 0x0D19
+#define GL_GREEN_BITS 0x0D53
+#define GL_GREEN_SCALE 0x0D18
+#define GL_HINT_BIT 0x00008000
+#define GL_INCR 0x1E02
+#define GL_INDEX_ARRAY 0x8077
+#define GL_INDEX_ARRAY_POINTER 0x8091
+#define GL_INDEX_ARRAY_STRIDE 0x8086
+#define GL_INDEX_ARRAY_TYPE 0x8085
+#define GL_INDEX_BITS 0x0D51
+#define GL_INDEX_CLEAR_VALUE 0x0C20
+#define GL_INDEX_LOGIC_OP 0x0BF1
+#define GL_INDEX_MODE 0x0C30
+#define GL_INDEX_OFFSET 0x0D13
+#define GL_INDEX_SHIFT 0x0D12
+#define GL_INDEX_WRITEMASK 0x0C21
+#define GL_INT 0x1404
+#define GL_INTENSITY 0x8049
+#define GL_INTENSITY12 0x804C
+#define GL_INTENSITY16 0x804D
+#define GL_INTENSITY4 0x804A
+#define GL_INTENSITY8 0x804B
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_OPERATION 0x0502
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVERT 0x150A
+#define GL_KEEP 0x1E00
+#define GL_LEFT 0x0406
+#define GL_LEQUAL 0x0203
+#define GL_LESS 0x0201
+#define GL_LIGHT0 0x4000
+#define GL_LIGHT1 0x4001
+#define GL_LIGHT2 0x4002
+#define GL_LIGHT3 0x4003
+#define GL_LIGHT4 0x4004
+#define GL_LIGHT5 0x4005
+#define GL_LIGHT6 0x4006
+#define GL_LIGHT7 0x4007
+#define GL_LIGHTING 0x0B50
+#define GL_LIGHTING_BIT 0x00000040
+#define GL_LIGHT_MODEL_AMBIENT 0x0B53
+#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51
+#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
+#define GL_LINE 0x1B01
+#define GL_LINEAR 0x2601
+#define GL_LINEAR_ATTENUATION 0x1208
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_LINES 0x0001
+#define GL_LINE_BIT 0x00000004
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_RESET_TOKEN 0x0707
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_LINE_STIPPLE 0x0B24
+#define GL_LINE_STIPPLE_PATTERN 0x0B25
+#define GL_LINE_STIPPLE_REPEAT 0x0B26
+#define GL_LINE_STRIP 0x0003
+#define GL_LINE_TOKEN 0x0702
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_LINE_WIDTH_RANGE 0x0B22
+#define GL_LIST_BASE 0x0B32
+#define GL_LIST_BIT 0x00020000
+#define GL_LIST_INDEX 0x0B33
+#define GL_LIST_MODE 0x0B30
+#define GL_LOAD 0x0101
+#define GL_LOGIC_OP 0x0BF1
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE12 0x8041
+#define GL_LUMINANCE12_ALPHA12 0x8047
+#define GL_LUMINANCE12_ALPHA4 0x8046
+#define GL_LUMINANCE16 0x8042
+#define GL_LUMINANCE16_ALPHA16 0x8048
+#define GL_LUMINANCE4 0x803F
+#define GL_LUMINANCE4_ALPHA4 0x8043
+#define GL_LUMINANCE6_ALPHA2 0x8044
+#define GL_LUMINANCE8 0x8040
+#define GL_LUMINANCE8_ALPHA8 0x8045
+#define GL_LUMINANCE_ALPHA 0x190A
+#define GL_MAP1_COLOR_4 0x0D90
+#define GL_MAP1_GRID_DOMAIN 0x0DD0
+#define GL_MAP1_GRID_SEGMENTS 0x0DD1
+#define GL_MAP1_INDEX 0x0D91
+#define GL_MAP1_NORMAL 0x0D92
+#define GL_MAP1_TEXTURE_COORD_1 0x0D93
+#define GL_MAP1_TEXTURE_COORD_2 0x0D94
+#define GL_MAP1_TEXTURE_COORD_3 0x0D95
+#define GL_MAP1_TEXTURE_COORD_4 0x0D96
+#define GL_MAP1_VERTEX_3 0x0D97
+#define GL_MAP1_VERTEX_4 0x0D98
+#define GL_MAP2_COLOR_4 0x0DB0
+#define GL_MAP2_GRID_DOMAIN 0x0DD2
+#define GL_MAP2_GRID_SEGMENTS 0x0DD3
+#define GL_MAP2_INDEX 0x0DB1
+#define GL_MAP2_NORMAL 0x0DB2
+#define GL_MAP2_TEXTURE_COORD_1 0x0DB3
+#define GL_MAP2_TEXTURE_COORD_2 0x0DB4
+#define GL_MAP2_TEXTURE_COORD_3 0x0DB5
+#define GL_MAP2_TEXTURE_COORD_4 0x0DB6
+#define GL_MAP2_VERTEX_3 0x0DB7
+#define GL_MAP2_VERTEX_4 0x0DB8
+#define GL_MAP_COLOR 0x0D10
+#define GL_MAP_STENCIL 0x0D11
+#define GL_MATRIX_MODE 0x0BA0
+#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35
+#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B
+#define GL_MAX_CLIP_PLANES 0x0D32
+#define GL_MAX_EVAL_ORDER 0x0D30
+#define GL_MAX_LIGHTS 0x0D31
+#define GL_MAX_LIST_NESTING 0x0B31
+#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
+#define GL_MAX_NAME_STACK_DEPTH 0x0D37
+#define GL_MAX_PIXEL_MAP_TABLE 0x0D34
+#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MODELVIEW 0x1700
+#define GL_MODELVIEW_MATRIX 0x0BA6
+#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
+#define GL_MODULATE 0x2100
+#define GL_MULT 0x0103
+#define GL_N3F_V3F 0x2A25
+#define GL_NAME_STACK_DEPTH 0x0D70
+#define GL_NAND 0x150E
+#define GL_NEAREST 0x2600
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_NEVER 0x0200
+#define GL_NICEST 0x1102
+#define GL_NONE 0
+#define GL_NOOP 0x1505
+#define GL_NOR 0x1508
+#define GL_NORMALIZE 0x0BA1
+#define GL_NORMAL_ARRAY 0x8075
+#define GL_NORMAL_ARRAY_POINTER 0x808F
+#define GL_NORMAL_ARRAY_STRIDE 0x807F
+#define GL_NORMAL_ARRAY_TYPE 0x807E
+#define GL_NOTEQUAL 0x0205
+#define GL_NO_ERROR 0
+#define GL_OBJECT_LINEAR 0x2401
+#define GL_OBJECT_PLANE 0x2501
+#define GL_ONE 1
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_OR 0x1507
+#define GL_ORDER 0x0A01
+#define GL_OR_INVERTED 0x150D
+#define GL_OR_REVERSE 0x150B
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_PASS_THROUGH_TOKEN 0x0700
+#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
+#define GL_PIXEL_MAP_A_TO_A 0x0C79
+#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9
+#define GL_PIXEL_MAP_B_TO_B 0x0C78
+#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8
+#define GL_PIXEL_MAP_G_TO_G 0x0C77
+#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7
+#define GL_PIXEL_MAP_I_TO_A 0x0C75
+#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5
+#define GL_PIXEL_MAP_I_TO_B 0x0C74
+#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4
+#define GL_PIXEL_MAP_I_TO_G 0x0C73
+#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3
+#define GL_PIXEL_MAP_I_TO_I 0x0C70
+#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0
+#define GL_PIXEL_MAP_I_TO_R 0x0C72
+#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2
+#define GL_PIXEL_MAP_R_TO_R 0x0C76
+#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6
+#define GL_PIXEL_MAP_S_TO_S 0x0C71
+#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1
+#define GL_PIXEL_MODE_BIT 0x00000020
+#define GL_POINT 0x1B00
+#define GL_POINTS 0x0000
+#define GL_POINT_BIT 0x00000002
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_POINT_SIZE_RANGE 0x0B12
+#define GL_POINT_SMOOTH 0x0B10
+#define GL_POINT_SMOOTH_HINT 0x0C51
+#define GL_POINT_TOKEN 0x0701
+#define GL_POLYGON 0x0009
+#define GL_POLYGON_BIT 0x00000008
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_POLYGON_STIPPLE 0x0B42
+#define GL_POLYGON_STIPPLE_BIT 0x00000010
+#define GL_POLYGON_TOKEN 0x0703
+#define GL_POSITION 0x1203
+#define GL_PROJECTION 0x1701
+#define GL_PROJECTION_MATRIX 0x0BA7
+#define GL_PROJECTION_STACK_DEPTH 0x0BA4
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_Q 0x2003
+#define GL_QUADRATIC_ATTENUATION 0x1209
+#define GL_QUADS 0x0007
+#define GL_QUAD_STRIP 0x0008
+#define GL_R 0x2002
+#define GL_R3_G3_B2 0x2A10
+#define GL_READ_BUFFER 0x0C02
+#define GL_RED 0x1903
+#define GL_RED_BIAS 0x0D15
+#define GL_RED_BITS 0x0D52
+#define GL_RED_SCALE 0x0D14
+#define GL_RENDER 0x1C00
+#define GL_RENDERER 0x1F01
+#define GL_RENDER_MODE 0x0C40
+#define GL_REPEAT 0x2901
+#define GL_REPLACE 0x1E01
+#define GL_RETURN 0x0102
+#define GL_RGB 0x1907
+#define GL_RGB10 0x8052
+#define GL_RGB10_A2 0x8059
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB5_A1 0x8057
+#define GL_RGB8 0x8051
+#define GL_RGBA 0x1908
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_RGBA2 0x8055
+#define GL_RGBA4 0x8056
+#define GL_RGBA8 0x8058
+#define GL_RGBA_MODE 0x0C31
+#define GL_RIGHT 0x0407
+#define GL_S 0x2000
+#define GL_SCISSOR_BIT 0x00080000
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_SELECT 0x1C02
+#define GL_SELECTION_BUFFER_POINTER 0x0DF3
+#define GL_SELECTION_BUFFER_SIZE 0x0DF4
+#define GL_SET 0x150F
+#define GL_SHADE_MODEL 0x0B54
+#define GL_SHININESS 0x1601
+#define GL_SHORT 0x1402
+#define GL_SMOOTH 0x1D01
+#define GL_SPECULAR 0x1202
+#define GL_SPHERE_MAP 0x2402
+#define GL_SPOT_CUTOFF 0x1206
+#define GL_SPOT_DIRECTION 0x1204
+#define GL_SPOT_EXPONENT 0x1205
+#define GL_SRC_ALPHA 0x0302
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_SRC_COLOR 0x0300
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_STENCIL 0x1802
+#define GL_STENCIL_BITS 0x0D57
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STEREO 0x0C33
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_T 0x2001
+#define GL_T2F_C3F_V3F 0x2A2A
+#define GL_T2F_C4F_N3F_V3F 0x2A2C
+#define GL_T2F_C4UB_V3F 0x2A29
+#define GL_T2F_N3F_V3F 0x2A2B
+#define GL_T2F_V3F 0x2A27
+#define GL_T4F_C4F_N3F_V4F 0x2A2D
+#define GL_T4F_V4F 0x2A28
+#define GL_TEXTURE 0x1702
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_BIT 0x00040000
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_BORDER 0x1005
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_TEXTURE_COMPONENTS 0x1003
+#define GL_TEXTURE_COORD_ARRAY 0x8078
+#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
+#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
+#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
+#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
+#define GL_TEXTURE_ENV 0x2300
+#define GL_TEXTURE_ENV_COLOR 0x2201
+#define GL_TEXTURE_ENV_MODE 0x2200
+#define GL_TEXTURE_GEN_MODE 0x2500
+#define GL_TEXTURE_GEN_Q 0x0C63
+#define GL_TEXTURE_GEN_R 0x0C62
+#define GL_TEXTURE_GEN_S 0x0C60
+#define GL_TEXTURE_GEN_T 0x0C61
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_INTENSITY_SIZE 0x8061
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_TEXTURE_LUMINANCE_SIZE 0x8060
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MATRIX 0x0BA8
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_PRIORITY 0x8066
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_RESIDENT 0x8067
+#define GL_TEXTURE_STACK_DEPTH 0x0BA5
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TRANSFORM_BIT 0x00001000
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRUE 1
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_V2F 0x2A20
+#define GL_V3F 0x2A21
+#define GL_VENDOR 0x1F00
+#define GL_VERSION 0x1F02
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_VERTEX_ARRAY_POINTER 0x808E
+#define GL_VERTEX_ARRAY_SIZE 0x807A
+#define GL_VERTEX_ARRAY_STRIDE 0x807C
+#define GL_VERTEX_ARRAY_TYPE 0x807B
+#define GL_VIEWPORT 0x0BA2
+#define GL_VIEWPORT_BIT 0x00000800
+#define GL_XOR 0x1506
+#define GL_ZERO 0
+#define GL_ZOOM_X 0x0D16
+#define GL_ZOOM_Y 0x0D17
+
+
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+extern void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum);
+#define glBlendEquationEXT sf_ptrc_glBlendEquationEXT
+#endif // GL_EXT_blend_minmax
+
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+extern void (GL_FUNCPTR *sf_ptrc_glActiveTextureARB)(GLenum);
+#define glActiveTextureARB sf_ptrc_glActiveTextureARB
+extern void (GL_FUNCPTR *sf_ptrc_glClientActiveTextureARB)(GLenum);
+#define glClientActiveTextureARB sf_ptrc_glClientActiveTextureARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1dARB)(GLenum, GLdouble);
+#define glMultiTexCoord1dARB sf_ptrc_glMultiTexCoord1dARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1dvARB)(GLenum, const GLdouble*);
+#define glMultiTexCoord1dvARB sf_ptrc_glMultiTexCoord1dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1fARB)(GLenum, GLfloat);
+#define glMultiTexCoord1fARB sf_ptrc_glMultiTexCoord1fARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1fvARB)(GLenum, const GLfloat*);
+#define glMultiTexCoord1fvARB sf_ptrc_glMultiTexCoord1fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1iARB)(GLenum, GLint);
+#define glMultiTexCoord1iARB sf_ptrc_glMultiTexCoord1iARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1ivARB)(GLenum, const GLint*);
+#define glMultiTexCoord1ivARB sf_ptrc_glMultiTexCoord1ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1sARB)(GLenum, GLshort);
+#define glMultiTexCoord1sARB sf_ptrc_glMultiTexCoord1sARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord1svARB)(GLenum, const GLshort*);
+#define glMultiTexCoord1svARB sf_ptrc_glMultiTexCoord1svARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2dARB)(GLenum, GLdouble, GLdouble);
+#define glMultiTexCoord2dARB sf_ptrc_glMultiTexCoord2dARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2dvARB)(GLenum, const GLdouble*);
+#define glMultiTexCoord2dvARB sf_ptrc_glMultiTexCoord2dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2fARB)(GLenum, GLfloat, GLfloat);
+#define glMultiTexCoord2fARB sf_ptrc_glMultiTexCoord2fARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2fvARB)(GLenum, const GLfloat*);
+#define glMultiTexCoord2fvARB sf_ptrc_glMultiTexCoord2fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2iARB)(GLenum, GLint, GLint);
+#define glMultiTexCoord2iARB sf_ptrc_glMultiTexCoord2iARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2ivARB)(GLenum, const GLint*);
+#define glMultiTexCoord2ivARB sf_ptrc_glMultiTexCoord2ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2sARB)(GLenum, GLshort, GLshort);
+#define glMultiTexCoord2sARB sf_ptrc_glMultiTexCoord2sARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord2svARB)(GLenum, const GLshort*);
+#define glMultiTexCoord2svARB sf_ptrc_glMultiTexCoord2svARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3dARB)(GLenum, GLdouble, GLdouble, GLdouble);
+#define glMultiTexCoord3dARB sf_ptrc_glMultiTexCoord3dARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3dvARB)(GLenum, const GLdouble*);
+#define glMultiTexCoord3dvARB sf_ptrc_glMultiTexCoord3dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3fARB)(GLenum, GLfloat, GLfloat, GLfloat);
+#define glMultiTexCoord3fARB sf_ptrc_glMultiTexCoord3fARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3fvARB)(GLenum, const GLfloat*);
+#define glMultiTexCoord3fvARB sf_ptrc_glMultiTexCoord3fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3iARB)(GLenum, GLint, GLint, GLint);
+#define glMultiTexCoord3iARB sf_ptrc_glMultiTexCoord3iARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3ivARB)(GLenum, const GLint*);
+#define glMultiTexCoord3ivARB sf_ptrc_glMultiTexCoord3ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3sARB)(GLenum, GLshort, GLshort, GLshort);
+#define glMultiTexCoord3sARB sf_ptrc_glMultiTexCoord3sARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord3svARB)(GLenum, const GLshort*);
+#define glMultiTexCoord3svARB sf_ptrc_glMultiTexCoord3svARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4dARB)(GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+#define glMultiTexCoord4dARB sf_ptrc_glMultiTexCoord4dARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4dvARB)(GLenum, const GLdouble*);
+#define glMultiTexCoord4dvARB sf_ptrc_glMultiTexCoord4dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4fARB)(GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+#define glMultiTexCoord4fARB sf_ptrc_glMultiTexCoord4fARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4fvARB)(GLenum, const GLfloat*);
+#define glMultiTexCoord4fvARB sf_ptrc_glMultiTexCoord4fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4iARB)(GLenum, GLint, GLint, GLint, GLint);
+#define glMultiTexCoord4iARB sf_ptrc_glMultiTexCoord4iARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4ivARB)(GLenum, const GLint*);
+#define glMultiTexCoord4ivARB sf_ptrc_glMultiTexCoord4ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4sARB)(GLenum, GLshort, GLshort, GLshort, GLshort);
+#define glMultiTexCoord4sARB sf_ptrc_glMultiTexCoord4sARB
+extern void (GL_FUNCPTR *sf_ptrc_glMultiTexCoord4svARB)(GLenum, const GLshort*);
+#define glMultiTexCoord4svARB sf_ptrc_glMultiTexCoord4svARB
+#endif // GL_ARB_multitexture
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+extern void (GL_FUNCPTR *sf_ptrc_glBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum);
+#define glBlendFuncSeparateEXT sf_ptrc_glBlendFuncSeparateEXT
+#endif // GL_EXT_blend_func_separate
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+extern void (GL_FUNCPTR *sf_ptrc_glBindBufferARB)(GLenum, GLuint);
+#define glBindBufferARB sf_ptrc_glBindBufferARB
+extern void (GL_FUNCPTR *sf_ptrc_glBufferDataARB)(GLenum, GLsizeiptrARB, const void*, GLenum);
+#define glBufferDataARB sf_ptrc_glBufferDataARB
+extern void (GL_FUNCPTR *sf_ptrc_glBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, const void*);
+#define glBufferSubDataARB sf_ptrc_glBufferSubDataARB
+extern void (GL_FUNCPTR *sf_ptrc_glDeleteBuffersARB)(GLsizei, const GLuint*);
+#define glDeleteBuffersARB sf_ptrc_glDeleteBuffersARB
+extern void (GL_FUNCPTR *sf_ptrc_glGenBuffersARB)(GLsizei, GLuint*);
+#define glGenBuffersARB sf_ptrc_glGenBuffersARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetBufferParameterivARB)(GLenum, GLenum, GLint*);
+#define glGetBufferParameterivARB sf_ptrc_glGetBufferParameterivARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetBufferPointervARB)(GLenum, GLenum, void**);
+#define glGetBufferPointervARB sf_ptrc_glGetBufferPointervARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, void*);
+#define glGetBufferSubDataARB sf_ptrc_glGetBufferSubDataARB
+extern GLboolean (GL_FUNCPTR *sf_ptrc_glIsBufferARB)(GLuint);
+#define glIsBufferARB sf_ptrc_glIsBufferARB
+extern void* (GL_FUNCPTR *sf_ptrc_glMapBufferARB)(GLenum, GLenum);
+#define glMapBufferARB sf_ptrc_glMapBufferARB
+extern GLboolean (GL_FUNCPTR *sf_ptrc_glUnmapBufferARB)(GLenum);
+#define glUnmapBufferARB sf_ptrc_glUnmapBufferARB
+#endif // GL_ARB_vertex_buffer_object
+
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+extern void (GL_FUNCPTR *sf_ptrc_glAttachObjectARB)(GLhandleARB, GLhandleARB);
+#define glAttachObjectARB sf_ptrc_glAttachObjectARB
+extern void (GL_FUNCPTR *sf_ptrc_glCompileShaderARB)(GLhandleARB);
+#define glCompileShaderARB sf_ptrc_glCompileShaderARB
+extern GLhandleARB (GL_FUNCPTR *sf_ptrc_glCreateProgramObjectARB)();
+#define glCreateProgramObjectARB sf_ptrc_glCreateProgramObjectARB
+extern GLhandleARB (GL_FUNCPTR *sf_ptrc_glCreateShaderObjectARB)(GLenum);
+#define glCreateShaderObjectARB sf_ptrc_glCreateShaderObjectARB
+extern void (GL_FUNCPTR *sf_ptrc_glDeleteObjectARB)(GLhandleARB);
+#define glDeleteObjectARB sf_ptrc_glDeleteObjectARB
+extern void (GL_FUNCPTR *sf_ptrc_glDetachObjectARB)(GLhandleARB, GLhandleARB);
+#define glDetachObjectARB sf_ptrc_glDetachObjectARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetActiveUniformARB)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*);
+#define glGetActiveUniformARB sf_ptrc_glGetActiveUniformARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetAttachedObjectsARB)(GLhandleARB, GLsizei, GLsizei*, GLhandleARB*);
+#define glGetAttachedObjectsARB sf_ptrc_glGetAttachedObjectsARB
+extern GLhandleARB (GL_FUNCPTR *sf_ptrc_glGetHandleARB)(GLenum);
+#define glGetHandleARB sf_ptrc_glGetHandleARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetInfoLogARB)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*);
+#define glGetInfoLogARB sf_ptrc_glGetInfoLogARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetObjectParameterfvARB)(GLhandleARB, GLenum, GLfloat*);
+#define glGetObjectParameterfvARB sf_ptrc_glGetObjectParameterfvARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetObjectParameterivARB)(GLhandleARB, GLenum, GLint*);
+#define glGetObjectParameterivARB sf_ptrc_glGetObjectParameterivARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetShaderSourceARB)(GLhandleARB, GLsizei, GLsizei*, GLcharARB*);
+#define glGetShaderSourceARB sf_ptrc_glGetShaderSourceARB
+extern GLint (GL_FUNCPTR *sf_ptrc_glGetUniformLocationARB)(GLhandleARB, const GLcharARB*);
+#define glGetUniformLocationARB sf_ptrc_glGetUniformLocationARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetUniformfvARB)(GLhandleARB, GLint, GLfloat*);
+#define glGetUniformfvARB sf_ptrc_glGetUniformfvARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetUniformivARB)(GLhandleARB, GLint, GLint*);
+#define glGetUniformivARB sf_ptrc_glGetUniformivARB
+extern void (GL_FUNCPTR *sf_ptrc_glLinkProgramARB)(GLhandleARB);
+#define glLinkProgramARB sf_ptrc_glLinkProgramARB
+extern void (GL_FUNCPTR *sf_ptrc_glShaderSourceARB)(GLhandleARB, GLsizei, const GLcharARB**, const GLint*);
+#define glShaderSourceARB sf_ptrc_glShaderSourceARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform1fARB)(GLint, GLfloat);
+#define glUniform1fARB sf_ptrc_glUniform1fARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform1fvARB)(GLint, GLsizei, const GLfloat*);
+#define glUniform1fvARB sf_ptrc_glUniform1fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform1iARB)(GLint, GLint);
+#define glUniform1iARB sf_ptrc_glUniform1iARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform1ivARB)(GLint, GLsizei, const GLint*);
+#define glUniform1ivARB sf_ptrc_glUniform1ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform2fARB)(GLint, GLfloat, GLfloat);
+#define glUniform2fARB sf_ptrc_glUniform2fARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform2fvARB)(GLint, GLsizei, const GLfloat*);
+#define glUniform2fvARB sf_ptrc_glUniform2fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform2iARB)(GLint, GLint, GLint);
+#define glUniform2iARB sf_ptrc_glUniform2iARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform2ivARB)(GLint, GLsizei, const GLint*);
+#define glUniform2ivARB sf_ptrc_glUniform2ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform3fARB)(GLint, GLfloat, GLfloat, GLfloat);
+#define glUniform3fARB sf_ptrc_glUniform3fARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform3fvARB)(GLint, GLsizei, const GLfloat*);
+#define glUniform3fvARB sf_ptrc_glUniform3fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform3iARB)(GLint, GLint, GLint, GLint);
+#define glUniform3iARB sf_ptrc_glUniform3iARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform3ivARB)(GLint, GLsizei, const GLint*);
+#define glUniform3ivARB sf_ptrc_glUniform3ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform4fARB)(GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+#define glUniform4fARB sf_ptrc_glUniform4fARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform4fvARB)(GLint, GLsizei, const GLfloat*);
+#define glUniform4fvARB sf_ptrc_glUniform4fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform4iARB)(GLint, GLint, GLint, GLint, GLint);
+#define glUniform4iARB sf_ptrc_glUniform4iARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniform4ivARB)(GLint, GLsizei, const GLint*);
+#define glUniform4ivARB sf_ptrc_glUniform4ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniformMatrix2fvARB)(GLint, GLsizei, GLboolean, const GLfloat*);
+#define glUniformMatrix2fvARB sf_ptrc_glUniformMatrix2fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniformMatrix3fvARB)(GLint, GLsizei, GLboolean, const GLfloat*);
+#define glUniformMatrix3fvARB sf_ptrc_glUniformMatrix3fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUniformMatrix4fvARB)(GLint, GLsizei, GLboolean, const GLfloat*);
+#define glUniformMatrix4fvARB sf_ptrc_glUniformMatrix4fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glUseProgramObjectARB)(GLhandleARB);
+#define glUseProgramObjectARB sf_ptrc_glUseProgramObjectARB
+extern void (GL_FUNCPTR *sf_ptrc_glValidateProgramARB)(GLhandleARB);
+#define glValidateProgramARB sf_ptrc_glValidateProgramARB
+#endif // GL_ARB_shader_objects
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+extern void (GL_FUNCPTR *sf_ptrc_glBindAttribLocationARB)(GLhandleARB, GLuint, const GLcharARB*);
+#define glBindAttribLocationARB sf_ptrc_glBindAttribLocationARB
+extern void (GL_FUNCPTR *sf_ptrc_glDisableVertexAttribArrayARB)(GLuint);
+#define glDisableVertexAttribArrayARB sf_ptrc_glDisableVertexAttribArrayARB
+extern void (GL_FUNCPTR *sf_ptrc_glEnableVertexAttribArrayARB)(GLuint);
+#define glEnableVertexAttribArrayARB sf_ptrc_glEnableVertexAttribArrayARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetActiveAttribARB)(GLhandleARB, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLcharARB*);
+#define glGetActiveAttribARB sf_ptrc_glGetActiveAttribARB
+extern GLint (GL_FUNCPTR *sf_ptrc_glGetAttribLocationARB)(GLhandleARB, const GLcharARB*);
+#define glGetAttribLocationARB sf_ptrc_glGetAttribLocationARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribPointervARB)(GLuint, GLenum, void**);
+#define glGetVertexAttribPointervARB sf_ptrc_glGetVertexAttribPointervARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribdvARB)(GLuint, GLenum, GLdouble*);
+#define glGetVertexAttribdvARB sf_ptrc_glGetVertexAttribdvARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribfvARB)(GLuint, GLenum, GLfloat*);
+#define glGetVertexAttribfvARB sf_ptrc_glGetVertexAttribfvARB
+extern void (GL_FUNCPTR *sf_ptrc_glGetVertexAttribivARB)(GLuint, GLenum, GLint*);
+#define glGetVertexAttribivARB sf_ptrc_glGetVertexAttribivARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1dARB)(GLuint, GLdouble);
+#define glVertexAttrib1dARB sf_ptrc_glVertexAttrib1dARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1dvARB)(GLuint, const GLdouble*);
+#define glVertexAttrib1dvARB sf_ptrc_glVertexAttrib1dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1fARB)(GLuint, GLfloat);
+#define glVertexAttrib1fARB sf_ptrc_glVertexAttrib1fARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1fvARB)(GLuint, const GLfloat*);
+#define glVertexAttrib1fvARB sf_ptrc_glVertexAttrib1fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1sARB)(GLuint, GLshort);
+#define glVertexAttrib1sARB sf_ptrc_glVertexAttrib1sARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib1svARB)(GLuint, const GLshort*);
+#define glVertexAttrib1svARB sf_ptrc_glVertexAttrib1svARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2dARB)(GLuint, GLdouble, GLdouble);
+#define glVertexAttrib2dARB sf_ptrc_glVertexAttrib2dARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2dvARB)(GLuint, const GLdouble*);
+#define glVertexAttrib2dvARB sf_ptrc_glVertexAttrib2dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2fARB)(GLuint, GLfloat, GLfloat);
+#define glVertexAttrib2fARB sf_ptrc_glVertexAttrib2fARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2fvARB)(GLuint, const GLfloat*);
+#define glVertexAttrib2fvARB sf_ptrc_glVertexAttrib2fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2sARB)(GLuint, GLshort, GLshort);
+#define glVertexAttrib2sARB sf_ptrc_glVertexAttrib2sARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib2svARB)(GLuint, const GLshort*);
+#define glVertexAttrib2svARB sf_ptrc_glVertexAttrib2svARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3dARB)(GLuint, GLdouble, GLdouble, GLdouble);
+#define glVertexAttrib3dARB sf_ptrc_glVertexAttrib3dARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3dvARB)(GLuint, const GLdouble*);
+#define glVertexAttrib3dvARB sf_ptrc_glVertexAttrib3dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3fARB)(GLuint, GLfloat, GLfloat, GLfloat);
+#define glVertexAttrib3fARB sf_ptrc_glVertexAttrib3fARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3fvARB)(GLuint, const GLfloat*);
+#define glVertexAttrib3fvARB sf_ptrc_glVertexAttrib3fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3sARB)(GLuint, GLshort, GLshort, GLshort);
+#define glVertexAttrib3sARB sf_ptrc_glVertexAttrib3sARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib3svARB)(GLuint, const GLshort*);
+#define glVertexAttrib3svARB sf_ptrc_glVertexAttrib3svARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NbvARB)(GLuint, const GLbyte*);
+#define glVertexAttrib4NbvARB sf_ptrc_glVertexAttrib4NbvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NivARB)(GLuint, const GLint*);
+#define glVertexAttrib4NivARB sf_ptrc_glVertexAttrib4NivARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NsvARB)(GLuint, const GLshort*);
+#define glVertexAttrib4NsvARB sf_ptrc_glVertexAttrib4NsvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NubARB)(GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+#define glVertexAttrib4NubARB sf_ptrc_glVertexAttrib4NubARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NubvARB)(GLuint, const GLubyte*);
+#define glVertexAttrib4NubvARB sf_ptrc_glVertexAttrib4NubvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NuivARB)(GLuint, const GLuint*);
+#define glVertexAttrib4NuivARB sf_ptrc_glVertexAttrib4NuivARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4NusvARB)(GLuint, const GLushort*);
+#define glVertexAttrib4NusvARB sf_ptrc_glVertexAttrib4NusvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4bvARB)(GLuint, const GLbyte*);
+#define glVertexAttrib4bvARB sf_ptrc_glVertexAttrib4bvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4dARB)(GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+#define glVertexAttrib4dARB sf_ptrc_glVertexAttrib4dARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4dvARB)(GLuint, const GLdouble*);
+#define glVertexAttrib4dvARB sf_ptrc_glVertexAttrib4dvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4fARB)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+#define glVertexAttrib4fARB sf_ptrc_glVertexAttrib4fARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4fvARB)(GLuint, const GLfloat*);
+#define glVertexAttrib4fvARB sf_ptrc_glVertexAttrib4fvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4ivARB)(GLuint, const GLint*);
+#define glVertexAttrib4ivARB sf_ptrc_glVertexAttrib4ivARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4sARB)(GLuint, GLshort, GLshort, GLshort, GLshort);
+#define glVertexAttrib4sARB sf_ptrc_glVertexAttrib4sARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4svARB)(GLuint, const GLshort*);
+#define glVertexAttrib4svARB sf_ptrc_glVertexAttrib4svARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4ubvARB)(GLuint, const GLubyte*);
+#define glVertexAttrib4ubvARB sf_ptrc_glVertexAttrib4ubvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4uivARB)(GLuint, const GLuint*);
+#define glVertexAttrib4uivARB sf_ptrc_glVertexAttrib4uivARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttrib4usvARB)(GLuint, const GLushort*);
+#define glVertexAttrib4usvARB sf_ptrc_glVertexAttrib4usvARB
+extern void (GL_FUNCPTR *sf_ptrc_glVertexAttribPointerARB)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*);
+#define glVertexAttribPointerARB sf_ptrc_glVertexAttribPointerARB
+#endif // GL_ARB_vertex_shader
+
+
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+extern void (GL_FUNCPTR *sf_ptrc_glBlendEquationSeparateEXT)(GLenum, GLenum);
+#define glBlendEquationSeparateEXT sf_ptrc_glBlendEquationSeparateEXT
+#endif // GL_EXT_blend_equation_separate
+
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+extern void (GL_FUNCPTR *sf_ptrc_glBindFramebufferEXT)(GLenum, GLuint);
+#define glBindFramebufferEXT sf_ptrc_glBindFramebufferEXT
+extern void (GL_FUNCPTR *sf_ptrc_glBindRenderbufferEXT)(GLenum, GLuint);
+#define glBindRenderbufferEXT sf_ptrc_glBindRenderbufferEXT
+extern GLenum (GL_FUNCPTR *sf_ptrc_glCheckFramebufferStatusEXT)(GLenum);
+#define glCheckFramebufferStatusEXT sf_ptrc_glCheckFramebufferStatusEXT
+extern void (GL_FUNCPTR *sf_ptrc_glDeleteFramebuffersEXT)(GLsizei, const GLuint*);
+#define glDeleteFramebuffersEXT sf_ptrc_glDeleteFramebuffersEXT
+extern void (GL_FUNCPTR *sf_ptrc_glDeleteRenderbuffersEXT)(GLsizei, const GLuint*);
+#define glDeleteRenderbuffersEXT sf_ptrc_glDeleteRenderbuffersEXT
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferRenderbufferEXT)(GLenum, GLenum, GLenum, GLuint);
+#define glFramebufferRenderbufferEXT sf_ptrc_glFramebufferRenderbufferEXT
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture1DEXT)(GLenum, GLenum, GLenum, GLuint, GLint);
+#define glFramebufferTexture1DEXT sf_ptrc_glFramebufferTexture1DEXT
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture2DEXT)(GLenum, GLenum, GLenum, GLuint, GLint);
+#define glFramebufferTexture2DEXT sf_ptrc_glFramebufferTexture2DEXT
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTexture3DEXT)(GLenum, GLenum, GLenum, GLuint, GLint, GLint);
+#define glFramebufferTexture3DEXT sf_ptrc_glFramebufferTexture3DEXT
+extern void (GL_FUNCPTR *sf_ptrc_glGenFramebuffersEXT)(GLsizei, GLuint*);
+#define glGenFramebuffersEXT sf_ptrc_glGenFramebuffersEXT
+extern void (GL_FUNCPTR *sf_ptrc_glGenRenderbuffersEXT)(GLsizei, GLuint*);
+#define glGenRenderbuffersEXT sf_ptrc_glGenRenderbuffersEXT
+extern void (GL_FUNCPTR *sf_ptrc_glGenerateMipmapEXT)(GLenum);
+#define glGenerateMipmapEXT sf_ptrc_glGenerateMipmapEXT
+extern void (GL_FUNCPTR *sf_ptrc_glGetFramebufferAttachmentParameterivEXT)(GLenum, GLenum, GLenum, GLint*);
+#define glGetFramebufferAttachmentParameterivEXT sf_ptrc_glGetFramebufferAttachmentParameterivEXT
+extern void (GL_FUNCPTR *sf_ptrc_glGetRenderbufferParameterivEXT)(GLenum, GLenum, GLint*);
+#define glGetRenderbufferParameterivEXT sf_ptrc_glGetRenderbufferParameterivEXT
+extern GLboolean (GL_FUNCPTR *sf_ptrc_glIsFramebufferEXT)(GLuint);
+#define glIsFramebufferEXT sf_ptrc_glIsFramebufferEXT
+extern GLboolean (GL_FUNCPTR *sf_ptrc_glIsRenderbufferEXT)(GLuint);
+#define glIsRenderbufferEXT sf_ptrc_glIsRenderbufferEXT
+extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsizei, GLsizei);
+#define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT
+#endif // GL_EXT_framebuffer_object
+
+
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+extern void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum);
+#define glBlitFramebufferEXT sf_ptrc_glBlitFramebufferEXT
+#endif // GL_EXT_framebuffer_blit
+
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageMultisampleEXT)(GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+#define glRenderbufferStorageMultisampleEXT sf_ptrc_glRenderbufferStorageMultisampleEXT
+#endif // GL_EXT_framebuffer_multisample
+
+#ifndef GL_ARB_copy_buffer
+#define GL_ARB_copy_buffer 1
+extern void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr);
+#define glCopyBufferSubData sf_ptrc_glCopyBufferSubData
+#endif // GL_ARB_copy_buffer
+
+#ifndef GL_ARB_geometry_shader4
+#define GL_ARB_geometry_shader4 1
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint);
+#define glFramebufferTextureARB sf_ptrc_glFramebufferTextureARB
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum);
+#define glFramebufferTextureFaceARB sf_ptrc_glFramebufferTextureFaceARB
+extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint);
+#define glFramebufferTextureLayerARB sf_ptrc_glFramebufferTextureLayerARB
+extern void (GL_FUNCPTR *sf_ptrc_glProgramParameteriARB)(GLuint, GLenum, GLint);
+#define glProgramParameteriARB sf_ptrc_glProgramParameteriARB
+#endif // GL_ARB_geometry_shader4
+
+GLAPI void APIENTRY glAccum(GLenum, GLfloat);
+GLAPI void APIENTRY glAlphaFunc(GLenum, GLfloat);
+GLAPI void APIENTRY glBegin(GLenum);
+GLAPI void APIENTRY glBitmap(GLsizei, GLsizei, GLfloat, GLfloat, GLfloat, GLfloat, const GLubyte*);
+GLAPI void APIENTRY glBlendFunc(GLenum, GLenum);
+GLAPI void APIENTRY glCallList(GLuint);
+GLAPI void APIENTRY glCallLists(GLsizei, GLenum, const void*);
+GLAPI void APIENTRY glClear(GLbitfield);
+GLAPI void APIENTRY glClearAccum(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glClearColor(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glClearDepth(GLdouble);
+GLAPI void APIENTRY glClearIndex(GLfloat);
+GLAPI void APIENTRY glClearStencil(GLint);
+GLAPI void APIENTRY glClipPlane(GLenum, const GLdouble*);
+GLAPI void APIENTRY glColor3b(GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glColor3bv(const GLbyte*);
+GLAPI void APIENTRY glColor3d(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glColor3dv(const GLdouble*);
+GLAPI void APIENTRY glColor3f(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor3fv(const GLfloat*);
+GLAPI void APIENTRY glColor3i(GLint, GLint, GLint);
+GLAPI void APIENTRY glColor3iv(const GLint*);
+GLAPI void APIENTRY glColor3s(GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glColor3sv(const GLshort*);
+GLAPI void APIENTRY glColor3ub(GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glColor3ubv(const GLubyte*);
+GLAPI void APIENTRY glColor3ui(GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColor3uiv(const GLuint*);
+GLAPI void APIENTRY glColor3us(GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glColor3usv(const GLushort*);
+GLAPI void APIENTRY glColor4b(GLbyte, GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glColor4bv(const GLbyte*);
+GLAPI void APIENTRY glColor4d(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glColor4dv(const GLdouble*);
+GLAPI void APIENTRY glColor4f(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4fv(const GLfloat*);
+GLAPI void APIENTRY glColor4i(GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glColor4iv(const GLint*);
+GLAPI void APIENTRY glColor4s(GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glColor4sv(const GLshort*);
+GLAPI void APIENTRY glColor4ub(GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glColor4ubv(const GLubyte*);
+GLAPI void APIENTRY glColor4ui(GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColor4uiv(const GLuint*);
+GLAPI void APIENTRY glColor4us(GLushort, GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glColor4usv(const GLushort*);
+GLAPI void APIENTRY glColorMask(GLboolean, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glColorMaterial(GLenum, GLenum);
+GLAPI void APIENTRY glCopyPixels(GLint, GLint, GLsizei, GLsizei, GLenum);
+GLAPI void APIENTRY glCullFace(GLenum);
+GLAPI void APIENTRY glDeleteLists(GLuint, GLsizei);
+GLAPI void APIENTRY glDepthFunc(GLenum);
+GLAPI void APIENTRY glDepthMask(GLboolean);
+GLAPI void APIENTRY glDepthRange(GLdouble, GLdouble);
+GLAPI void APIENTRY glDisable(GLenum);
+GLAPI void APIENTRY glDrawBuffer(GLenum);
+GLAPI void APIENTRY glDrawPixels(GLsizei, GLsizei, GLenum, GLenum, const void*);
+GLAPI void APIENTRY glEdgeFlag(GLboolean);
+GLAPI void APIENTRY glEdgeFlagv(const GLboolean*);
+GLAPI void APIENTRY glEnable(GLenum);
+GLAPI void APIENTRY glEnd();
+GLAPI void APIENTRY glEndList();
+GLAPI void APIENTRY glEvalCoord1d(GLdouble);
+GLAPI void APIENTRY glEvalCoord1dv(const GLdouble*);
+GLAPI void APIENTRY glEvalCoord1f(GLfloat);
+GLAPI void APIENTRY glEvalCoord1fv(const GLfloat*);
+GLAPI void APIENTRY glEvalCoord2d(GLdouble, GLdouble);
+GLAPI void APIENTRY glEvalCoord2dv(const GLdouble*);
+GLAPI void APIENTRY glEvalCoord2f(GLfloat, GLfloat);
+GLAPI void APIENTRY glEvalCoord2fv(const GLfloat*);
+GLAPI void APIENTRY glEvalMesh1(GLenum, GLint, GLint);
+GLAPI void APIENTRY glEvalMesh2(GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glEvalPoint1(GLint);
+GLAPI void APIENTRY glEvalPoint2(GLint, GLint);
+GLAPI void APIENTRY glFeedbackBuffer(GLsizei, GLenum, GLfloat*);
+GLAPI void APIENTRY glFinish();
+GLAPI void APIENTRY glFlush();
+GLAPI void APIENTRY glFogf(GLenum, GLfloat);
+GLAPI void APIENTRY glFogfv(GLenum, const GLfloat*);
+GLAPI void APIENTRY glFogi(GLenum, GLint);
+GLAPI void APIENTRY glFogiv(GLenum, const GLint*);
+GLAPI void APIENTRY glFrontFace(GLenum);
+GLAPI void APIENTRY glFrustum(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI GLuint APIENTRY glGenLists(GLsizei);
+GLAPI void APIENTRY glGetBooleanv(GLenum, GLboolean*);
+GLAPI void APIENTRY glGetClipPlane(GLenum, GLdouble*);
+GLAPI void APIENTRY glGetDoublev(GLenum, GLdouble*);
+GLAPI GLenum APIENTRY glGetError();
+GLAPI void APIENTRY glGetFloatv(GLenum, GLfloat*);
+GLAPI void APIENTRY glGetIntegerv(GLenum, GLint*);
+GLAPI void APIENTRY glGetLightfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetLightiv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glGetMapdv(GLenum, GLenum, GLdouble*);
+GLAPI void APIENTRY glGetMapfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetMapiv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glGetMaterialfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetMaterialiv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glGetPixelMapfv(GLenum, GLfloat*);
+GLAPI void APIENTRY glGetPixelMapuiv(GLenum, GLuint*);
+GLAPI void APIENTRY glGetPixelMapusv(GLenum, GLushort*);
+GLAPI void APIENTRY glGetPolygonStipple(GLubyte*);
+GLAPI const GLubyte* APIENTRY glGetString(GLenum);
+GLAPI void APIENTRY glGetTexEnvfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetTexEnviv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glGetTexGendv(GLenum, GLenum, GLdouble*);
+GLAPI void APIENTRY glGetTexGenfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetTexGeniv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glGetTexImage(GLenum, GLint, GLenum, GLenum, void*);
+GLAPI void APIENTRY glGetTexLevelParameterfv(GLenum, GLint, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetTexLevelParameteriv(GLenum, GLint, GLenum, GLint*);
+GLAPI void APIENTRY glGetTexParameterfv(GLenum, GLenum, GLfloat*);
+GLAPI void APIENTRY glGetTexParameteriv(GLenum, GLenum, GLint*);
+GLAPI void APIENTRY glHint(GLenum, GLenum);
+GLAPI void APIENTRY glIndexMask(GLuint);
+GLAPI void APIENTRY glIndexd(GLdouble);
+GLAPI void APIENTRY glIndexdv(const GLdouble*);
+GLAPI void APIENTRY glIndexf(GLfloat);
+GLAPI void APIENTRY glIndexfv(const GLfloat*);
+GLAPI void APIENTRY glIndexi(GLint);
+GLAPI void APIENTRY glIndexiv(const GLint*);
+GLAPI void APIENTRY glIndexs(GLshort);
+GLAPI void APIENTRY glIndexsv(const GLshort*);
+GLAPI void APIENTRY glInitNames();
+GLAPI GLboolean APIENTRY glIsEnabled(GLenum);
+GLAPI GLboolean APIENTRY glIsList(GLuint);
+GLAPI void APIENTRY glLightModelf(GLenum, GLfloat);
+GLAPI void APIENTRY glLightModelfv(GLenum, const GLfloat*);
+GLAPI void APIENTRY glLightModeli(GLenum, GLint);
+GLAPI void APIENTRY glLightModeliv(GLenum, const GLint*);
+GLAPI void APIENTRY glLightf(GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glLightfv(GLenum, GLenum, const GLfloat*);
+GLAPI void APIENTRY glLighti(GLenum, GLenum, GLint);
+GLAPI void APIENTRY glLightiv(GLenum, GLenum, const GLint*);
+GLAPI void APIENTRY glLineStipple(GLint, GLushort);
+GLAPI void APIENTRY glLineWidth(GLfloat);
+GLAPI void APIENTRY glListBase(GLuint);
+GLAPI void APIENTRY glLoadIdentity();
+GLAPI void APIENTRY glLoadMatrixd(const GLdouble*);
+GLAPI void APIENTRY glLoadMatrixf(const GLfloat*);
+GLAPI void APIENTRY glLoadName(GLuint);
+GLAPI void APIENTRY glLogicOp(GLenum);
+GLAPI void APIENTRY glMap1d(GLenum, GLdouble, GLdouble, GLint, GLint, const GLdouble*);
+GLAPI void APIENTRY glMap1f(GLenum, GLfloat, GLfloat, GLint, GLint, const GLfloat*);
+GLAPI void APIENTRY glMap2d(GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble*);
+GLAPI void APIENTRY glMap2f(GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat*);
+GLAPI void APIENTRY glMapGrid1d(GLint, GLdouble, GLdouble);
+GLAPI void APIENTRY glMapGrid1f(GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glMapGrid2d(GLint, GLdouble, GLdouble, GLint, GLdouble, GLdouble);
+GLAPI void APIENTRY glMapGrid2f(GLint, GLfloat, GLfloat, GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glMaterialf(GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glMaterialfv(GLenum, GLenum, const GLfloat*);
+GLAPI void APIENTRY glMateriali(GLenum, GLenum, GLint);
+GLAPI void APIENTRY glMaterialiv(GLenum, GLenum, const GLint*);
+GLAPI void APIENTRY glMatrixMode(GLenum);
+GLAPI void APIENTRY glMultMatrixd(const GLdouble*);
+GLAPI void APIENTRY glMultMatrixf(const GLfloat*);
+GLAPI void APIENTRY glNewList(GLuint, GLenum);
+GLAPI void APIENTRY glNormal3b(GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glNormal3bv(const GLbyte*);
+GLAPI void APIENTRY glNormal3d(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glNormal3dv(const GLdouble*);
+GLAPI void APIENTRY glNormal3f(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormal3fv(const GLfloat*);
+GLAPI void APIENTRY glNormal3i(GLint, GLint, GLint);
+GLAPI void APIENTRY glNormal3iv(const GLint*);
+GLAPI void APIENTRY glNormal3s(GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glNormal3sv(const GLshort*);
+GLAPI void APIENTRY glOrtho(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glPassThrough(GLfloat);
+GLAPI void APIENTRY glPixelMapfv(GLenum, GLsizei, const GLfloat*);
+GLAPI void APIENTRY glPixelMapuiv(GLenum, GLsizei, const GLuint*);
+GLAPI void APIENTRY glPixelMapusv(GLenum, GLsizei, const GLushort*);
+GLAPI void APIENTRY glPixelStoref(GLenum, GLfloat);
+GLAPI void APIENTRY glPixelStorei(GLenum, GLint);
+GLAPI void APIENTRY glPixelTransferf(GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTransferi(GLenum, GLint);
+GLAPI void APIENTRY glPixelZoom(GLfloat, GLfloat);
+GLAPI void APIENTRY glPointSize(GLfloat);
+GLAPI void APIENTRY glPolygonMode(GLenum, GLenum);
+GLAPI void APIENTRY glPolygonStipple(const GLubyte*);
+GLAPI void APIENTRY glPopAttrib();
+GLAPI void APIENTRY glPopMatrix();
+GLAPI void APIENTRY glPopName();
+GLAPI void APIENTRY glPushAttrib(GLbitfield);
+GLAPI void APIENTRY glPushMatrix();
+GLAPI void APIENTRY glPushName(GLuint);
+GLAPI void APIENTRY glRasterPos2d(GLdouble, GLdouble);
+GLAPI void APIENTRY glRasterPos2dv(const GLdouble*);
+GLAPI void APIENTRY glRasterPos2f(GLfloat, GLfloat);
+GLAPI void APIENTRY glRasterPos2fv(const GLfloat*);
+GLAPI void APIENTRY glRasterPos2i(GLint, GLint);
+GLAPI void APIENTRY glRasterPos2iv(const GLint*);
+GLAPI void APIENTRY glRasterPos2s(GLshort, GLshort);
+GLAPI void APIENTRY glRasterPos2sv(const GLshort*);
+GLAPI void APIENTRY glRasterPos3d(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glRasterPos3dv(const GLdouble*);
+GLAPI void APIENTRY glRasterPos3f(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glRasterPos3fv(const GLfloat*);
+GLAPI void APIENTRY glRasterPos3i(GLint, GLint, GLint);
+GLAPI void APIENTRY glRasterPos3iv(const GLint*);
+GLAPI void APIENTRY glRasterPos3s(GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glRasterPos3sv(const GLshort*);
+GLAPI void APIENTRY glRasterPos4d(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glRasterPos4dv(const GLdouble*);
+GLAPI void APIENTRY glRasterPos4f(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glRasterPos4fv(const GLfloat*);
+GLAPI void APIENTRY glRasterPos4i(GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glRasterPos4iv(const GLint*);
+GLAPI void APIENTRY glRasterPos4s(GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glRasterPos4sv(const GLshort*);
+GLAPI void APIENTRY glReadBuffer(GLenum);
+GLAPI void APIENTRY glReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*);
+GLAPI void APIENTRY glRectd(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glRectdv(const GLdouble*, const GLdouble*);
+GLAPI void APIENTRY glRectf(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glRectfv(const GLfloat*, const GLfloat*);
+GLAPI void APIENTRY glRecti(GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glRectiv(const GLint*, const GLint*);
+GLAPI void APIENTRY glRects(GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glRectsv(const GLshort*, const GLshort*);
+GLAPI GLint APIENTRY glRenderMode(GLenum);
+GLAPI void APIENTRY glRotated(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glRotatef(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glScaled(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glScalef(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glScissor(GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glSelectBuffer(GLsizei, GLuint*);
+GLAPI void APIENTRY glShadeModel(GLenum);
+GLAPI void APIENTRY glStencilFunc(GLenum, GLint, GLuint);
+GLAPI void APIENTRY glStencilMask(GLuint);
+GLAPI void APIENTRY glStencilOp(GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glTexCoord1d(GLdouble);
+GLAPI void APIENTRY glTexCoord1dv(const GLdouble*);
+GLAPI void APIENTRY glTexCoord1f(GLfloat);
+GLAPI void APIENTRY glTexCoord1fv(const GLfloat*);
+GLAPI void APIENTRY glTexCoord1i(GLint);
+GLAPI void APIENTRY glTexCoord1iv(const GLint*);
+GLAPI void APIENTRY glTexCoord1s(GLshort);
+GLAPI void APIENTRY glTexCoord1sv(const GLshort*);
+GLAPI void APIENTRY glTexCoord2d(GLdouble, GLdouble);
+GLAPI void APIENTRY glTexCoord2dv(const GLdouble*);
+GLAPI void APIENTRY glTexCoord2f(GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fv(const GLfloat*);
+GLAPI void APIENTRY glTexCoord2i(GLint, GLint);
+GLAPI void APIENTRY glTexCoord2iv(const GLint*);
+GLAPI void APIENTRY glTexCoord2s(GLshort, GLshort);
+GLAPI void APIENTRY glTexCoord2sv(const GLshort*);
+GLAPI void APIENTRY glTexCoord3d(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTexCoord3dv(const GLdouble*);
+GLAPI void APIENTRY glTexCoord3f(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord3fv(const GLfloat*);
+GLAPI void APIENTRY glTexCoord3i(GLint, GLint, GLint);
+GLAPI void APIENTRY glTexCoord3iv(const GLint*);
+GLAPI void APIENTRY glTexCoord3s(GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTexCoord3sv(const GLshort*);
+GLAPI void APIENTRY glTexCoord4d(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTexCoord4dv(const GLdouble*);
+GLAPI void APIENTRY glTexCoord4f(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fv(const GLfloat*);
+GLAPI void APIENTRY glTexCoord4i(GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glTexCoord4iv(const GLint*);
+GLAPI void APIENTRY glTexCoord4s(GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTexCoord4sv(const GLshort*);
+GLAPI void APIENTRY glTexEnvf(GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glTexEnvfv(GLenum, GLenum, const GLfloat*);
+GLAPI void APIENTRY glTexEnvi(GLenum, GLenum, GLint);
+GLAPI void APIENTRY glTexEnviv(GLenum, GLenum, const GLint*);
+GLAPI void APIENTRY glTexGend(GLenum, GLenum, GLdouble);
+GLAPI void APIENTRY glTexGendv(GLenum, GLenum, const GLdouble*);
+GLAPI void APIENTRY glTexGenf(GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glTexGenfv(GLenum, GLenum, const GLfloat*);
+GLAPI void APIENTRY glTexGeni(GLenum, GLenum, GLint);
+GLAPI void APIENTRY glTexGeniv(GLenum, GLenum, const GLint*);
+GLAPI void APIENTRY glTexImage1D(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const void*);
+GLAPI void APIENTRY glTexImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*);
+GLAPI void APIENTRY glTexParameterf(GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glTexParameterfv(GLenum, GLenum, const GLfloat*);
+GLAPI void APIENTRY glTexParameteri(GLenum, GLenum, GLint);
+GLAPI void APIENTRY glTexParameteriv(GLenum, GLenum, const GLint*);
+GLAPI void APIENTRY glTranslated(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTranslatef(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertex2d(GLdouble, GLdouble);
+GLAPI void APIENTRY glVertex2dv(const GLdouble*);
+GLAPI void APIENTRY glVertex2f(GLfloat, GLfloat);
+GLAPI void APIENTRY glVertex2fv(const GLfloat*);
+GLAPI void APIENTRY glVertex2i(GLint, GLint);
+GLAPI void APIENTRY glVertex2iv(const GLint*);
+GLAPI void APIENTRY glVertex2s(GLshort, GLshort);
+GLAPI void APIENTRY glVertex2sv(const GLshort*);
+GLAPI void APIENTRY glVertex3d(GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertex3dv(const GLdouble*);
+GLAPI void APIENTRY glVertex3f(GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertex3fv(const GLfloat*);
+GLAPI void APIENTRY glVertex3i(GLint, GLint, GLint);
+GLAPI void APIENTRY glVertex3iv(const GLint*);
+GLAPI void APIENTRY glVertex3s(GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertex3sv(const GLshort*);
+GLAPI void APIENTRY glVertex4d(GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertex4dv(const GLdouble*);
+GLAPI void APIENTRY glVertex4f(GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertex4fv(const GLfloat*);
+GLAPI void APIENTRY glVertex4i(GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertex4iv(const GLint*);
+GLAPI void APIENTRY glVertex4s(GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertex4sv(const GLshort*);
+GLAPI void APIENTRY glViewport(GLint, GLint, GLsizei, GLsizei);
+
+GLAPI GLboolean APIENTRY glAreTexturesResident(GLsizei, const GLuint*, GLboolean*);
+GLAPI void APIENTRY glArrayElement(GLint);
+GLAPI void APIENTRY glBindTexture(GLenum, GLuint);
+GLAPI void APIENTRY glColorPointer(GLint, GLenum, GLsizei, const void*);
+GLAPI void APIENTRY glCopyTexImage1D(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexImage2D(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexSubImage1D(GLenum, GLint, GLint, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glDeleteTextures(GLsizei, const GLuint*);
+GLAPI void APIENTRY glDisableClientState(GLenum);
+GLAPI void APIENTRY glDrawArrays(GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glDrawElements(GLenum, GLsizei, GLenum, const void*);
+GLAPI void APIENTRY glEdgeFlagPointer(GLsizei, const void*);
+GLAPI void APIENTRY glEnableClientState(GLenum);
+GLAPI void APIENTRY glGenTextures(GLsizei, GLuint*);
+GLAPI void APIENTRY glGetPointerv(GLenum, void**);
+GLAPI void APIENTRY glIndexPointer(GLenum, GLsizei, const void*);
+GLAPI void APIENTRY glIndexub(GLubyte);
+GLAPI void APIENTRY glIndexubv(const GLubyte*);
+GLAPI void APIENTRY glInterleavedArrays(GLenum, GLsizei, const void*);
+GLAPI GLboolean APIENTRY glIsTexture(GLuint);
+GLAPI void APIENTRY glNormalPointer(GLenum, GLsizei, const void*);
+GLAPI void APIENTRY glPolygonOffset(GLfloat, GLfloat);
+GLAPI void APIENTRY glPopClientAttrib();
+GLAPI void APIENTRY glPrioritizeTextures(GLsizei, const GLuint*, const GLfloat*);
+GLAPI void APIENTRY glPushClientAttrib(GLbitfield);
+GLAPI void APIENTRY glTexCoordPointer(GLint, GLenum, GLsizei, const void*);
+GLAPI void APIENTRY glTexSubImage1D(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const void*);
+GLAPI void APIENTRY glTexSubImage2D(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*);
+GLAPI void APIENTRY glVertexPointer(GLint, GLenum, GLsizei, const void*);
+
+enum sfogl_LoadStatus
+{
+ sfogl_LOAD_FAILED = 0,
+ sfogl_LOAD_SUCCEEDED = 1
+};
+
+void sfogl_LoadFunctions();
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SFML_GLLOADER_HPP
diff --git a/src/SFML/Graphics/Glsl.cpp b/src/SFML/Graphics/Glsl.cpp
new file mode 100644
index 0000000..e8f9c1e
--- /dev/null
+++ b/src/SFML/Graphics/Glsl.cpp
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Glsl.hpp>
+#include <algorithm>
+
+
+namespace sf
+{
+namespace priv
+{
+
+ ////////////////////////////////////////////////////////////
+ void copyMatrix(const Transform& source, Matrix<3, 3>& dest)
+ {
+ const float* from = source.getMatrix(); // 4x4
+ float* to = dest.array; // 3x3
+
+ // Use only left-upper 3x3 block (for a 2D transform)
+ to[0] = from[ 0]; to[1] = from[ 1]; to[2] = from[ 3];
+ to[3] = from[ 4]; to[4] = from[ 5]; to[5] = from[ 7];
+ to[6] = from[12]; to[7] = from[13]; to[8] = from[15];
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ void copyMatrix(const Transform& source, Matrix<4, 4>& dest)
+ {
+ // Adopt 4x4 matrix as-is
+ copyMatrix(source.getMatrix(), 4 * 4, dest.array);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ void copyMatrix(const float* source, std::size_t elements, float* dest)
+ {
+ std::copy(source, source + elements, dest);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ void copyVector(const Color& source, Vector4<float>& dest)
+ {
+ dest.x = source.r / 255.f;
+ dest.y = source.g / 255.f;
+ dest.z = source.b / 255.f;
+ dest.w = source.a / 255.f;
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ void copyVector(const Color& source, Vector4<int>& dest)
+ {
+ dest.x = static_cast<int>(source.r);
+ dest.y = static_cast<int>(source.g);
+ dest.z = static_cast<int>(source.b);
+ dest.w = static_cast<int>(source.a);
+ }
+
+} // namespace priv
+} // namespace sf
diff --git a/src/SFML/Graphics/Image.cpp b/src/SFML/Graphics/Image.cpp
new file mode 100644
index 0000000..67c2840
--- /dev/null
+++ b/src/SFML/Graphics/Image.cpp
@@ -0,0 +1,340 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Graphics/ImageLoader.hpp>
+#include <SFML/System/Err.hpp>
+#ifdef SFML_SYSTEM_ANDROID
+ #include <SFML/System/Android/ResourceStream.hpp>
+#endif
+#include <algorithm>
+#include <cstring>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Image::Image() :
+m_size(0, 0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Image::~Image()
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::create(unsigned int width, unsigned int height, const Color& color)
+{
+ if (width && height)
+ {
+ // Create a new pixel buffer first for exception safety's sake
+ std::vector<Uint8> newPixels(width * height * 4);
+
+ // Fill it with the specified color
+ Uint8* ptr = &newPixels[0];
+ Uint8* end = ptr + newPixels.size();
+ while (ptr < end)
+ {
+ *ptr++ = color.r;
+ *ptr++ = color.g;
+ *ptr++ = color.b;
+ *ptr++ = color.a;
+ }
+
+ // Commit the new pixel buffer
+ m_pixels.swap(newPixels);
+
+ // Assign the new size
+ m_size.x = width;
+ m_size.y = height;
+ }
+ else
+ {
+ // Dump the pixel buffer
+ std::vector<Uint8>().swap(m_pixels);
+
+ // Assign the new size
+ m_size.x = 0;
+ m_size.y = 0;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::create(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ if (pixels && width && height)
+ {
+ // Create a new pixel buffer first for exception safety's sake
+ std::vector<Uint8> newPixels(pixels, pixels + width * height * 4);
+
+ // Commit the new pixel buffer
+ m_pixels.swap(newPixels);
+
+ // Assign the new size
+ m_size.x = width;
+ m_size.y = height;
+ }
+ else
+ {
+ // Dump the pixel buffer
+ std::vector<Uint8>().swap(m_pixels);
+
+ // Assign the new size
+ m_size.x = 0;
+ m_size.y = 0;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Image::loadFromFile(const std::string& filename)
+{
+ #ifndef SFML_SYSTEM_ANDROID
+
+ return priv::ImageLoader::getInstance().loadImageFromFile(filename, m_pixels, m_size);
+
+ #else
+
+ priv::ResourceStream stream(filename);
+ return loadFromStream(stream);
+
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+bool Image::loadFromMemory(const void* data, std::size_t size)
+{
+ return priv::ImageLoader::getInstance().loadImageFromMemory(data, size, m_pixels, m_size);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Image::loadFromStream(InputStream& stream)
+{
+ return priv::ImageLoader::getInstance().loadImageFromStream(stream, m_pixels, m_size);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Image::saveToFile(const std::string& filename) const
+{
+ return priv::ImageLoader::getInstance().saveImageToFile(filename, m_pixels, m_size);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u Image::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::createMaskFromColor(const Color& color, Uint8 alpha)
+{
+ // Make sure that the image is not empty
+ if (!m_pixels.empty())
+ {
+ // Replace the alpha of the pixels that match the transparent color
+ Uint8* ptr = &m_pixels[0];
+ Uint8* end = ptr + m_pixels.size();
+ while (ptr < end)
+ {
+ if ((ptr[0] == color.r) && (ptr[1] == color.g) && (ptr[2] == color.b) && (ptr[3] == color.a))
+ ptr[3] = alpha;
+ ptr += 4;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::copy(const Image& source, unsigned int destX, unsigned int destY, const IntRect& sourceRect, bool applyAlpha)
+{
+ // Make sure that both images are valid
+ if ((source.m_size.x == 0) || (source.m_size.y == 0) || (m_size.x == 0) || (m_size.y == 0))
+ return;
+
+ // Adjust the source rectangle
+ IntRect srcRect = sourceRect;
+ if (srcRect.width == 0 || (srcRect.height == 0))
+ {
+ srcRect.left = 0;
+ srcRect.top = 0;
+ srcRect.width = source.m_size.x;
+ srcRect.height = source.m_size.y;
+ }
+ else
+ {
+ if (srcRect.left < 0) srcRect.left = 0;
+ if (srcRect.top < 0) srcRect.top = 0;
+ if (srcRect.width > static_cast<int>(source.m_size.x)) srcRect.width = source.m_size.x;
+ if (srcRect.height > static_cast<int>(source.m_size.y)) srcRect.height = source.m_size.y;
+ }
+
+ // Then find the valid bounds of the destination rectangle
+ int width = srcRect.width;
+ int height = srcRect.height;
+ if (destX + width > m_size.x) width = m_size.x - destX;
+ if (destY + height > m_size.y) height = m_size.y - destY;
+
+ // Make sure the destination area is valid
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ // Precompute as much as possible
+ int pitch = width * 4;
+ int rows = height;
+ int srcStride = source.m_size.x * 4;
+ int dstStride = m_size.x * 4;
+ const Uint8* srcPixels = &source.m_pixels[0] + (srcRect.left + srcRect.top * source.m_size.x) * 4;
+ Uint8* dstPixels = &m_pixels[0] + (destX + destY * m_size.x) * 4;
+
+ // Copy the pixels
+ if (applyAlpha)
+ {
+ // Interpolation using alpha values, pixel by pixel (slower)
+ for (int i = 0; i < rows; ++i)
+ {
+ for (int j = 0; j < width; ++j)
+ {
+ // Get a direct pointer to the components of the current pixel
+ const Uint8* src = srcPixels + j * 4;
+ Uint8* dst = dstPixels + j * 4;
+
+ // Interpolate RGBA components using the alpha value of the source pixel
+ Uint8 alpha = src[3];
+ dst[0] = (src[0] * alpha + dst[0] * (255 - alpha)) / 255;
+ dst[1] = (src[1] * alpha + dst[1] * (255 - alpha)) / 255;
+ dst[2] = (src[2] * alpha + dst[2] * (255 - alpha)) / 255;
+ dst[3] = alpha + dst[3] * (255 - alpha) / 255;
+ }
+
+ srcPixels += srcStride;
+ dstPixels += dstStride;
+ }
+ }
+ else
+ {
+ // Optimized copy ignoring alpha values, row by row (faster)
+ for (int i = 0; i < rows; ++i)
+ {
+ std::memcpy(dstPixels, srcPixels, pitch);
+ srcPixels += srcStride;
+ dstPixels += dstStride;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::setPixel(unsigned int x, unsigned int y, const Color& color)
+{
+ Uint8* pixel = &m_pixels[(x + y * m_size.x) * 4];
+ *pixel++ = color.r;
+ *pixel++ = color.g;
+ *pixel++ = color.b;
+ *pixel++ = color.a;
+}
+
+
+////////////////////////////////////////////////////////////
+Color Image::getPixel(unsigned int x, unsigned int y) const
+{
+ const Uint8* pixel = &m_pixels[(x + y * m_size.x) * 4];
+ return Color(pixel[0], pixel[1], pixel[2], pixel[3]);
+}
+
+
+////////////////////////////////////////////////////////////
+const Uint8* Image::getPixelsPtr() const
+{
+ if (!m_pixels.empty())
+ {
+ return &m_pixels[0];
+ }
+ else
+ {
+ err() << "Trying to access the pixels of an empty image" << std::endl;
+ return NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::flipHorizontally()
+{
+ if (!m_pixels.empty())
+ {
+ std::size_t rowSize = m_size.x * 4;
+
+ for (std::size_t y = 0; y < m_size.y; ++y)
+ {
+ std::vector<Uint8>::iterator left = m_pixels.begin() + y * rowSize;
+ std::vector<Uint8>::iterator right = m_pixels.begin() + (y + 1) * rowSize - 4;
+
+ for (std::size_t x = 0; x < m_size.x / 2; ++x)
+ {
+ std::swap_ranges(left, left + 4, right);
+
+ left += 4;
+ right -= 4;
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Image::flipVertically()
+{
+ if (!m_pixels.empty())
+ {
+ std::size_t rowSize = m_size.x * 4;
+
+ std::vector<Uint8>::iterator top = m_pixels.begin();
+ std::vector<Uint8>::iterator bottom = m_pixels.end() - rowSize;
+
+ for (std::size_t y = 0; y < m_size.y / 2; ++y)
+ {
+ std::swap_ranges(top, top + rowSize, bottom);
+
+ top += rowSize;
+ bottom -= rowSize;
+ }
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/ImageLoader.cpp b/src/SFML/Graphics/ImageLoader.cpp
new file mode 100644
index 0000000..023541d
--- /dev/null
+++ b/src/SFML/Graphics/ImageLoader.cpp
@@ -0,0 +1,277 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/ImageLoader.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Err.hpp>
+#define STB_IMAGE_IMPLEMENTATION
+#include <stb_image.h>
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include <stb_image_write.h>
+#include <cctype>
+
+
+namespace
+{
+ // Convert a string to lower case
+ std::string toLower(std::string str)
+ {
+ for (std::string::iterator i = str.begin(); i != str.end(); ++i)
+ *i = static_cast<char>(std::tolower(*i));
+ return str;
+ }
+
+ // stb_image callbacks that operate on a sf::InputStream
+ int read(void* user, char* data, int size)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(user);
+ return static_cast<int>(stream->read(data, size));
+ }
+ void skip(void* user, int size)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(user);
+ stream->seek(stream->tell() + size);
+ }
+ int eof(void* user)
+ {
+ sf::InputStream* stream = static_cast<sf::InputStream*>(user);
+ return stream->tell() >= stream->getSize();
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+ImageLoader& ImageLoader::getInstance()
+{
+ static ImageLoader Instance;
+
+ return Instance;
+}
+
+
+////////////////////////////////////////////////////////////
+ImageLoader::ImageLoader()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+ImageLoader::~ImageLoader()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool ImageLoader::loadImageFromFile(const std::string& filename, std::vector<Uint8>& pixels, Vector2u& size)
+{
+ // Clear the array (just in case)
+ pixels.clear();
+
+ // Load the image and get a pointer to the pixels in memory
+ int width = 0;
+ int height = 0;
+ int channels = 0;
+ unsigned char* ptr = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha);
+
+ if (ptr)
+ {
+ // Assign the image properties
+ size.x = width;
+ size.y = height;
+
+ if (width && height)
+ {
+ // Copy the loaded pixels to the pixel buffer
+ pixels.resize(width * height * 4);
+ memcpy(&pixels[0], ptr, pixels.size());
+ }
+
+ // Free the loaded pixels (they are now in our own pixel buffer)
+ stbi_image_free(ptr);
+
+ return true;
+ }
+ else
+ {
+ // Error, failed to load the image
+ err() << "Failed to load image \"" << filename << "\". Reason: " << stbi_failure_reason() << std::endl;
+
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool ImageLoader::loadImageFromMemory(const void* data, std::size_t dataSize, std::vector<Uint8>& pixels, Vector2u& size)
+{
+ // Check input parameters
+ if (data && dataSize)
+ {
+ // Clear the array (just in case)
+ pixels.clear();
+
+ // Load the image and get a pointer to the pixels in memory
+ int width = 0;
+ int height = 0;
+ int channels = 0;
+ const unsigned char* buffer = static_cast<const unsigned char*>(data);
+ unsigned char* ptr = stbi_load_from_memory(buffer, static_cast<int>(dataSize), &width, &height, &channels, STBI_rgb_alpha);
+
+ if (ptr)
+ {
+ // Assign the image properties
+ size.x = width;
+ size.y = height;
+
+ if (width && height)
+ {
+ // Copy the loaded pixels to the pixel buffer
+ pixels.resize(width * height * 4);
+ memcpy(&pixels[0], ptr, pixels.size());
+ }
+
+ // Free the loaded pixels (they are now in our own pixel buffer)
+ stbi_image_free(ptr);
+
+ return true;
+ }
+ else
+ {
+ // Error, failed to load the image
+ err() << "Failed to load image from memory. Reason: " << stbi_failure_reason() << std::endl;
+
+ return false;
+ }
+ }
+ else
+ {
+ err() << "Failed to load image from memory, no data provided" << std::endl;
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool ImageLoader::loadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, Vector2u& size)
+{
+ // Clear the array (just in case)
+ pixels.clear();
+
+ // Make sure that the stream's reading position is at the beginning
+ stream.seek(0);
+
+ // Setup the stb_image callbacks
+ stbi_io_callbacks callbacks;
+ callbacks.read = &read;
+ callbacks.skip = &skip;
+ callbacks.eof = &eof;
+
+ // Load the image and get a pointer to the pixels in memory
+ int width = 0;
+ int height = 0;
+ int channels = 0;
+ unsigned char* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &channels, STBI_rgb_alpha);
+
+ if (ptr)
+ {
+ // Assign the image properties
+ size.x = width;
+ size.y = height;
+
+ if (width && height)
+ {
+ // Copy the loaded pixels to the pixel buffer
+ pixels.resize(width * height * 4);
+ memcpy(&pixels[0], ptr, pixels.size());
+ }
+
+ // Free the loaded pixels (they are now in our own pixel buffer)
+ stbi_image_free(ptr);
+
+ return true;
+ }
+ else
+ {
+ // Error, failed to load the image
+ err() << "Failed to load image from stream. Reason: " << stbi_failure_reason() << std::endl;
+
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool ImageLoader::saveImageToFile(const std::string& filename, const std::vector<Uint8>& pixels, const Vector2u& size)
+{
+ // Make sure the image is not empty
+ if (!pixels.empty() && (size.x > 0) && (size.y > 0))
+ {
+ // Deduce the image type from its extension
+
+ // Extract the extension
+ const std::size_t dot = filename.find_last_of('.');
+ const std::string extension = dot != std::string::npos ? toLower(filename.substr(dot + 1)) : "";
+
+ if (extension == "bmp")
+ {
+ // BMP format
+ if (stbi_write_bmp(filename.c_str(), size.x, size.y, 4, &pixels[0]))
+ return true;
+ }
+ else if (extension == "tga")
+ {
+ // TGA format
+ if (stbi_write_tga(filename.c_str(), size.x, size.y, 4, &pixels[0]))
+ return true;
+ }
+ else if (extension == "png")
+ {
+ // PNG format
+ if (stbi_write_png(filename.c_str(), size.x, size.y, 4, &pixels[0], 0))
+ return true;
+ }
+ else if (extension == "jpg" || extension == "jpeg")
+ {
+ // JPG format
+ if (stbi_write_jpg(filename.c_str(), size.x, size.y, 4, &pixels[0], 90))
+ return true;
+ }
+ }
+
+ err() << "Failed to save image \"" << filename << "\"" << std::endl;
+ return false;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/ImageLoader.hpp b/src/SFML/Graphics/ImageLoader.hpp
new file mode 100644
index 0000000..0134bd8
--- /dev/null
+++ b/src/SFML/Graphics/ImageLoader.hpp
@@ -0,0 +1,128 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_IMAGELOADER_HPP
+#define SFML_IMAGELOADER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <string>
+#include <vector>
+
+
+namespace sf
+{
+class InputStream;
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Load/save image files
+///
+////////////////////////////////////////////////////////////
+class ImageLoader : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the unique instance of the class
+ ///
+ /// \return Reference to the ImageLoader instance
+ ///
+ ////////////////////////////////////////////////////////////
+ static ImageLoader& getInstance();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load an image from a file on disk
+ ///
+ /// \param filename Path of image file to load
+ /// \param pixels Array of pixels to fill with loaded image
+ /// \param size Size of loaded image, in pixels
+ ///
+ /// \return True if loading was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadImageFromFile(const std::string& filename, std::vector<Uint8>& pixels, Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load an image from a file in memory
+ ///
+ /// \param data Pointer to the file data in memory
+ /// \param dataSize Size of the data to load, in bytes
+ /// \param pixels Array of pixels to fill with loaded image
+ /// \param size Size of loaded image, in pixels
+ ///
+ /// \return True if loading was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadImageFromMemory(const void* data, std::size_t dataSize, std::vector<Uint8>& pixels, Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load an image from a custom stream
+ ///
+ /// \param stream Source stream to read from
+ /// \param pixels Array of pixels to fill with loaded image
+ /// \param size Size of loaded image, in pixels
+ ///
+ /// \return True if loading was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Save an array of pixels as an image file
+ ///
+ /// \param filename Path of image file to save
+ /// \param pixels Array of pixels to save to image
+ /// \param size Size of image to save, in pixels
+ ///
+ /// \return True if saving was successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool saveImageToFile(const std::string& filename, const std::vector<Uint8>& pixels, const Vector2u& size);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ImageLoader();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ImageLoader();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_IMAGELOADER_HPP
diff --git a/src/SFML/Graphics/RectangleShape.cpp b/src/SFML/Graphics/RectangleShape.cpp
new file mode 100644
index 0000000..f7778c0
--- /dev/null
+++ b/src/SFML/Graphics/RectangleShape.cpp
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RectangleShape.hpp>
+#include <cmath>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+RectangleShape::RectangleShape(const Vector2f& size)
+{
+ setSize(size);
+}
+
+
+////////////////////////////////////////////////////////////
+void RectangleShape::setSize(const Vector2f& size)
+{
+ m_size = size;
+ update();
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& RectangleShape::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t RectangleShape::getPointCount() const
+{
+ return 4;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f RectangleShape::getPoint(std::size_t index) const
+{
+ switch (index)
+ {
+ default:
+ case 0: return Vector2f(0, 0);
+ case 1: return Vector2f(m_size.x, 0);
+ case 2: return Vector2f(m_size.x, m_size.y);
+ case 3: return Vector2f(0, m_size.y);
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderStates.cpp b/src/SFML/Graphics/RenderStates.cpp
new file mode 100644
index 0000000..4c55546
--- /dev/null
+++ b/src/SFML/Graphics/RenderStates.cpp
@@ -0,0 +1,102 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderStates.hpp>
+#include <cstddef>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+// We cannot use the default constructor here, because it accesses BlendAlpha, which is also global (and dynamically
+// initialized). Initialization order of global objects in different translation units is not defined.
+const RenderStates RenderStates::Default(BlendMode(
+ BlendMode::SrcAlpha, BlendMode::OneMinusSrcAlpha, BlendMode::Add,
+ BlendMode::One, BlendMode::OneMinusSrcAlpha, BlendMode::Add));
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates() :
+blendMode(BlendAlpha),
+transform(),
+texture (NULL),
+shader (NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates(const Transform& theTransform) :
+blendMode(BlendAlpha),
+transform(theTransform),
+texture (NULL),
+shader (NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates(const BlendMode& theBlendMode) :
+blendMode(theBlendMode),
+transform(),
+texture (NULL),
+shader (NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates(const Texture* theTexture) :
+blendMode(BlendAlpha),
+transform(),
+texture (theTexture),
+shader (NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates(const Shader* theShader) :
+blendMode(BlendAlpha),
+transform(),
+texture (NULL),
+shader (theShader)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+RenderStates::RenderStates(const BlendMode& theBlendMode, const Transform& theTransform,
+ const Texture* theTexture, const Shader* theShader) :
+blendMode(theBlendMode),
+transform(theTransform),
+texture (theTexture),
+shader (theShader)
+{
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp
new file mode 100644
index 0000000..9a6e301
--- /dev/null
+++ b/src/SFML/Graphics/RenderTarget.cpp
@@ -0,0 +1,769 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Graphics/Drawable.hpp>
+#include <SFML/Graphics/Shader.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/Graphics/VertexBuffer.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <cassert>
+#include <iostream>
+#include <algorithm>
+#include <map>
+
+
+// GL_QUADS is unavailable on OpenGL ES, thus we need to define GL_QUADS ourselves
+#ifdef SFML_OPENGL_ES
+
+ #define GL_QUADS 0
+
+#endif // SFML_OPENGL_ES
+
+
+namespace
+{
+ // Mutex to protect ID generation and our context-RenderTarget-map
+ sf::Mutex mutex;
+
+ // Unique identifier, used for identifying RenderTargets when
+ // tracking the currently active RenderTarget within a given context
+ sf::Uint64 getUniqueId()
+ {
+ sf::Lock lock(mutex);
+
+ static sf::Uint64 id = 1; // start at 1, zero is "no RenderTarget"
+
+ return id++;
+ }
+
+ // Map to help us detect whether a different RenderTarget
+ // has been activated within a single context
+ typedef std::map<sf::Uint64, sf::Uint64> ContextRenderTargetMap;
+ ContextRenderTargetMap contextRenderTargetMap;
+
+ // Check if a RenderTarget with the given ID is active in the current context
+ bool isActive(sf::Uint64 id)
+ {
+ ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(sf::Context::getActiveContextId());
+
+ if ((iter == contextRenderTargetMap.end()) || (iter->second != id))
+ return false;
+
+ return true;
+ }
+
+ // Convert an sf::BlendMode::Factor constant to the corresponding OpenGL constant.
+ sf::Uint32 factorToGlConstant(sf::BlendMode::Factor blendFactor)
+ {
+ switch (blendFactor)
+ {
+ case sf::BlendMode::Zero: return GL_ZERO;
+ case sf::BlendMode::One: return GL_ONE;
+ case sf::BlendMode::SrcColor: return GL_SRC_COLOR;
+ case sf::BlendMode::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR;
+ case sf::BlendMode::DstColor: return GL_DST_COLOR;
+ case sf::BlendMode::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR;
+ case sf::BlendMode::SrcAlpha: return GL_SRC_ALPHA;
+ case sf::BlendMode::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
+ case sf::BlendMode::DstAlpha: return GL_DST_ALPHA;
+ case sf::BlendMode::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA;
+ }
+
+ sf::err() << "Invalid value for sf::BlendMode::Factor! Fallback to sf::BlendMode::Zero." << std::endl;
+ assert(false);
+ return GL_ZERO;
+ }
+
+
+ // Convert an sf::BlendMode::BlendEquation constant to the corresponding OpenGL constant.
+ sf::Uint32 equationToGlConstant(sf::BlendMode::Equation blendEquation)
+ {
+ switch (blendEquation)
+ {
+ case sf::BlendMode::Add: return GLEXT_GL_FUNC_ADD;
+ case sf::BlendMode::Subtract: return GLEXT_GL_FUNC_SUBTRACT;
+ case sf::BlendMode::ReverseSubtract: return GLEXT_GL_FUNC_REVERSE_SUBTRACT;
+ }
+
+ sf::err() << "Invalid value for sf::BlendMode::Equation! Fallback to sf::BlendMode::Add." << std::endl;
+ assert(false);
+ return GLEXT_GL_FUNC_ADD;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+RenderTarget::RenderTarget() :
+m_defaultView(),
+m_view (),
+m_cache (),
+m_id (0)
+{
+ m_cache.glStatesSet = false;
+}
+
+
+////////////////////////////////////////////////////////////
+RenderTarget::~RenderTarget()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::clear(const Color& color)
+{
+ if (isActive(m_id) || setActive(true))
+ {
+ // Unbind texture to fix RenderTexture preventing clear
+ applyTexture(NULL);
+
+ glCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
+ glCheck(glClear(GL_COLOR_BUFFER_BIT));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::setView(const View& view)
+{
+ m_view = view;
+ m_cache.viewChanged = true;
+}
+
+
+////////////////////////////////////////////////////////////
+const View& RenderTarget::getView() const
+{
+ return m_view;
+}
+
+
+////////////////////////////////////////////////////////////
+const View& RenderTarget::getDefaultView() const
+{
+ return m_defaultView;
+}
+
+
+////////////////////////////////////////////////////////////
+IntRect RenderTarget::getViewport(const View& view) const
+{
+ float width = static_cast<float>(getSize().x);
+ float height = static_cast<float>(getSize().y);
+ const FloatRect& viewport = view.getViewport();
+
+ return IntRect(static_cast<int>(0.5f + width * viewport.left),
+ static_cast<int>(0.5f + height * viewport.top),
+ static_cast<int>(0.5f + width * viewport.width),
+ static_cast<int>(0.5f + height * viewport.height));
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f RenderTarget::mapPixelToCoords(const Vector2i& point) const
+{
+ return mapPixelToCoords(point, getView());
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f RenderTarget::mapPixelToCoords(const Vector2i& point, const View& view) const
+{
+ // First, convert from viewport coordinates to homogeneous coordinates
+ Vector2f normalized;
+ IntRect viewport = getViewport(view);
+ normalized.x = -1.f + 2.f * (point.x - viewport.left) / viewport.width;
+ normalized.y = 1.f - 2.f * (point.y - viewport.top) / viewport.height;
+
+ // Then transform by the inverse of the view matrix
+ return view.getInverseTransform().transformPoint(normalized);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i RenderTarget::mapCoordsToPixel(const Vector2f& point) const
+{
+ return mapCoordsToPixel(point, getView());
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i RenderTarget::mapCoordsToPixel(const Vector2f& point, const View& view) const
+{
+ // First, transform the point by the view matrix
+ Vector2f normalized = view.getTransform().transformPoint(point);
+
+ // Then convert to viewport coordinates
+ Vector2i pixel;
+ IntRect viewport = getViewport(view);
+ pixel.x = static_cast<int>(( normalized.x + 1.f) / 2.f * viewport.width + viewport.left);
+ pixel.y = static_cast<int>((-normalized.y + 1.f) / 2.f * viewport.height + viewport.top);
+
+ return pixel;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::draw(const Drawable& drawable, const RenderStates& states)
+{
+ drawable.draw(*this, states);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
+ PrimitiveType type, const RenderStates& states)
+{
+ // Nothing to draw?
+ if (!vertices || (vertexCount == 0))
+ return;
+
+ // GL_QUADS is unavailable on OpenGL ES
+ #ifdef SFML_OPENGL_ES
+ if (type == Quads)
+ {
+ err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
+ return;
+ }
+ #endif
+
+ if (isActive(m_id) || setActive(true))
+ {
+ // Check if the vertex count is low enough so that we can pre-transform them
+ bool useVertexCache = (vertexCount <= StatesCache::VertexCacheSize);
+
+ if (useVertexCache)
+ {
+ // Pre-transform the vertices and store them into the vertex cache
+ for (std::size_t i = 0; i < vertexCount; ++i)
+ {
+ Vertex& vertex = m_cache.vertexCache[i];
+ vertex.position = states.transform * vertices[i].position;
+ vertex.color = vertices[i].color;
+ vertex.texCoords = vertices[i].texCoords;
+ }
+ }
+
+ setupDraw(useVertexCache, states);
+
+ // Check if texture coordinates array is needed, and update client state accordingly
+ bool enableTexCoordsArray = (states.texture || states.shader);
+ if (!m_cache.enable || (enableTexCoordsArray != m_cache.texCoordsArrayEnabled))
+ {
+ if (enableTexCoordsArray)
+ glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+ else
+ glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
+ }
+
+ // If we switch between non-cache and cache mode or enable texture
+ // coordinates we need to set up the pointers to the vertices' components
+ if (!m_cache.enable || !useVertexCache || !m_cache.useVertexCache)
+ {
+ const char* data = reinterpret_cast<const char*>(vertices);
+
+ // If we pre-transform the vertices, we must use our internal vertex cache
+ if (useVertexCache)
+ data = reinterpret_cast<const char*>(m_cache.vertexCache);
+
+ glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
+ glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
+ if (enableTexCoordsArray)
+ glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
+ }
+ else if (enableTexCoordsArray && !m_cache.texCoordsArrayEnabled)
+ {
+ // If we enter this block, we are already using our internal vertex cache
+ const char* data = reinterpret_cast<const char*>(m_cache.vertexCache);
+
+ glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
+ }
+
+ drawPrimitives(type, 0, vertexCount);
+ cleanupDraw(states);
+
+ // Update the cache
+ m_cache.useVertexCache = useVertexCache;
+ m_cache.texCoordsArrayEnabled = enableTexCoordsArray;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::draw(const VertexBuffer& vertexBuffer, const RenderStates& states)
+{
+ draw(vertexBuffer, 0, vertexBuffer.getVertexCount(), states);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
+ std::size_t vertexCount, const RenderStates& states)
+{
+ // VertexBuffer not supported?
+ if (!VertexBuffer::isAvailable())
+ {
+ err() << "sf::VertexBuffer is not available, drawing skipped" << std::endl;
+ return;
+ }
+
+ // Sanity check
+ if (firstVertex > vertexBuffer.getVertexCount())
+ return;
+
+ // Clamp vertexCount to something that makes sense
+ vertexCount = std::min(vertexCount, vertexBuffer.getVertexCount() - firstVertex);
+
+ // Nothing to draw?
+ if (!vertexCount || !vertexBuffer.getNativeHandle())
+ return;
+
+ // GL_QUADS is unavailable on OpenGL ES
+ #ifdef SFML_OPENGL_ES
+ if (vertexBuffer.getPrimitiveType() == Quads)
+ {
+ err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
+ return;
+ }
+ #endif
+
+ if (isActive(m_id) || setActive(true))
+ {
+ setupDraw(false, states);
+
+ // Bind vertex buffer
+ VertexBuffer::bind(&vertexBuffer);
+
+ // Always enable texture coordinates
+ if (!m_cache.enable || !m_cache.texCoordsArrayEnabled)
+ glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+
+ glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(0)));
+ glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), reinterpret_cast<const void*>(8)));
+ glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(12)));
+
+ drawPrimitives(vertexBuffer.getPrimitiveType(), firstVertex, vertexCount);
+
+ // Unbind vertex buffer
+ VertexBuffer::bind(NULL);
+
+ cleanupDraw(states);
+
+ // Update the cache
+ m_cache.useVertexCache = false;
+ m_cache.texCoordsArrayEnabled = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTarget::setActive(bool active)
+{
+ // Mark this RenderTarget as active or no longer active in the tracking map
+ {
+ sf::Lock lock(mutex);
+
+ Uint64 contextId = Context::getActiveContextId();
+
+ ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(contextId);
+
+ if (active)
+ {
+ if (iter == contextRenderTargetMap.end())
+ {
+ contextRenderTargetMap[contextId] = m_id;
+
+ m_cache.enable = false;
+ }
+ else if (iter->second != m_id)
+ {
+ iter->second = m_id;
+
+ m_cache.enable = false;
+ }
+ }
+ else
+ {
+ if (iter != contextRenderTargetMap.end())
+ contextRenderTargetMap.erase(iter);
+
+ m_cache.enable = false;
+ }
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::pushGLStates()
+{
+ if (isActive(m_id) || setActive(true))
+ {
+ #ifdef SFML_DEBUG
+ // make sure that the user didn't leave an unchecked OpenGL error
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ {
+ err() << "OpenGL error (" << error << ") detected in user code, "
+ << "you should check for errors with glGetError()"
+ << std::endl;
+ }
+ #endif
+
+ #ifndef SFML_OPENGL_ES
+ glCheck(glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS));
+ glCheck(glPushAttrib(GL_ALL_ATTRIB_BITS));
+ #endif
+ glCheck(glMatrixMode(GL_MODELVIEW));
+ glCheck(glPushMatrix());
+ glCheck(glMatrixMode(GL_PROJECTION));
+ glCheck(glPushMatrix());
+ glCheck(glMatrixMode(GL_TEXTURE));
+ glCheck(glPushMatrix());
+ }
+
+ resetGLStates();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::popGLStates()
+{
+ if (isActive(m_id) || setActive(true))
+ {
+ glCheck(glMatrixMode(GL_PROJECTION));
+ glCheck(glPopMatrix());
+ glCheck(glMatrixMode(GL_MODELVIEW));
+ glCheck(glPopMatrix());
+ glCheck(glMatrixMode(GL_TEXTURE));
+ glCheck(glPopMatrix());
+ #ifndef SFML_OPENGL_ES
+ glCheck(glPopClientAttrib());
+ glCheck(glPopAttrib());
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::resetGLStates()
+{
+ // Check here to make sure a context change does not happen after activate(true)
+ bool shaderAvailable = Shader::isAvailable();
+ bool vertexBufferAvailable = VertexBuffer::isAvailable();
+
+ // Workaround for states not being properly reset on
+ // macOS unless a context switch really takes place
+ #if defined(SFML_SYSTEM_MACOS)
+ setActive(false);
+ #endif
+
+ if (isActive(m_id) || setActive(true))
+ {
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+
+ // Make sure that the texture unit which is active is the number 0
+ if (GLEXT_multitexture)
+ {
+ glCheck(GLEXT_glClientActiveTexture(GLEXT_GL_TEXTURE0));
+ glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0));
+ }
+
+ // Define the default OpenGL states
+ glCheck(glDisable(GL_CULL_FACE));
+ glCheck(glDisable(GL_LIGHTING));
+ glCheck(glDisable(GL_DEPTH_TEST));
+ glCheck(glDisable(GL_ALPHA_TEST));
+ glCheck(glEnable(GL_TEXTURE_2D));
+ glCheck(glEnable(GL_BLEND));
+ glCheck(glMatrixMode(GL_MODELVIEW));
+ glCheck(glLoadIdentity());
+ glCheck(glEnableClientState(GL_VERTEX_ARRAY));
+ glCheck(glEnableClientState(GL_COLOR_ARRAY));
+ glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+ m_cache.glStatesSet = true;
+
+ // Apply the default SFML states
+ applyBlendMode(BlendAlpha);
+ applyTexture(NULL);
+ if (shaderAvailable)
+ applyShader(NULL);
+
+ if (vertexBufferAvailable)
+ glCheck(VertexBuffer::bind(NULL));
+
+ m_cache.texCoordsArrayEnabled = true;
+
+ m_cache.useVertexCache = false;
+
+ // Set the default view
+ setView(getView());
+
+ m_cache.enable = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::initialize()
+{
+ // Setup the default and current views
+ m_defaultView.reset(FloatRect(0, 0, static_cast<float>(getSize().x), static_cast<float>(getSize().y)));
+ m_view = m_defaultView;
+
+ // Set GL states only on first draw, so that we don't pollute user's states
+ m_cache.glStatesSet = false;
+
+ // Generate a unique ID for this RenderTarget to track
+ // whether it is active within a specific context
+ m_id = getUniqueId();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::applyCurrentView()
+{
+ // Set the viewport
+ IntRect viewport = getViewport(m_view);
+ int top = getSize().y - (viewport.top + viewport.height);
+ glCheck(glViewport(viewport.left, top, viewport.width, viewport.height));
+
+ // Set the projection matrix
+ glCheck(glMatrixMode(GL_PROJECTION));
+ glCheck(glLoadMatrixf(m_view.getTransform().getMatrix()));
+
+ // Go back to model-view mode
+ glCheck(glMatrixMode(GL_MODELVIEW));
+
+ m_cache.viewChanged = false;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::applyBlendMode(const BlendMode& mode)
+{
+ // Apply the blend mode, falling back to the non-separate versions if necessary
+ if (GLEXT_blend_func_separate)
+ {
+ glCheck(GLEXT_glBlendFuncSeparate(
+ factorToGlConstant(mode.colorSrcFactor), factorToGlConstant(mode.colorDstFactor),
+ factorToGlConstant(mode.alphaSrcFactor), factorToGlConstant(mode.alphaDstFactor)));
+ }
+ else
+ {
+ glCheck(glBlendFunc(
+ factorToGlConstant(mode.colorSrcFactor),
+ factorToGlConstant(mode.colorDstFactor)));
+ }
+
+ if (GLEXT_blend_minmax && GLEXT_blend_subtract)
+ {
+ if (GLEXT_blend_equation_separate)
+ {
+ glCheck(GLEXT_glBlendEquationSeparate(
+ equationToGlConstant(mode.colorEquation),
+ equationToGlConstant(mode.alphaEquation)));
+ }
+ else
+ {
+ glCheck(GLEXT_glBlendEquation(equationToGlConstant(mode.colorEquation)));
+ }
+ }
+ else if ((mode.colorEquation != BlendMode::Add) || (mode.alphaEquation != BlendMode::Add))
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ err() << "OpenGL extension EXT_blend_minmax and/or EXT_blend_subtract unavailable" << std::endl;
+ err() << "Selecting a blend equation not possible" << std::endl;
+ err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
+
+ warned = true;
+ }
+ }
+
+ m_cache.lastBlendMode = mode;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::applyTransform(const Transform& transform)
+{
+ // No need to call glMatrixMode(GL_MODELVIEW), it is always the
+ // current mode (for optimization purpose, since it's the most used)
+ if (transform == Transform::Identity)
+ glCheck(glLoadIdentity());
+ else
+ glCheck(glLoadMatrixf(transform.getMatrix()));
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::applyTexture(const Texture* texture)
+{
+ Texture::bind(texture, Texture::Pixels);
+
+ m_cache.lastTextureId = texture ? texture->m_cacheId : 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::applyShader(const Shader* shader)
+{
+ Shader::bind(shader);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
+{
+ // First set the persistent OpenGL states if it's the very first call
+ if (!m_cache.glStatesSet)
+ resetGLStates();
+
+ if (useVertexCache)
+ {
+ // Since vertices are transformed, we must use an identity transform to render them
+ if (!m_cache.enable || !m_cache.useVertexCache)
+ glCheck(glLoadIdentity());
+ }
+ else
+ {
+ applyTransform(states.transform);
+ }
+
+ // Apply the view
+ if (!m_cache.enable || m_cache.viewChanged)
+ applyCurrentView();
+
+ // Apply the blend mode
+ if (!m_cache.enable || (states.blendMode != m_cache.lastBlendMode))
+ applyBlendMode(states.blendMode);
+
+ // Apply the texture
+ if (!m_cache.enable || (states.texture && states.texture->m_fboAttachment))
+ {
+ // If the texture is an FBO attachment, always rebind it
+ // in order to inform the OpenGL driver that we want changes
+ // made to it in other contexts to be visible here as well
+ // This saves us from having to call glFlush() in
+ // RenderTextureImplFBO which can be quite costly
+ // See: https://www.khronos.org/opengl/wiki/Memory_Model
+ applyTexture(states.texture);
+ }
+ else
+ {
+ Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
+ if (textureId != m_cache.lastTextureId)
+ applyTexture(states.texture);
+ }
+
+ // Apply the shader
+ if (states.shader)
+ applyShader(states.shader);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount)
+{
+ // Find the OpenGL primitive type
+ static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
+ GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
+ GLenum mode = modes[type];
+
+ // Draw the primitives
+ glCheck(glDrawArrays(mode, static_cast<GLint>(firstVertex), static_cast<GLsizei>(vertexCount)));
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTarget::cleanupDraw(const RenderStates& states)
+{
+ // Unbind the shader, if any
+ if (states.shader)
+ applyShader(NULL);
+
+ // If the texture we used to draw belonged to a RenderTexture, then forcibly unbind that texture.
+ // This prevents a bug where some drivers do not clear RenderTextures properly.
+ if (states.texture && states.texture->m_fboAttachment)
+ applyTexture(NULL);
+
+ // Re-enable the cache at the end of the draw if it was disabled
+ m_cache.enable = true;
+}
+
+} // namespace sf
+
+
+////////////////////////////////////////////////////////////
+// Render states caching strategies
+//
+// * View
+// If SetView was called since last draw, the projection
+// matrix is updated. We don't need more, the view doesn't
+// change frequently.
+//
+// * Transform
+// The transform matrix is usually expensive because each
+// entity will most likely use a different transform. This can
+// lead, in worst case, to changing it every 4 vertices.
+// To avoid that, when the vertex count is low enough, we
+// pre-transform them and therefore use an identity transform
+// to render them.
+//
+// * Blending mode
+// Since it overloads the == operator, we can easily check
+// whether any of the 6 blending components changed and,
+// thus, whether we need to update the blend mode.
+//
+// * Texture
+// Storing the pointer or OpenGL ID of the last used texture
+// is not enough; if the sf::Texture instance is destroyed,
+// both the pointer and the OpenGL ID might be recycled in
+// a new texture instance. We need to use our own unique
+// identifier system to ensure consistent caching.
+//
+// * Shader
+// Shaders are very hard to optimize, because they have
+// parameters that can be hard (if not impossible) to track,
+// like matrices or textures. The only optimization that we
+// do is that we avoid setting a null shader if there was
+// already none for the previous draw.
+//
+////////////////////////////////////////////////////////////
diff --git a/src/SFML/Graphics/RenderTexture.cpp b/src/SFML/Graphics/RenderTexture.cpp
new file mode 100644
index 0000000..51abee9
--- /dev/null
+++ b/src/SFML/Graphics/RenderTexture.cpp
@@ -0,0 +1,186 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTexture.hpp>
+#include <SFML/Graphics/RenderTextureImplFBO.hpp>
+#include <SFML/Graphics/RenderTextureImplDefault.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+RenderTexture::RenderTexture() :
+m_impl(NULL)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+RenderTexture::~RenderTexture()
+{
+ delete m_impl;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::create(unsigned int width, unsigned int height, bool depthBuffer)
+{
+ return create(width, height, ContextSettings(depthBuffer ? 32 : 0));
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::create(unsigned int width, unsigned int height, const ContextSettings& settings)
+{
+ // Create the texture
+ if (!m_texture.create(width, height))
+ {
+ err() << "Impossible to create render texture (failed to create the target texture)" << std::endl;
+ return false;
+ }
+
+ // We disable smoothing by default for render textures
+ setSmooth(false);
+
+ // Create the implementation
+ delete m_impl;
+ if (priv::RenderTextureImplFBO::isAvailable())
+ {
+ // Use frame-buffer object (FBO)
+ m_impl = new priv::RenderTextureImplFBO;
+
+ // Mark the texture as being a framebuffer object attachment
+ m_texture.m_fboAttachment = true;
+ }
+ else
+ {
+ // Use default implementation
+ m_impl = new priv::RenderTextureImplDefault;
+ }
+
+ // Initialize the render texture
+ if (!m_impl->create(width, height, m_texture.m_texture, settings))
+ return false;
+
+ // We can now initialize the render target part
+ RenderTarget::initialize();
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int RenderTexture::getMaximumAntialiasingLevel()
+{
+ if (priv::RenderTextureImplFBO::isAvailable())
+ {
+ return priv::RenderTextureImplFBO::getMaximumAntialiasingLevel();
+ }
+ else
+ {
+ return priv::RenderTextureImplDefault::getMaximumAntialiasingLevel();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTexture::setSmooth(bool smooth)
+{
+ m_texture.setSmooth(smooth);
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::isSmooth() const
+{
+ return m_texture.isSmooth();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTexture::setRepeated(bool repeated)
+{
+ m_texture.setRepeated(repeated);
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::isRepeated() const
+{
+ return m_texture.isRepeated();
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::generateMipmap()
+{
+ return m_texture.generateMipmap();
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTexture::setActive(bool active)
+{
+ bool result = m_impl && m_impl->activate(active);
+
+ // Update RenderTarget tracking
+ if (result)
+ RenderTarget::setActive(active);
+
+ return result;
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTexture::display()
+{
+ // Update the target texture
+ if (m_impl && (priv::RenderTextureImplFBO::isAvailable() || setActive(true)))
+ {
+ m_impl->updateTexture(m_texture.m_texture);
+ m_texture.m_pixelsFlipped = true;
+ m_texture.invalidateMipmap();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u RenderTexture::getSize() const
+{
+ return m_texture.getSize();
+}
+
+
+////////////////////////////////////////////////////////////
+const Texture& RenderTexture::getTexture() const
+{
+ return m_texture;
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderTextureImpl.cpp b/src/SFML/Graphics/RenderTextureImpl.cpp
new file mode 100644
index 0000000..d1e927c
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImpl.cpp
@@ -0,0 +1,43 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTextureImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+RenderTextureImpl::~RenderTextureImpl()
+{
+ // Nothing to do
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderTextureImpl.hpp b/src/SFML/Graphics/RenderTextureImpl.hpp
new file mode 100644
index 0000000..5a357c7
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImpl.hpp
@@ -0,0 +1,92 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_RENDERTEXTUREIMPL_HPP
+#define SFML_RENDERTEXTUREIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+
+struct ContextSettings;
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Abstract base class for render-texture implementations
+///
+////////////////////////////////////////////////////////////
+class RenderTextureImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~RenderTextureImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the render texture implementation
+ ///
+ /// \param width Width of the texture to render to
+ /// \param height Height of the texture to render to
+ /// \param textureId OpenGL identifier of the target texture
+ /// \param settings Context settings to create render-texture with
+ ///
+ /// \return True if creation has been successful
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate or deactivate the render texture for rendering
+ ///
+ /// \param active True to activate, false to deactivate
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool activate(bool active) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the pixels of the target texture
+ ///
+ /// \param textureId OpenGL identifier of the target texture
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void updateTexture(unsigned int textureId) = 0;
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_RENDERTEXTUREIMPL_HPP
diff --git a/src/SFML/Graphics/RenderTextureImplDefault.cpp b/src/SFML/Graphics/RenderTextureImplDefault.cpp
new file mode 100644
index 0000000..29399d5
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImplDefault.cpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTextureImplDefault.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/Graphics/TextureSaver.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+RenderTextureImplDefault::RenderTextureImplDefault() :
+m_context(0),
+m_width (0),
+m_height (0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+RenderTextureImplDefault::~RenderTextureImplDefault()
+{
+ // Destroy the context
+ delete m_context;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int RenderTextureImplDefault::getMaximumAntialiasingLevel()
+{
+ // If the system is so old that it doesn't support FBOs, chances are it is
+ // also using either a software renderer or some CPU emulated support for AA
+ // In order to not cripple performance in this rare case, we just return 0 here
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplDefault::create(unsigned int width, unsigned int height, unsigned int, const ContextSettings& settings)
+{
+ // Store the dimensions
+ m_width = width;
+ m_height = height;
+
+ // Create the in-memory OpenGL context
+ m_context = new Context(settings, width, height);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplDefault::activate(bool active)
+{
+ return m_context->setActive(active);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTextureImplDefault::updateTexture(unsigned int textureId)
+{
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Copy the rendered pixels to the texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, textureId));
+ glCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height));
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderTextureImplDefault.hpp b/src/SFML/Graphics/RenderTextureImplDefault.hpp
new file mode 100644
index 0000000..c3b59ae
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImplDefault.hpp
@@ -0,0 +1,115 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_RENDERTEXTUREIMPLDEFAULT_HPP
+#define SFML_RENDERTEXTUREIMPLDEFAULT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTextureImpl.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/Window/Context.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Default specialization of RenderTextureImpl,
+/// using an in-memory context
+///
+////////////////////////////////////////////////////////////
+class RenderTextureImplDefault : public RenderTextureImpl, GlResource
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ RenderTextureImplDefault();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~RenderTextureImplDefault();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the maximum anti-aliasing level supported by the system
+ ///
+ /// \return The maximum anti-aliasing level supported by the system
+ ///
+ ////////////////////////////////////////////////////////////
+ static unsigned int getMaximumAntialiasingLevel();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the render texture implementation
+ ///
+ /// \param width Width of the texture to render to
+ /// \param height Height of the texture to render to
+ /// \param textureId OpenGL identifier of the target texture
+ /// \param settings Context settings to create render-texture with
+ ///
+ /// \return True if creation has been successful
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate or deactivate the render texture for rendering
+ ///
+ /// \param active True to activate, false to deactivate
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool activate(bool active);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the pixels of the target texture
+ ///
+ /// \param textureId OpenGL identifier of the target texture
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void updateTexture(unsigned textureId);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Context* m_context; ///< P-Buffer based context
+ unsigned int m_width; ///< Width of the P-Buffer
+ unsigned int m_height; ///< Height of the P-Buffer
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_RENDERTEXTUREIMPLDEFAULT_HPP
diff --git a/src/SFML/Graphics/RenderTextureImplFBO.cpp b/src/SFML/Graphics/RenderTextureImplFBO.cpp
new file mode 100644
index 0000000..c0debd7
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImplFBO.cpp
@@ -0,0 +1,605 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTextureImplFBO.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <utility>
+#include <set>
+
+
+namespace
+{
+ // Set to track all active FBO mappings
+ // This is used to free active FBOs while their owning
+ // RenderTextureImplFBO is still alive
+ std::set<std::map<sf::Uint64, unsigned int>*> frameBuffers;
+
+ // Set to track all stale FBOs
+ // This is used to free stale FBOs after their owning
+ // RenderTextureImplFBO has already been destroyed
+ // An FBO cannot be destroyed until it's containing context
+ // becomes active, so the destruction of the RenderTextureImplFBO
+ // has to be decoupled from the destruction of the FBOs themselves
+ std::set<std::pair<sf::Uint64, unsigned int> > staleFrameBuffers;
+
+ // Mutex to protect both active and stale frame buffer sets
+ sf::Mutex mutex;
+
+ // This function is called either when a RenderTextureImplFBO is
+ // destroyed or via contextDestroyCallback when context destruction
+ // might trigger deletion of its contained stale FBOs
+ void destroyStaleFBOs()
+ {
+ sf::Uint64 contextId = sf::Context::getActiveContextId();
+
+ for (std::set<std::pair<sf::Uint64, unsigned int> >::iterator iter = staleFrameBuffers.begin(); iter != staleFrameBuffers.end();)
+ {
+ if (iter->first == contextId)
+ {
+ GLuint frameBuffer = static_cast<GLuint>(iter->second);
+ glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
+
+ staleFrameBuffers.erase(iter++);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+ }
+
+ // Callback that is called every time a context is destroyed
+ void contextDestroyCallback(void* arg)
+ {
+ sf::Lock lock(mutex);
+
+ sf::Uint64 contextId = sf::Context::getActiveContextId();
+
+ // Destroy active frame buffer objects
+ for (std::set<std::map<sf::Uint64, unsigned int>*>::iterator frameBuffersIter = frameBuffers.begin(); frameBuffersIter != frameBuffers.end(); ++frameBuffersIter)
+ {
+ for (std::map<sf::Uint64, unsigned int>::iterator iter = (*frameBuffersIter)->begin(); iter != (*frameBuffersIter)->end(); ++iter)
+ {
+ if (iter->first == contextId)
+ {
+ GLuint frameBuffer = static_cast<GLuint>(iter->second);
+ glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
+
+ // Erase the entry from the RenderTextureImplFBO's map
+ (*frameBuffersIter)->erase(iter);
+
+ break;
+ }
+ }
+ }
+
+ // Destroy stale frame buffer objects
+ destroyStaleFBOs();
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+RenderTextureImplFBO::RenderTextureImplFBO() :
+m_depthStencilBuffer(0),
+m_colorBuffer (0),
+m_width (0),
+m_height (0),
+m_context (NULL),
+m_textureId (0),
+m_multisample (false),
+m_stencil (false)
+{
+ Lock lock(mutex);
+
+ // Register the context destruction callback
+ registerContextDestroyCallback(contextDestroyCallback, 0);
+
+ // Insert the new frame buffer mapping into the set of all active mappings
+ frameBuffers.insert(&m_frameBuffers);
+ frameBuffers.insert(&m_multisampleFrameBuffers);
+}
+
+
+////////////////////////////////////////////////////////////
+RenderTextureImplFBO::~RenderTextureImplFBO()
+{
+ TransientContextLock contextLock;
+
+ Lock lock(mutex);
+
+ // Remove the frame buffer mapping from the set of all active mappings
+ frameBuffers.erase(&m_frameBuffers);
+ frameBuffers.erase(&m_multisampleFrameBuffers);
+
+ // Destroy the color buffer
+ if (m_colorBuffer)
+ {
+ GLuint colorBuffer = static_cast<GLuint>(m_colorBuffer);
+ glCheck(GLEXT_glDeleteRenderbuffers(1, &colorBuffer));
+ }
+
+ // Destroy the depth/stencil buffer
+ if (m_depthStencilBuffer)
+ {
+ GLuint depthStencilBuffer = static_cast<GLuint>(m_depthStencilBuffer);
+ glCheck(GLEXT_glDeleteRenderbuffers(1, &depthStencilBuffer));
+ }
+
+ // Move all frame buffer objects to stale set
+ for (std::map<Uint64, unsigned int>::iterator iter = m_frameBuffers.begin(); iter != m_frameBuffers.end(); ++iter)
+ staleFrameBuffers.insert(std::make_pair(iter->first, iter->second));
+
+ for (std::map<Uint64, unsigned int>::iterator iter = m_multisampleFrameBuffers.begin(); iter != m_multisampleFrameBuffers.end(); ++iter)
+ staleFrameBuffers.insert(std::make_pair(iter->first, iter->second));
+
+ // Clean up FBOs
+ destroyStaleFBOs();
+
+ // Delete the backup context if we had to create one
+ delete m_context;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplFBO::isAvailable()
+{
+ TransientContextLock lock;
+
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+
+ return GLEXT_framebuffer_object != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int RenderTextureImplFBO::getMaximumAntialiasingLevel()
+{
+ TransientContextLock lock;
+
+ GLint samples = 0;
+
+#ifndef SFML_OPENGL_ES
+
+ glCheck(glGetIntegerv(GLEXT_GL_MAX_SAMPLES, &samples));
+
+#endif
+
+ return static_cast<unsigned int>(samples);
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTextureImplFBO::unbind()
+{
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0));
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplFBO::create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings)
+{
+ // Store the dimensions
+ m_width = width;
+ m_height = height;
+
+ {
+ TransientContextLock lock;
+
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+
+ if (settings.antialiasingLevel && !(GLEXT_framebuffer_multisample && GLEXT_framebuffer_blit))
+ return false;
+
+ if (settings.stencilBits && !GLEXT_packed_depth_stencil)
+ return false;
+
+#ifndef SFML_OPENGL_ES
+
+ // Check if the requested anti-aliasing level is supported
+ if (settings.antialiasingLevel)
+ {
+ GLint samples = 0;
+ glCheck(glGetIntegerv(GLEXT_GL_MAX_SAMPLES, &samples));
+
+ if (settings.antialiasingLevel > static_cast<unsigned int>(samples))
+ {
+ err() << "Impossible to create render texture (unsupported anti-aliasing level)";
+ err() << " Requested: " << settings.antialiasingLevel << " Maximum supported: " << samples << std::endl;
+ return false;
+ }
+ }
+
+#endif
+
+
+ if (!settings.antialiasingLevel)
+ {
+ // Create the depth/stencil buffer if requested
+ if (settings.stencilBits)
+ {
+
+#ifndef SFML_OPENGL_ES
+
+ GLuint depthStencil = 0;
+ glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
+ m_depthStencilBuffer = static_cast<unsigned int>(depthStencil);
+ if (!m_depthStencilBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER, GLEXT_GL_DEPTH24_STENCIL8, width, height));
+
+#else
+
+ err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)" << std::endl;
+ return false;
+
+#endif // SFML_OPENGL_ES
+
+ m_stencil = true;
+
+ }
+ else if (settings.depthBits)
+ {
+ GLuint depthStencil = 0;
+ glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
+ m_depthStencilBuffer = static_cast<unsigned int>(depthStencil);
+ if (!m_depthStencilBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the attached depth buffer)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER, GLEXT_GL_DEPTH_COMPONENT, width, height));
+ }
+ }
+ else
+ {
+
+#ifndef SFML_OPENGL_ES
+
+ // Create the multisample color buffer
+ GLuint color = 0;
+ glCheck(GLEXT_glGenRenderbuffers(1, &color));
+ m_colorBuffer = static_cast<unsigned int>(color);
+ if (!m_colorBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the attached multisample color buffer)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_colorBuffer));
+ glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GL_RGBA, width, height));
+
+ // Create the multisample depth/stencil buffer if requested
+ if (settings.stencilBits)
+ {
+ GLuint depthStencil = 0;
+ glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
+ m_depthStencilBuffer = static_cast<unsigned int>(depthStencil);
+ if (!m_depthStencilBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the attached multisample depth/stencil buffer)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GLEXT_GL_DEPTH24_STENCIL8, width, height));
+
+ m_stencil = true;
+ }
+ else if (settings.depthBits)
+ {
+ GLuint depthStencil = 0;
+ glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
+ m_depthStencilBuffer = static_cast<unsigned int>(depthStencil);
+ if (!m_depthStencilBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the attached multisample depth buffer)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GLEXT_GL_DEPTH_COMPONENT, width, height));
+ }
+
+#else
+
+ err() << "Impossible to create render texture (failed to create the multisample render buffers)" << std::endl;
+ return false;
+
+#endif // SFML_OPENGL_ES
+
+ m_multisample = true;
+
+ }
+ }
+
+ // Save our texture ID in order to be able to attach it to an FBO at any time
+ m_textureId = textureId;
+
+ // We can't create an FBO now if there is no active context
+ if (!Context::getActiveContextId())
+ return true;
+
+#ifndef SFML_OPENGL_ES
+
+ // Save the current bindings so we can restore them after we are done
+ GLint readFramebuffer = 0;
+ GLint drawFramebuffer = 0;
+
+ glCheck(glGetIntegerv(GLEXT_GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer));
+ glCheck(glGetIntegerv(GLEXT_GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer));
+
+ if (createFrameBuffer())
+ {
+ // Restore previously bound framebuffers
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, readFramebuffer));
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, drawFramebuffer));
+
+ return true;
+ }
+
+#else
+
+ // Save the current binding so we can restore them after we are done
+ GLint frameBuffer = 0;
+
+ glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, &frameBuffer));
+
+ if (createFrameBuffer())
+ {
+ // Restore previously bound framebuffer
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
+
+ return true;
+ }
+
+#endif
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplFBO::createFrameBuffer()
+{
+ // Create the framebuffer object
+ GLuint frameBuffer = 0;
+ glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer));
+
+ if (!frameBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
+
+ // Link the depth/stencil renderbuffer to the frame buffer
+ if (!m_multisample && m_depthStencilBuffer)
+ {
+ glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+
+#ifndef SFML_OPENGL_ES
+
+ if (m_stencil)
+ {
+ glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_STENCIL_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ }
+
+#endif
+
+ }
+
+ // Link the texture to the frame buffer
+ glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textureId, 0));
+
+ // A final check, just to be sure...
+ GLenum status;
+ glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER));
+ if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE)
+ {
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0));
+ glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
+ err() << "Impossible to create render texture (failed to link the target texture to the frame buffer)" << std::endl;
+ return false;
+ }
+
+ {
+ Lock lock(mutex);
+
+ // Insert the FBO into our map
+ m_frameBuffers.insert(std::make_pair(Context::getActiveContextId(), static_cast<unsigned int>(frameBuffer)));
+ }
+
+#ifndef SFML_OPENGL_ES
+
+ if (m_multisample)
+ {
+ // Create the multisample framebuffer object
+ GLuint multisampleFrameBuffer = 0;
+ glCheck(GLEXT_glGenFramebuffers(1, &multisampleFrameBuffer));
+
+ if (!multisampleFrameBuffer)
+ {
+ err() << "Impossible to create render texture (failed to create the multisample frame buffer object)" << std::endl;
+ return false;
+ }
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, multisampleFrameBuffer));
+
+ // Link the multisample color buffer to the frame buffer
+ glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_colorBuffer));
+ glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GLEXT_GL_RENDERBUFFER, m_colorBuffer));
+
+ // Link the depth/stencil renderbuffer to the frame buffer
+ if (m_depthStencilBuffer)
+ {
+ glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+
+ if (m_stencil)
+ {
+ glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_STENCIL_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
+ }
+ }
+
+ // A final check, just to be sure...
+ glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER));
+ if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE)
+ {
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0));
+ glCheck(GLEXT_glDeleteFramebuffers(1, &multisampleFrameBuffer));
+ err() << "Impossible to create render texture (failed to link the render buffers to the multisample frame buffer)" << std::endl;
+ return false;
+ }
+
+ {
+ Lock lock(mutex);
+
+ // Insert the FBO into our map
+ m_multisampleFrameBuffers.insert(std::make_pair(Context::getActiveContextId(), static_cast<unsigned int>(multisampleFrameBuffer)));
+ }
+ }
+
+#endif
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderTextureImplFBO::activate(bool active)
+{
+ // Unbind the FBO if requested
+ if (!active)
+ {
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0));
+ return true;
+ }
+
+ Uint64 contextId = Context::getActiveContextId();
+
+ // In the odd case we have to activate and there is no active
+ // context yet, we have to create one
+ if (!contextId)
+ {
+ if (!m_context)
+ m_context = new Context;
+
+ m_context->setActive(true);
+
+ contextId = Context::getActiveContextId();
+
+ if (!contextId)
+ {
+ err() << "Impossible to activate render texture (failed to create backup context)" << std::endl;
+
+ return false;
+ }
+ }
+
+ // Lookup the FBO corresponding to the currently active context
+ // If none is found, there is no FBO corresponding to the
+ // currently active context so we will have to create a new FBO
+ {
+ Lock lock(mutex);
+
+ std::map<Uint64, unsigned int>::iterator iter;
+
+ if (m_multisample)
+ {
+ iter = m_multisampleFrameBuffers.find(contextId);
+
+ if (iter != m_multisampleFrameBuffers.end())
+ {
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, iter->second));
+
+ return true;
+ }
+ }
+ else
+ {
+ iter = m_frameBuffers.find(contextId);
+
+ if (iter != m_frameBuffers.end())
+ {
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, iter->second));
+
+ return true;
+ }
+ }
+ }
+
+ return createFrameBuffer();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderTextureImplFBO::updateTexture(unsigned int)
+{
+ // If multisampling is enabled, we need to resolve by blitting
+ // from our FBO with multisample renderbuffer attachments
+ // to our FBO to which our target texture is attached
+
+#ifndef SFML_OPENGL_ES
+
+ // In case of multisampling, make sure both FBOs
+ // are already available within the current context
+ if (m_multisample && m_width && m_height && activate(true))
+ {
+ Uint64 contextId = Context::getActiveContextId();
+
+ Lock lock(mutex);
+
+ std::map<Uint64, unsigned int>::iterator iter = m_frameBuffers.find(contextId);
+ std::map<Uint64, unsigned int>::iterator multisampleIter = m_multisampleFrameBuffers.find(contextId);
+
+ if ((iter != m_frameBuffers.end()) && (multisampleIter != m_multisampleFrameBuffers.end()))
+ {
+ // Set up the blit target (draw framebuffer) and blit (from the read framebuffer, our multisample FBO)
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, iter->second));
+ glCheck(GLEXT_glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, multisampleIter->second));
+ }
+ }
+
+#endif // SFML_OPENGL_ES
+
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/RenderTextureImplFBO.hpp b/src/SFML/Graphics/RenderTextureImplFBO.hpp
new file mode 100644
index 0000000..f83074e
--- /dev/null
+++ b/src/SFML/Graphics/RenderTextureImplFBO.hpp
@@ -0,0 +1,145 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_RENDERTEXTUREIMPLFBO_HPP
+#define SFML_RENDERTEXTUREIMPLFBO_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderTextureImpl.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <map>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Specialization of RenderTextureImpl using the
+/// FrameBuffer Object OpenGL extension
+///
+////////////////////////////////////////////////////////////
+class RenderTextureImplFBO : public RenderTextureImpl, GlResource
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ RenderTextureImplFBO();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~RenderTextureImplFBO();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the system supports FBOs or not
+ ///
+ /// \return True if FBO render textures are supported
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the maximum anti-aliasing level supported by the system
+ ///
+ /// \return The maximum anti-aliasing level supported by the system
+ ///
+ ////////////////////////////////////////////////////////////
+ static unsigned int getMaximumAntialiasingLevel();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unbind the currently bound FBO
+ ///
+ ////////////////////////////////////////////////////////////
+ static void unbind();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the render texture implementation
+ ///
+ /// \param width Width of the texture to render to
+ /// \param height Height of the texture to render to
+ /// \param textureId OpenGL identifier of the target texture
+ /// \param settings Context settings to create render-texture with
+ ///
+ /// \return True if creation has been successful
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create an FBO in the current context
+ ///
+ /// \return True if creation has been successful
+ ///
+ ////////////////////////////////////////////////////////////
+ bool createFrameBuffer();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate or deactivate the render texture for rendering
+ ///
+ /// \param active True to activate, false to deactivate
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool activate(bool active);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the pixels of the target texture
+ ///
+ /// \param textureId OpenGL identifier of the target texture
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void updateTexture(unsigned textureId);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ std::map<Uint64, unsigned int> m_frameBuffers; ///< OpenGL frame buffer objects per context
+ std::map<Uint64, unsigned int> m_multisampleFrameBuffers; ///< Optional per-context OpenGL frame buffer objects with multisample attachments
+ unsigned int m_depthStencilBuffer; ///< Optional depth/stencil buffer attached to the frame buffer
+ unsigned int m_colorBuffer; ///< Optional multisample color buffer attached to the frame buffer
+ unsigned int m_width; ///< Width of the attachments
+ unsigned int m_height; ///< Height of the attachments
+ Context* m_context; ///< Backup OpenGL context, used when none already exist
+ unsigned int m_textureId; ///< The ID of the texture to attach to the FBO
+ bool m_multisample; ///< Whether we have to create a multisample frame buffer as well
+ bool m_stencil; ///< Whether we have stencil attachment
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_RENDERTEXTUREIMPLFBO_HPP
diff --git a/src/SFML/Graphics/RenderWindow.cpp b/src/SFML/Graphics/RenderWindow.cpp
new file mode 100644
index 0000000..446e906
--- /dev/null
+++ b/src/SFML/Graphics/RenderWindow.cpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/RenderWindow.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/Graphics/RenderTextureImplFBO.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+RenderWindow::RenderWindow()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+RenderWindow::RenderWindow(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
+{
+ // Don't call the base class constructor because it contains virtual function calls
+ create(mode, title, style, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+RenderWindow::RenderWindow(WindowHandle handle, const ContextSettings& settings)
+{
+ // Don't call the base class constructor because it contains virtual function calls
+ create(handle, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+RenderWindow::~RenderWindow()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u RenderWindow::getSize() const
+{
+ return Window::getSize();
+}
+
+
+////////////////////////////////////////////////////////////
+bool RenderWindow::setActive(bool active)
+{
+ bool result = Window::setActive(active);
+
+ // Update RenderTarget tracking
+ if (result)
+ RenderTarget::setActive(active);
+
+ // If FBOs are available, make sure none are bound when we
+ // try to draw to the default framebuffer of the RenderWindow
+ if (active && result && priv::RenderTextureImplFBO::isAvailable())
+ {
+ priv::RenderTextureImplFBO::unbind();
+
+ return true;
+ }
+
+ return result;
+}
+
+
+////////////////////////////////////////////////////////////
+Image RenderWindow::capture() const
+{
+ Vector2u windowSize = getSize();
+
+ Texture texture;
+ texture.create(windowSize.x, windowSize.y);
+ texture.update(*this);
+
+ return texture.copyToImage();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderWindow::onCreate()
+{
+ // Just initialize the render target part
+ RenderTarget::initialize();
+}
+
+
+////////////////////////////////////////////////////////////
+void RenderWindow::onResize()
+{
+ // Update the current view (recompute the viewport, which is stored in relative coordinates)
+ setView(getView());
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp
new file mode 100644
index 0000000..353a72d
--- /dev/null
+++ b/src/SFML/Graphics/Shader.cpp
@@ -0,0 +1,1334 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Shader.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/Transform.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <fstream>
+#include <vector>
+
+
+#ifndef SFML_OPENGL_ES
+
+#if defined(SFML_SYSTEM_MACOS) || defined(SFML_SYSTEM_IOS)
+
+ #define castToGlHandle(x) reinterpret_cast<GLEXT_GLhandle>(static_cast<ptrdiff_t>(x))
+ #define castFromGlHandle(x) static_cast<unsigned int>(reinterpret_cast<ptrdiff_t>(x))
+
+#else
+
+ #define castToGlHandle(x) (x)
+ #define castFromGlHandle(x) (x)
+
+#endif
+
+namespace
+{
+ sf::Mutex maxTextureUnitsMutex;
+ sf::Mutex isAvailableMutex;
+
+ GLint checkMaxTextureUnits()
+ {
+ GLint maxUnits = 0;
+ glCheck(glGetIntegerv(GLEXT_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits));
+
+ return maxUnits;
+ }
+
+ // Retrieve the maximum number of texture units available
+ GLint getMaxTextureUnits()
+ {
+ // TODO: Remove this lock when it becomes unnecessary in C++11
+ sf::Lock lock(maxTextureUnitsMutex);
+
+ static GLint maxUnits = checkMaxTextureUnits();
+
+ return maxUnits;
+ }
+
+ // Read the contents of a file into an array of char
+ bool getFileContents(const std::string& filename, std::vector<char>& buffer)
+ {
+ std::ifstream file(filename.c_str(), std::ios_base::binary);
+ if (file)
+ {
+ file.seekg(0, std::ios_base::end);
+ std::streamsize size = file.tellg();
+ if (size > 0)
+ {
+ file.seekg(0, std::ios_base::beg);
+ buffer.resize(static_cast<std::size_t>(size));
+ file.read(&buffer[0], size);
+ }
+ buffer.push_back('\0');
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Read the contents of a stream into an array of char
+ bool getStreamContents(sf::InputStream& stream, std::vector<char>& buffer)
+ {
+ bool success = true;
+ sf::Int64 size = stream.getSize();
+ if (size > 0)
+ {
+ buffer.resize(static_cast<std::size_t>(size));
+ stream.seek(0);
+ sf::Int64 read = stream.read(&buffer[0], size);
+ success = (read == size);
+ }
+ buffer.push_back('\0');
+ return success;
+ }
+
+ // Transforms an array of 2D vectors into a contiguous array of scalars
+ template <typename T>
+ std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length)
+ {
+ const std::size_t vectorSize = 2;
+
+ std::vector<T> contiguous(vectorSize * length);
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ contiguous[vectorSize * i] = vectorArray[i].x;
+ contiguous[vectorSize * i + 1] = vectorArray[i].y;
+ }
+
+ return contiguous;
+ }
+
+ // Transforms an array of 3D vectors into a contiguous array of scalars
+ template <typename T>
+ std::vector<T> flatten(const sf::Vector3<T>* vectorArray, std::size_t length)
+ {
+ const std::size_t vectorSize = 3;
+
+ std::vector<T> contiguous(vectorSize * length);
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ contiguous[vectorSize * i] = vectorArray[i].x;
+ contiguous[vectorSize * i + 1] = vectorArray[i].y;
+ contiguous[vectorSize * i + 2] = vectorArray[i].z;
+ }
+
+ return contiguous;
+ }
+
+ // Transforms an array of 4D vectors into a contiguous array of scalars
+ template <typename T>
+ std::vector<T> flatten(const sf::priv::Vector4<T>* vectorArray, std::size_t length)
+ {
+ const std::size_t vectorSize = 4;
+
+ std::vector<T> contiguous(vectorSize * length);
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ contiguous[vectorSize * i] = vectorArray[i].x;
+ contiguous[vectorSize * i + 1] = vectorArray[i].y;
+ contiguous[vectorSize * i + 2] = vectorArray[i].z;
+ contiguous[vectorSize * i + 3] = vectorArray[i].w;
+ }
+
+ return contiguous;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Shader::CurrentTextureType Shader::CurrentTexture;
+
+
+////////////////////////////////////////////////////////////
+struct Shader::UniformBinder : private NonCopyable
+{
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor: set up state before uniform is set
+ ///
+ ////////////////////////////////////////////////////////////
+ UniformBinder(Shader& shader, const std::string& name) :
+ savedProgram(0),
+ currentProgram(castToGlHandle(shader.m_shaderProgram)),
+ location(-1)
+ {
+ if (currentProgram)
+ {
+ // Enable program object
+ glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT));
+ if (currentProgram != savedProgram)
+ glCheck(GLEXT_glUseProgramObject(currentProgram));
+
+ // Store uniform location for further use outside constructor
+ location = shader.getUniformLocation(name);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor: restore state after uniform is set
+ ///
+ ////////////////////////////////////////////////////////////
+ ~UniformBinder()
+ {
+ // Disable program object
+ if (currentProgram && (currentProgram != savedProgram))
+ glCheck(GLEXT_glUseProgramObject(savedProgram));
+ }
+
+ TransientContextLock lock; ///< Lock to keep context active while uniform is bound
+ GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object
+ GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance
+ GLint location; ///< Uniform location, used by the surrounding sf::Shader code
+};
+
+
+////////////////////////////////////////////////////////////
+Shader::Shader() :
+m_shaderProgram (0),
+m_currentTexture(-1),
+m_textures (),
+m_uniforms ()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Shader::~Shader()
+{
+ TransientContextLock lock;
+
+ // Destroy effect program
+ if (m_shaderProgram)
+ glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram)));
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& filename, Type type)
+{
+ // Read the file
+ std::vector<char> shader;
+ if (!getFileContents(filename, shader))
+ {
+ err() << "Failed to open shader file \"" << filename << "\"" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ if (type == Vertex)
+ return compile(&shader[0], NULL, NULL);
+ else if (type == Geometry)
+ return compile(NULL, &shader[0], NULL);
+ else
+ return compile(NULL, NULL, &shader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename)
+{
+ // Read the vertex shader file
+ std::vector<char> vertexShader;
+ if (!getFileContents(vertexShaderFilename, vertexShader))
+ {
+ err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl;
+ return false;
+ }
+
+ // Read the fragment shader file
+ std::vector<char> fragmentShader;
+ if (!getFileContents(fragmentShaderFilename, fragmentShader))
+ {
+ err() << "Failed to open fragment shader file \"" << fragmentShaderFilename << "\"" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ return compile(&vertexShader[0], NULL, &fragmentShader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename)
+{
+ // Read the vertex shader file
+ std::vector<char> vertexShader;
+ if (!getFileContents(vertexShaderFilename, vertexShader))
+ {
+ err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl;
+ return false;
+ }
+
+ // Read the geometry shader file
+ std::vector<char> geometryShader;
+ if (!getFileContents(geometryShaderFilename, geometryShader))
+ {
+ err() << "Failed to open geometry shader file \"" << geometryShaderFilename << "\"" << std::endl;
+ return false;
+ }
+
+ // Read the fragment shader file
+ std::vector<char> fragmentShader;
+ if (!getFileContents(fragmentShaderFilename, fragmentShader))
+ {
+ err() << "Failed to open fragment shader file \"" << fragmentShaderFilename << "\"" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ return compile(&vertexShader[0], &geometryShader[0], &fragmentShader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& shader, Type type)
+{
+ // Compile the shader program
+ if (type == Vertex)
+ return compile(shader.c_str(), NULL, NULL);
+ else if (type == Geometry)
+ return compile(NULL, shader.c_str(), NULL);
+ else
+ return compile(NULL, NULL, shader.c_str());
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader)
+{
+ // Compile the shader program
+ return compile(vertexShader.c_str(), NULL, fragmentShader.c_str());
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader)
+{
+ // Compile the shader program
+ return compile(vertexShader.c_str(), geometryShader.c_str(), fragmentShader.c_str());
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& stream, Type type)
+{
+ // Read the shader code from the stream
+ std::vector<char> shader;
+ if (!getStreamContents(stream, shader))
+ {
+ err() << "Failed to read shader from stream" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ if (type == Vertex)
+ return compile(&shader[0], NULL, NULL);
+ else if (type == Geometry)
+ return compile(NULL, &shader[0], NULL);
+ else
+ return compile(NULL, NULL, &shader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream)
+{
+ // Read the vertex shader code from the stream
+ std::vector<char> vertexShader;
+ if (!getStreamContents(vertexShaderStream, vertexShader))
+ {
+ err() << "Failed to read vertex shader from stream" << std::endl;
+ return false;
+ }
+
+ // Read the fragment shader code from the stream
+ std::vector<char> fragmentShader;
+ if (!getStreamContents(fragmentShaderStream, fragmentShader))
+ {
+ err() << "Failed to read fragment shader from stream" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ return compile(&vertexShader[0], NULL, &fragmentShader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream)
+{
+ // Read the vertex shader code from the stream
+ std::vector<char> vertexShader;
+ if (!getStreamContents(vertexShaderStream, vertexShader))
+ {
+ err() << "Failed to read vertex shader from stream" << std::endl;
+ return false;
+ }
+
+ // Read the geometry shader code from the stream
+ std::vector<char> geometryShader;
+ if (!getStreamContents(geometryShaderStream, geometryShader))
+ {
+ err() << "Failed to read geometry shader from stream" << std::endl;
+ return false;
+ }
+
+ // Read the fragment shader code from the stream
+ std::vector<char> fragmentShader;
+ if (!getStreamContents(fragmentShaderStream, fragmentShader))
+ {
+ err() << "Failed to read fragment shader from stream" << std::endl;
+ return false;
+ }
+
+ // Compile the shader program
+ return compile(&vertexShader[0], &geometryShader[0], &fragmentShader[0]);
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, float x)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform1f(binder.location, x));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec2& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform2f(binder.location, v.x, v.y));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec3& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform3f(binder.location, v.x, v.y, v.z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec4& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform4f(binder.location, v.x, v.y, v.z, v.w));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, int x)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform1i(binder.location, x));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec2& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform2i(binder.location, v.x, v.y));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec3& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform3i(binder.location, v.x, v.y, v.z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec4& v)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform4i(binder.location, v.x, v.y, v.z, v.w));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, bool x)
+{
+ setUniform(name, static_cast<int>(x));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec2& v)
+{
+ setUniform(name, Glsl::Ivec2(v));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec3& v)
+{
+ setUniform(name, Glsl::Ivec3(v));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec4& v)
+{
+ setUniform(name, Glsl::Ivec4(v));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Mat3& matrix)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniformMatrix3fv(binder.location, 1, GL_FALSE, matrix.array));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Mat4& matrix)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniformMatrix4fv(binder.location, 1, GL_FALSE, matrix.array));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Texture& texture)
+{
+ if (m_shaderProgram)
+ {
+ TransientContextLock lock;
+
+ // Find the location of the variable in the shader
+ int location = getUniformLocation(name);
+ if (location != -1)
+ {
+ // Store the location -> texture mapping
+ TextureTable::iterator it = m_textures.find(location);
+ if (it == m_textures.end())
+ {
+ // New entry, make sure there are enough texture units
+ GLint maxUnits = getMaxTextureUnits();
+ if (m_textures.size() + 1 >= static_cast<std::size_t>(maxUnits))
+ {
+ err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl;
+ return;
+ }
+
+ m_textures[location] = &texture;
+ }
+ else
+ {
+ // Location already used, just replace the texture
+ it->second = &texture;
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, CurrentTextureType)
+{
+ if (m_shaderProgram)
+ {
+ TransientContextLock lock;
+
+ // Find the location of the variable in the shader
+ m_currentTexture = getUniformLocation(name);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const float* scalarArray, std::size_t length)
+{
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform1fv(binder.location, static_cast<GLsizei>(length), scalarArray));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length)
+{
+ std::vector<float> contiguous = flatten(vectorArray, length);
+
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform2fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length)
+{
+ std::vector<float> contiguous = flatten(vectorArray, length);
+
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform3fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length)
+{
+ std::vector<float> contiguous = flatten(vectorArray, length);
+
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniform4fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length)
+{
+ const std::size_t matrixSize = 3 * 3;
+
+ std::vector<float> contiguous(matrixSize * length);
+ for (std::size_t i = 0; i < length; ++i)
+ priv::copyMatrix(matrixArray[i].array, matrixSize, &contiguous[matrixSize * i]);
+
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniformMatrix3fv(binder.location, static_cast<GLsizei>(length), GL_FALSE, &contiguous[0]));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length)
+{
+ const std::size_t matrixSize = 4 * 4;
+
+ std::vector<float> contiguous(matrixSize * length);
+ for (std::size_t i = 0; i < length; ++i)
+ priv::copyMatrix(matrixArray[i].array, matrixSize, &contiguous[matrixSize * i]);
+
+ UniformBinder binder(*this, name);
+ if (binder.location != -1)
+ glCheck(GLEXT_glUniformMatrix4fv(binder.location, static_cast<GLsizei>(length), GL_FALSE, &contiguous[0]));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x)
+{
+ setUniform(name, x);
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y)
+{
+ setUniform(name, Glsl::Vec2(x, y));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y, float z)
+{
+ setUniform(name, Glsl::Vec3(x, y, z));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y, float z, float w)
+{
+ setUniform(name, Glsl::Vec4(x, y, z, w));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Vector2f& v)
+{
+ setUniform(name, v);
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Vector3f& v)
+{
+ setUniform(name, v);
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Color& color)
+{
+ setUniform(name, Glsl::Vec4(color));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Transform& transform)
+{
+ setUniform(name, Glsl::Mat4(transform));
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Texture& texture)
+{
+ setUniform(name, texture);
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, CurrentTextureType)
+{
+ setUniform(name, CurrentTexture);
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Shader::getNativeHandle() const
+{
+ return m_shaderProgram;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::bind(const Shader* shader)
+{
+ TransientContextLock lock;
+
+ // Make sure that we can use shaders
+ if (!isAvailable())
+ {
+ err() << "Failed to bind or unbind shader: your system doesn't support shaders "
+ << "(you should test Shader::isAvailable() before trying to use the Shader class)" << std::endl;
+ return;
+ }
+
+ if (shader && shader->m_shaderProgram)
+ {
+ // Enable the program
+ glCheck(GLEXT_glUseProgramObject(castToGlHandle(shader->m_shaderProgram)));
+
+ // Bind the textures
+ shader->bindTextures();
+
+ // Bind the current texture
+ if (shader->m_currentTexture != -1)
+ glCheck(GLEXT_glUniform1i(shader->m_currentTexture, 0));
+ }
+ else
+ {
+ // Bind no shader
+ glCheck(GLEXT_glUseProgramObject(0));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::isAvailable()
+{
+ Lock lock(isAvailableMutex);
+
+ static bool checked = false;
+ static bool available = false;
+
+ if (!checked)
+ {
+ checked = true;
+
+ TransientContextLock contextLock;
+
+ // Make sure that extensions are initialized
+ sf::priv::ensureExtensionsInit();
+
+ available = GLEXT_multitexture &&
+ GLEXT_shading_language_100 &&
+ GLEXT_shader_objects &&
+ GLEXT_vertex_shader &&
+ GLEXT_fragment_shader;
+ }
+
+ return available;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::isGeometryAvailable()
+{
+ Lock lock(isAvailableMutex);
+
+ static bool checked = false;
+ static bool available = false;
+
+ if (!checked)
+ {
+ checked = true;
+
+ TransientContextLock contextLock;
+
+ // Make sure that extensions are initialized
+ sf::priv::ensureExtensionsInit();
+
+ available = isAvailable() && GLEXT_geometry_shader4;
+ }
+
+ return available;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
+{
+ TransientContextLock lock;
+
+ // First make sure that we can use shaders
+ if (!isAvailable())
+ {
+ err() << "Failed to create a shader: your system doesn't support shaders "
+ << "(you should test Shader::isAvailable() before trying to use the Shader class)" << std::endl;
+ return false;
+ }
+
+ // Make sure we can use geometry shaders
+ if (geometryShaderCode && !isGeometryAvailable())
+ {
+ err() << "Failed to create a shader: your system doesn't support geometry shaders "
+ << "(you should test Shader::isGeometryAvailable() before trying to use geometry shaders)" << std::endl;
+ return false;
+ }
+
+ // Destroy the shader if it was already created
+ if (m_shaderProgram)
+ {
+ glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram)));
+ m_shaderProgram = 0;
+ }
+
+ // Reset the internal state
+ m_currentTexture = -1;
+ m_textures.clear();
+ m_uniforms.clear();
+
+ // Create the program
+ GLEXT_GLhandle shaderProgram;
+ glCheck(shaderProgram = GLEXT_glCreateProgramObject());
+
+ // Create the vertex shader if needed
+ if (vertexShaderCode)
+ {
+ // Create and compile the shader
+ GLEXT_GLhandle vertexShader;
+ glCheck(vertexShader = GLEXT_glCreateShaderObject(GLEXT_GL_VERTEX_SHADER));
+ glCheck(GLEXT_glShaderSource(vertexShader, 1, &vertexShaderCode, NULL));
+ glCheck(GLEXT_glCompileShader(vertexShader));
+
+ // Check the compile log
+ GLint success;
+ glCheck(GLEXT_glGetObjectParameteriv(vertexShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
+ if (success == GL_FALSE)
+ {
+ char log[1024];
+ glCheck(GLEXT_glGetInfoLog(vertexShader, sizeof(log), 0, log));
+ err() << "Failed to compile vertex shader:" << std::endl
+ << log << std::endl;
+ glCheck(GLEXT_glDeleteObject(vertexShader));
+ glCheck(GLEXT_glDeleteObject(shaderProgram));
+ return false;
+ }
+
+ // Attach the shader to the program, and delete it (not needed anymore)
+ glCheck(GLEXT_glAttachObject(shaderProgram, vertexShader));
+ glCheck(GLEXT_glDeleteObject(vertexShader));
+ }
+
+ // Create the geometry shader if needed
+ if (geometryShaderCode)
+ {
+ // Create and compile the shader
+ GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER);
+ glCheck(GLEXT_glShaderSource(geometryShader, 1, &geometryShaderCode, NULL));
+ glCheck(GLEXT_glCompileShader(geometryShader));
+
+ // Check the compile log
+ GLint success;
+ glCheck(GLEXT_glGetObjectParameteriv(geometryShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
+ if (success == GL_FALSE)
+ {
+ char log[1024];
+ glCheck(GLEXT_glGetInfoLog(geometryShader, sizeof(log), 0, log));
+ err() << "Failed to compile geometry shader:" << std::endl
+ << log << std::endl;
+ glCheck(GLEXT_glDeleteObject(geometryShader));
+ glCheck(GLEXT_glDeleteObject(shaderProgram));
+ return false;
+ }
+
+ // Attach the shader to the program, and delete it (not needed anymore)
+ glCheck(GLEXT_glAttachObject(shaderProgram, geometryShader));
+ glCheck(GLEXT_glDeleteObject(geometryShader));
+ }
+
+ // Create the fragment shader if needed
+ if (fragmentShaderCode)
+ {
+ // Create and compile the shader
+ GLEXT_GLhandle fragmentShader;
+ glCheck(fragmentShader = GLEXT_glCreateShaderObject(GLEXT_GL_FRAGMENT_SHADER));
+ glCheck(GLEXT_glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL));
+ glCheck(GLEXT_glCompileShader(fragmentShader));
+
+ // Check the compile log
+ GLint success;
+ glCheck(GLEXT_glGetObjectParameteriv(fragmentShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
+ if (success == GL_FALSE)
+ {
+ char log[1024];
+ glCheck(GLEXT_glGetInfoLog(fragmentShader, sizeof(log), 0, log));
+ err() << "Failed to compile fragment shader:" << std::endl
+ << log << std::endl;
+ glCheck(GLEXT_glDeleteObject(fragmentShader));
+ glCheck(GLEXT_glDeleteObject(shaderProgram));
+ return false;
+ }
+
+ // Attach the shader to the program, and delete it (not needed anymore)
+ glCheck(GLEXT_glAttachObject(shaderProgram, fragmentShader));
+ glCheck(GLEXT_glDeleteObject(fragmentShader));
+ }
+
+ // Link the program
+ glCheck(GLEXT_glLinkProgram(shaderProgram));
+
+ // Check the link log
+ GLint success;
+ glCheck(GLEXT_glGetObjectParameteriv(shaderProgram, GLEXT_GL_OBJECT_LINK_STATUS, &success));
+ if (success == GL_FALSE)
+ {
+ char log[1024];
+ glCheck(GLEXT_glGetInfoLog(shaderProgram, sizeof(log), 0, log));
+ err() << "Failed to link shader:" << std::endl
+ << log << std::endl;
+ glCheck(GLEXT_glDeleteObject(shaderProgram));
+ return false;
+ }
+
+ m_shaderProgram = castFromGlHandle(shaderProgram);
+
+ // Force an OpenGL flush, so that the shader will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::bindTextures() const
+{
+ TextureTable::const_iterator it = m_textures.begin();
+ for (std::size_t i = 0; i < m_textures.size(); ++i)
+ {
+ GLint index = static_cast<GLsizei>(i + 1);
+ glCheck(GLEXT_glUniform1i(it->first, index));
+ glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0 + index));
+ Texture::bind(it->second);
+ ++it;
+ }
+
+ // Make sure that the texture unit which is left active is the number 0
+ glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0));
+}
+
+
+////////////////////////////////////////////////////////////
+int Shader::getUniformLocation(const std::string& name)
+{
+ // Check the cache
+ UniformTable::const_iterator it = m_uniforms.find(name);
+ if (it != m_uniforms.end())
+ {
+ // Already in cache, return it
+ return it->second;
+ }
+ else
+ {
+ // Not in cache, request the location from OpenGL
+ int location = GLEXT_glGetUniformLocation(castToGlHandle(m_shaderProgram), name.c_str());
+ m_uniforms.insert(std::make_pair(name, location));
+
+ if (location == -1)
+ err() << "Uniform \"" << name << "\" not found in shader" << std::endl;
+
+ return location;
+ }
+}
+
+} // namespace sf
+
+#else // SFML_OPENGL_ES
+
+// OpenGL ES 1 doesn't support GLSL shaders at all, we have to provide an empty implementation
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Shader::CurrentTextureType Shader::CurrentTexture;
+
+
+////////////////////////////////////////////////////////////
+Shader::Shader() :
+m_shaderProgram (0),
+m_currentTexture(-1)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Shader::~Shader()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& filename, Type type)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& shader, Type type)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& stream, Type type)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, float x)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec2& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec3& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Vec4& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, int x)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec2& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec3& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Ivec4& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, bool x)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec2& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec3& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Bvec4& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Mat3& matrix)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Glsl::Mat4& matrix)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, const Texture& texture)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniform(const std::string& name, CurrentTextureType)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const float* scalarArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y, float z)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, float x, float y, float z, float w)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Vector2f& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Vector3f& v)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Color& color)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Transform& transform)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, const Texture& texture)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::setParameter(const std::string& name, CurrentTextureType)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Shader::getNativeHandle() const
+{
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::bind(const Shader* shader)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::isAvailable()
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::isGeometryAvailable()
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
+{
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shader::bindTextures() const
+{
+}
+
+} // namespace sf
+
+#endif // SFML_OPENGL_ES
diff --git a/src/SFML/Graphics/Shape.cpp b/src/SFML/Graphics/Shape.cpp
new file mode 100644
index 0000000..545b6fa
--- /dev/null
+++ b/src/SFML/Graphics/Shape.cpp
@@ -0,0 +1,313 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Shape.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/System/Err.hpp>
+#include <cmath>
+
+
+namespace
+{
+ // Compute the normal of a segment
+ sf::Vector2f computeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2)
+ {
+ sf::Vector2f normal(p1.y - p2.y, p2.x - p1.x);
+ float length = std::sqrt(normal.x * normal.x + normal.y * normal.y);
+ if (length != 0.f)
+ normal /= length;
+ return normal;
+ }
+
+ // Compute the dot product of two vectors
+ float dotProduct(const sf::Vector2f& p1, const sf::Vector2f& p2)
+ {
+ return p1.x * p2.x + p1.y * p2.y;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Shape::~Shape()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::setTexture(const Texture* texture, bool resetRect)
+{
+ if (texture)
+ {
+ // Recompute the texture area if requested, or if there was no texture & rect before
+ if (resetRect || (!m_texture && (m_textureRect == IntRect())))
+ setTextureRect(IntRect(0, 0, texture->getSize().x, texture->getSize().y));
+ }
+
+ // Assign the new texture
+ m_texture = texture;
+}
+
+
+////////////////////////////////////////////////////////////
+const Texture* Shape::getTexture() const
+{
+ return m_texture;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::setTextureRect(const IntRect& rect)
+{
+ m_textureRect = rect;
+ updateTexCoords();
+}
+
+
+////////////////////////////////////////////////////////////
+const IntRect& Shape::getTextureRect() const
+{
+ return m_textureRect;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::setFillColor(const Color& color)
+{
+ m_fillColor = color;
+ updateFillColors();
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Shape::getFillColor() const
+{
+ return m_fillColor;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::setOutlineColor(const Color& color)
+{
+ m_outlineColor = color;
+ updateOutlineColors();
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Shape::getOutlineColor() const
+{
+ return m_outlineColor;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::setOutlineThickness(float thickness)
+{
+ m_outlineThickness = thickness;
+ update(); // recompute everything because the whole shape must be offset
+}
+
+
+////////////////////////////////////////////////////////////
+float Shape::getOutlineThickness() const
+{
+ return m_outlineThickness;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Shape::getLocalBounds() const
+{
+ return m_bounds;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Shape::getGlobalBounds() const
+{
+ return getTransform().transformRect(getLocalBounds());
+}
+
+
+////////////////////////////////////////////////////////////
+Shape::Shape() :
+m_texture (NULL),
+m_textureRect (),
+m_fillColor (255, 255, 255),
+m_outlineColor (255, 255, 255),
+m_outlineThickness(0),
+m_vertices (TriangleFan),
+m_outlineVertices (TriangleStrip),
+m_insideBounds (),
+m_bounds ()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::update()
+{
+ // Get the total number of points of the shape
+ std::size_t count = getPointCount();
+ if (count < 3)
+ {
+ m_vertices.resize(0);
+ m_outlineVertices.resize(0);
+ return;
+ }
+
+ m_vertices.resize(count + 2); // + 2 for center and repeated first point
+
+ // Position
+ for (std::size_t i = 0; i < count; ++i)
+ m_vertices[i + 1].position = getPoint(i);
+ m_vertices[count + 1].position = m_vertices[1].position;
+
+ // Update the bounding rectangle
+ m_vertices[0] = m_vertices[1]; // so that the result of getBounds() is correct
+ m_insideBounds = m_vertices.getBounds();
+
+ // Compute the center and make it the first vertex
+ m_vertices[0].position.x = m_insideBounds.left + m_insideBounds.width / 2;
+ m_vertices[0].position.y = m_insideBounds.top + m_insideBounds.height / 2;
+
+ // Color
+ updateFillColors();
+
+ // Texture coordinates
+ updateTexCoords();
+
+ // Outline
+ updateOutline();
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::draw(RenderTarget& target, RenderStates states) const
+{
+ states.transform *= getTransform();
+
+ // Render the inside
+ states.texture = m_texture;
+ target.draw(m_vertices, states);
+
+ // Render the outline
+ if (m_outlineThickness != 0)
+ {
+ states.texture = NULL;
+ target.draw(m_outlineVertices, states);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::updateFillColors()
+{
+ for (std::size_t i = 0; i < m_vertices.getVertexCount(); ++i)
+ m_vertices[i].color = m_fillColor;
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::updateTexCoords()
+{
+ for (std::size_t i = 0; i < m_vertices.getVertexCount(); ++i)
+ {
+ float xratio = m_insideBounds.width > 0 ? (m_vertices[i].position.x - m_insideBounds.left) / m_insideBounds.width : 0;
+ float yratio = m_insideBounds.height > 0 ? (m_vertices[i].position.y - m_insideBounds.top) / m_insideBounds.height : 0;
+ m_vertices[i].texCoords.x = m_textureRect.left + m_textureRect.width * xratio;
+ m_vertices[i].texCoords.y = m_textureRect.top + m_textureRect.height * yratio;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::updateOutline()
+{
+ // Return if there is no outline
+ if (m_outlineThickness == 0.f)
+ {
+ m_outlineVertices.clear();
+ m_bounds = m_insideBounds;
+ return;
+ }
+
+ std::size_t count = m_vertices.getVertexCount() - 2;
+ m_outlineVertices.resize((count + 1) * 2);
+
+ for (std::size_t i = 0; i < count; ++i)
+ {
+ std::size_t index = i + 1;
+
+ // Get the two segments shared by the current point
+ Vector2f p0 = (i == 0) ? m_vertices[count].position : m_vertices[index - 1].position;
+ Vector2f p1 = m_vertices[index].position;
+ Vector2f p2 = m_vertices[index + 1].position;
+
+ // Compute their normal
+ Vector2f n1 = computeNormal(p0, p1);
+ Vector2f n2 = computeNormal(p1, p2);
+
+ // Make sure that the normals point towards the outside of the shape
+ // (this depends on the order in which the points were defined)
+ if (dotProduct(n1, m_vertices[0].position - p1) > 0)
+ n1 = -n1;
+ if (dotProduct(n2, m_vertices[0].position - p1) > 0)
+ n2 = -n2;
+
+ // Combine them to get the extrusion direction
+ float factor = 1.f + (n1.x * n2.x + n1.y * n2.y);
+ Vector2f normal = (n1 + n2) / factor;
+
+ // Update the outline points
+ m_outlineVertices[i * 2 + 0].position = p1;
+ m_outlineVertices[i * 2 + 1].position = p1 + normal * m_outlineThickness;
+ }
+
+ // Duplicate the first point at the end, to close the outline
+ m_outlineVertices[count * 2 + 0].position = m_outlineVertices[0].position;
+ m_outlineVertices[count * 2 + 1].position = m_outlineVertices[1].position;
+
+ // Update outline colors
+ updateOutlineColors();
+
+ // Update the shape's bounds
+ m_bounds = m_outlineVertices.getBounds();
+}
+
+
+////////////////////////////////////////////////////////////
+void Shape::updateOutlineColors()
+{
+ for (std::size_t i = 0; i < m_outlineVertices.getVertexCount(); ++i)
+ m_outlineVertices[i].color = m_outlineColor;
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Sprite.cpp b/src/SFML/Graphics/Sprite.cpp
new file mode 100644
index 0000000..feb79a4
--- /dev/null
+++ b/src/SFML/Graphics/Sprite.cpp
@@ -0,0 +1,174 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Sprite.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <cstdlib>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Sprite::Sprite() :
+m_texture (NULL),
+m_textureRect()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Sprite::Sprite(const Texture& texture) :
+m_texture (NULL),
+m_textureRect()
+{
+ setTexture(texture);
+}
+
+
+////////////////////////////////////////////////////////////
+Sprite::Sprite(const Texture& texture, const IntRect& rectangle) :
+m_texture (NULL),
+m_textureRect()
+{
+ setTexture(texture);
+ setTextureRect(rectangle);
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::setTexture(const Texture& texture, bool resetRect)
+{
+ // Recompute the texture area if requested, or if there was no valid texture & rect before
+ if (resetRect || (!m_texture && (m_textureRect == sf::IntRect())))
+ setTextureRect(IntRect(0, 0, texture.getSize().x, texture.getSize().y));
+
+ // Assign the new texture
+ m_texture = &texture;
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::setTextureRect(const IntRect& rectangle)
+{
+ if (rectangle != m_textureRect)
+ {
+ m_textureRect = rectangle;
+ updatePositions();
+ updateTexCoords();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::setColor(const Color& color)
+{
+ // Update the vertices' color
+ m_vertices[0].color = color;
+ m_vertices[1].color = color;
+ m_vertices[2].color = color;
+ m_vertices[3].color = color;
+}
+
+
+////////////////////////////////////////////////////////////
+const Texture* Sprite::getTexture() const
+{
+ return m_texture;
+}
+
+
+////////////////////////////////////////////////////////////
+const IntRect& Sprite::getTextureRect() const
+{
+ return m_textureRect;
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Sprite::getColor() const
+{
+ return m_vertices[0].color;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Sprite::getLocalBounds() const
+{
+ float width = static_cast<float>(std::abs(m_textureRect.width));
+ float height = static_cast<float>(std::abs(m_textureRect.height));
+
+ return FloatRect(0.f, 0.f, width, height);
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Sprite::getGlobalBounds() const
+{
+ return getTransform().transformRect(getLocalBounds());
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::draw(RenderTarget& target, RenderStates states) const
+{
+ if (m_texture)
+ {
+ states.transform *= getTransform();
+ states.texture = m_texture;
+ target.draw(m_vertices, 4, TriangleStrip, states);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::updatePositions()
+{
+ FloatRect bounds = getLocalBounds();
+
+ m_vertices[0].position = Vector2f(0, 0);
+ m_vertices[1].position = Vector2f(0, bounds.height);
+ m_vertices[2].position = Vector2f(bounds.width, 0);
+ m_vertices[3].position = Vector2f(bounds.width, bounds.height);
+}
+
+
+////////////////////////////////////////////////////////////
+void Sprite::updateTexCoords()
+{
+ float left = static_cast<float>(m_textureRect.left);
+ float right = left + m_textureRect.width;
+ float top = static_cast<float>(m_textureRect.top);
+ float bottom = top + m_textureRect.height;
+
+ m_vertices[0].texCoords = Vector2f(left, top);
+ m_vertices[1].texCoords = Vector2f(left, bottom);
+ m_vertices[2].texCoords = Vector2f(right, top);
+ m_vertices[3].texCoords = Vector2f(right, bottom);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp
new file mode 100644
index 0000000..6687551
--- /dev/null
+++ b/src/SFML/Graphics/Text.cpp
@@ -0,0 +1,567 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Text.hpp>
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <cmath>
+
+
+namespace
+{
+ // Add an underline or strikethrough line to the vertex array
+ void addLine(sf::VertexArray& vertices, float lineLength, float lineTop, const sf::Color& color, float offset, float thickness, float outlineThickness = 0)
+ {
+ float top = std::floor(lineTop + offset - (thickness / 2) + 0.5f);
+ float bottom = top + std::floor(thickness + 0.5f);
+
+ vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
+ vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
+ vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
+ vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
+ vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
+ vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
+ }
+
+ // Add a glyph quad to the vertex array
+ void addGlyphQuad(sf::VertexArray& vertices, sf::Vector2f position, const sf::Color& color, const sf::Glyph& glyph, float italicShear, float outlineThickness = 0)
+ {
+ float padding = 1.0;
+
+ float left = glyph.bounds.left - padding;
+ float top = glyph.bounds.top - padding;
+ float right = glyph.bounds.left + glyph.bounds.width + padding;
+ float bottom = glyph.bounds.top + glyph.bounds.height + padding;
+
+ float u1 = static_cast<float>(glyph.textureRect.left) - padding;
+ float v1 = static_cast<float>(glyph.textureRect.top) - padding;
+ float u2 = static_cast<float>(glyph.textureRect.left + glyph.textureRect.width) + padding;
+ float v2 = static_cast<float>(glyph.textureRect.top + glyph.textureRect.height) + padding;
+
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italicShear * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u1, v1)));
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italicShear * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u2, v1)));
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italicShear * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u1, v2)));
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italicShear * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u1, v2)));
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italicShear * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u2, v1)));
+ vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italicShear * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u2, v2)));
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Text::Text() :
+m_string (),
+m_font (NULL),
+m_characterSize (30),
+m_letterSpacingFactor(1.f),
+m_lineSpacingFactor (1.f),
+m_style (Regular),
+m_fillColor (255, 255, 255),
+m_outlineColor (0, 0, 0),
+m_outlineThickness (0),
+m_vertices (Triangles),
+m_outlineVertices (Triangles),
+m_bounds (),
+m_geometryNeedUpdate (false),
+m_fontTextureId (0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Text::Text(const String& string, const Font& font, unsigned int characterSize) :
+m_string (string),
+m_font (&font),
+m_characterSize (characterSize),
+m_letterSpacingFactor(1.f),
+m_lineSpacingFactor (1.f),
+m_style (Regular),
+m_fillColor (255, 255, 255),
+m_outlineColor (0, 0, 0),
+m_outlineThickness (0),
+m_vertices (Triangles),
+m_outlineVertices (Triangles),
+m_bounds (),
+m_geometryNeedUpdate (true),
+m_fontTextureId (0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setString(const String& string)
+{
+ if (m_string != string)
+ {
+ m_string = string;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setFont(const Font& font)
+{
+ if (m_font != &font)
+ {
+ m_font = &font;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setCharacterSize(unsigned int size)
+{
+ if (m_characterSize != size)
+ {
+ m_characterSize = size;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setLetterSpacing(float spacingFactor)
+{
+ if (m_letterSpacingFactor != spacingFactor)
+ {
+ m_letterSpacingFactor = spacingFactor;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setLineSpacing(float spacingFactor)
+{
+ if (m_lineSpacingFactor != spacingFactor)
+ {
+ m_lineSpacingFactor = spacingFactor;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setStyle(Uint32 style)
+{
+ if (m_style != style)
+ {
+ m_style = style;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setColor(const Color& color)
+{
+ setFillColor(color);
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setFillColor(const Color& color)
+{
+ if (color != m_fillColor)
+ {
+ m_fillColor = color;
+
+ // Change vertex colors directly, no need to update whole geometry
+ // (if geometry is updated anyway, we can skip this step)
+ if (!m_geometryNeedUpdate)
+ {
+ for (std::size_t i = 0; i < m_vertices.getVertexCount(); ++i)
+ m_vertices[i].color = m_fillColor;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setOutlineColor(const Color& color)
+{
+ if (color != m_outlineColor)
+ {
+ m_outlineColor = color;
+
+ // Change vertex colors directly, no need to update whole geometry
+ // (if geometry is updated anyway, we can skip this step)
+ if (!m_geometryNeedUpdate)
+ {
+ for (std::size_t i = 0; i < m_outlineVertices.getVertexCount(); ++i)
+ m_outlineVertices[i].color = m_outlineColor;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::setOutlineThickness(float thickness)
+{
+ if (thickness != m_outlineThickness)
+ {
+ m_outlineThickness = thickness;
+ m_geometryNeedUpdate = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const String& Text::getString() const
+{
+ return m_string;
+}
+
+
+////////////////////////////////////////////////////////////
+const Font* Text::getFont() const
+{
+ return m_font;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Text::getCharacterSize() const
+{
+ return m_characterSize;
+}
+
+
+////////////////////////////////////////////////////////////
+float Text::getLetterSpacing() const
+{
+ return m_letterSpacingFactor;
+}
+
+
+////////////////////////////////////////////////////////////
+float Text::getLineSpacing() const
+{
+ return m_lineSpacingFactor;
+}
+
+
+////////////////////////////////////////////////////////////
+Uint32 Text::getStyle() const
+{
+ return m_style;
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Text::getColor() const
+{
+ return getFillColor();
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Text::getFillColor() const
+{
+ return m_fillColor;
+}
+
+
+////////////////////////////////////////////////////////////
+const Color& Text::getOutlineColor() const
+{
+ return m_outlineColor;
+}
+
+
+////////////////////////////////////////////////////////////
+float Text::getOutlineThickness() const
+{
+ return m_outlineThickness;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f Text::findCharacterPos(std::size_t index) const
+{
+ // Make sure that we have a valid font
+ if (!m_font)
+ return Vector2f();
+
+ // Adjust the index if it's out of range
+ if (index > m_string.getSize())
+ index = m_string.getSize();
+
+ // Precompute the variables needed by the algorithm
+ bool isBold = m_style & Bold;
+ float whitespaceWidth = m_font->getGlyph(L' ', m_characterSize, isBold).advance;
+ float letterSpacing = ( whitespaceWidth / 3.f ) * ( m_letterSpacingFactor - 1.f );
+ whitespaceWidth += letterSpacing;
+ float lineSpacing = m_font->getLineSpacing(m_characterSize) * m_lineSpacingFactor;
+
+ // Compute the position
+ Vector2f position;
+ Uint32 prevChar = 0;
+ for (std::size_t i = 0; i < index; ++i)
+ {
+ Uint32 curChar = m_string[i];
+
+ // Apply the kerning offset
+ position.x += m_font->getKerning(prevChar, curChar, m_characterSize);
+ prevChar = curChar;
+
+ // Handle special characters
+ switch (curChar)
+ {
+ case ' ': position.x += whitespaceWidth; continue;
+ case '\t': position.x += whitespaceWidth * 4; continue;
+ case '\n': position.y += lineSpacing; position.x = 0; continue;
+ }
+
+ // For regular characters, add the advance offset of the glyph
+ position.x += m_font->getGlyph(curChar, m_characterSize, isBold).advance + letterSpacing;
+ }
+
+ // Transform the position to global coordinates
+ position = getTransform().transformPoint(position);
+
+ return position;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Text::getLocalBounds() const
+{
+ ensureGeometryUpdate();
+
+ return m_bounds;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Text::getGlobalBounds() const
+{
+ return getTransform().transformRect(getLocalBounds());
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::draw(RenderTarget& target, RenderStates states) const
+{
+ if (m_font)
+ {
+ ensureGeometryUpdate();
+
+ states.transform *= getTransform();
+ states.texture = &m_font->getTexture(m_characterSize);
+
+ // Only draw the outline if there is something to draw
+ if (m_outlineThickness != 0)
+ target.draw(m_outlineVertices, states);
+
+ target.draw(m_vertices, states);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Text::ensureGeometryUpdate() const
+{
+ if (!m_font)
+ return;
+
+ // Do nothing, if geometry has not changed and the font texture has not changed
+ if (!m_geometryNeedUpdate && m_font->getTexture(m_characterSize).m_cacheId == m_fontTextureId)
+ return;
+
+ // Save the current fonts texture id
+ m_fontTextureId = m_font->getTexture(m_characterSize).m_cacheId;
+
+ // Mark geometry as updated
+ m_geometryNeedUpdate = false;
+
+ // Clear the previous geometry
+ m_vertices.clear();
+ m_outlineVertices.clear();
+ m_bounds = FloatRect();
+
+ // No text: nothing to draw
+ if (m_string.isEmpty())
+ return;
+
+ // Compute values related to the text style
+ bool isBold = m_style & Bold;
+ bool isUnderlined = m_style & Underlined;
+ bool isStrikeThrough = m_style & StrikeThrough;
+ float italicShear = (m_style & Italic) ? 0.209f : 0.f; // 12 degrees in radians
+ float underlineOffset = m_font->getUnderlinePosition(m_characterSize);
+ float underlineThickness = m_font->getUnderlineThickness(m_characterSize);
+
+ // Compute the location of the strike through dynamically
+ // We use the center point of the lowercase 'x' glyph as the reference
+ // We reuse the underline thickness as the thickness of the strike through as well
+ FloatRect xBounds = m_font->getGlyph(L'x', m_characterSize, isBold).bounds;
+ float strikeThroughOffset = xBounds.top + xBounds.height / 2.f;
+
+ // Precompute the variables needed by the algorithm
+ float whitespaceWidth = m_font->getGlyph(L' ', m_characterSize, isBold).advance;
+ float letterSpacing = ( whitespaceWidth / 3.f ) * ( m_letterSpacingFactor - 1.f );
+ whitespaceWidth += letterSpacing;
+ float lineSpacing = m_font->getLineSpacing(m_characterSize) * m_lineSpacingFactor;
+ float x = 0.f;
+ float y = static_cast<float>(m_characterSize);
+
+ // Create one quad for each character
+ float minX = static_cast<float>(m_characterSize);
+ float minY = static_cast<float>(m_characterSize);
+ float maxX = 0.f;
+ float maxY = 0.f;
+ Uint32 prevChar = 0;
+ for (std::size_t i = 0; i < m_string.getSize(); ++i)
+ {
+ Uint32 curChar = m_string[i];
+
+ // Skip the \r char to avoid weird graphical issues
+ if (curChar == '\r')
+ continue;
+
+ // Apply the kerning offset
+ x += m_font->getKerning(prevChar, curChar, m_characterSize);
+
+ // If we're using the underlined style and there's a new line, draw a line
+ if (isUnderlined && (curChar == L'\n' && prevChar != L'\n'))
+ {
+ addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
+
+ if (m_outlineThickness != 0)
+ addLine(m_outlineVertices, x, y, m_outlineColor, underlineOffset, underlineThickness, m_outlineThickness);
+ }
+
+ // If we're using the strike through style and there's a new line, draw a line across all characters
+ if (isStrikeThrough && (curChar == L'\n' && prevChar != L'\n'))
+ {
+ addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
+
+ if (m_outlineThickness != 0)
+ addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness);
+ }
+
+ prevChar = curChar;
+
+ // Handle special characters
+ if ((curChar == L' ') || (curChar == L'\n') || (curChar == L'\t'))
+ {
+ // Update the current bounds (min coordinates)
+ minX = std::min(minX, x);
+ minY = std::min(minY, y);
+
+ switch (curChar)
+ {
+ case L' ': x += whitespaceWidth; break;
+ case L'\t': x += whitespaceWidth * 4; break;
+ case L'\n': y += lineSpacing; x = 0; break;
+ }
+
+ // Update the current bounds (max coordinates)
+ maxX = std::max(maxX, x);
+ maxY = std::max(maxY, y);
+
+ // Next glyph, no need to create a quad for whitespace
+ continue;
+ }
+
+ // Apply the outline
+ if (m_outlineThickness != 0)
+ {
+ const Glyph& glyph = m_font->getGlyph(curChar, m_characterSize, isBold, m_outlineThickness);
+
+ float left = glyph.bounds.left;
+ float top = glyph.bounds.top;
+ float right = glyph.bounds.left + glyph.bounds.width;
+ float bottom = glyph.bounds.top + glyph.bounds.height;
+
+ // Add the outline glyph to the vertices
+ addGlyphQuad(m_outlineVertices, Vector2f(x, y), m_outlineColor, glyph, italicShear, m_outlineThickness);
+
+ // Update the current bounds with the outlined glyph bounds
+ minX = std::min(minX, x + left - italicShear * bottom - m_outlineThickness);
+ maxX = std::max(maxX, x + right - italicShear * top - m_outlineThickness);
+ minY = std::min(minY, y + top - m_outlineThickness);
+ maxY = std::max(maxY, y + bottom - m_outlineThickness);
+ }
+
+ // Extract the current glyph's description
+ const Glyph& glyph = m_font->getGlyph(curChar, m_characterSize, isBold);
+
+ // Add the glyph to the vertices
+ addGlyphQuad(m_vertices, Vector2f(x, y), m_fillColor, glyph, italicShear);
+
+ // Update the current bounds with the non outlined glyph bounds
+ if (m_outlineThickness == 0)
+ {
+ float left = glyph.bounds.left;
+ float top = glyph.bounds.top;
+ float right = glyph.bounds.left + glyph.bounds.width;
+ float bottom = glyph.bounds.top + glyph.bounds.height;
+
+ minX = std::min(minX, x + left - italicShear * bottom);
+ maxX = std::max(maxX, x + right - italicShear * top);
+ minY = std::min(minY, y + top);
+ maxY = std::max(maxY, y + bottom);
+ }
+
+ // Advance to the next character
+ x += glyph.advance + letterSpacing;
+ }
+
+ // If we're using the underlined style, add the last line
+ if (isUnderlined && (x > 0))
+ {
+ addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
+
+ if (m_outlineThickness != 0)
+ addLine(m_outlineVertices, x, y, m_outlineColor, underlineOffset, underlineThickness, m_outlineThickness);
+ }
+
+ // If we're using the strike through style, add the last line across all characters
+ if (isStrikeThrough && (x > 0))
+ {
+ addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
+
+ if (m_outlineThickness != 0)
+ addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness);
+ }
+
+ // Update the bounding rectangle
+ m_bounds.left = minX;
+ m_bounds.top = minY;
+ m_bounds.width = maxX - minX;
+ m_bounds.height = maxY - minY;
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp
new file mode 100644
index 0000000..fd94acf
--- /dev/null
+++ b/src/SFML/Graphics/Texture.cpp
@@ -0,0 +1,870 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Texture.hpp>
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/Graphics/TextureSaver.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/Window/Window.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <cassert>
+#include <cstring>
+
+
+namespace
+{
+ sf::Mutex idMutex;
+ sf::Mutex maximumSizeMutex;
+
+ // Thread-safe unique identifier generator,
+ // is used for states cache (see RenderTarget)
+ sf::Uint64 getUniqueId()
+ {
+ sf::Lock lock(idMutex);
+
+ static sf::Uint64 id = 1; // start at 1, zero is "no texture"
+
+ return id++;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Texture::Texture() :
+m_size (0, 0),
+m_actualSize (0, 0),
+m_texture (0),
+m_isSmooth (false),
+m_sRgb (false),
+m_isRepeated (false),
+m_pixelsFlipped(false),
+m_fboAttachment(false),
+m_hasMipmap (false),
+m_cacheId (getUniqueId())
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Texture::Texture(const Texture& copy) :
+m_size (0, 0),
+m_actualSize (0, 0),
+m_texture (0),
+m_isSmooth (copy.m_isSmooth),
+m_sRgb (copy.m_sRgb),
+m_isRepeated (copy.m_isRepeated),
+m_pixelsFlipped(false),
+m_fboAttachment(false),
+m_hasMipmap (false),
+m_cacheId (getUniqueId())
+{
+ if (copy.m_texture)
+ {
+ if (create(copy.getSize().x, copy.getSize().y))
+ {
+ update(copy);
+
+ // Force an OpenGL flush, so that the texture will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+ }
+ else
+ {
+ err() << "Failed to copy texture, failed to create new texture" << std::endl;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Texture::~Texture()
+{
+ // Destroy the OpenGL texture
+ if (m_texture)
+ {
+ TransientContextLock lock;
+
+ GLuint texture = static_cast<GLuint>(m_texture);
+ glCheck(glDeleteTextures(1, &texture));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::create(unsigned int width, unsigned int height)
+{
+ // Check if texture parameters are valid before creating it
+ if ((width == 0) || (height == 0))
+ {
+ err() << "Failed to create texture, invalid size (" << width << "x" << height << ")" << std::endl;
+ return false;
+ }
+
+ TransientContextLock lock;
+
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+
+ // Compute the internal texture dimensions depending on NPOT textures support
+ Vector2u actualSize(getValidSize(width), getValidSize(height));
+
+ // Check the maximum texture size
+ unsigned int maxSize = getMaximumSize();
+ if ((actualSize.x > maxSize) || (actualSize.y > maxSize))
+ {
+ err() << "Failed to create texture, its internal size is too high "
+ << "(" << actualSize.x << "x" << actualSize.y << ", "
+ << "maximum is " << maxSize << "x" << maxSize << ")"
+ << std::endl;
+ return false;
+ }
+
+ // All the validity checks passed, we can store the new texture settings
+ m_size.x = width;
+ m_size.y = height;
+ m_actualSize = actualSize;
+ m_pixelsFlipped = false;
+ m_fboAttachment = false;
+
+ // Create the OpenGL texture if it doesn't exist yet
+ if (!m_texture)
+ {
+ GLuint texture;
+ glCheck(glGenTextures(1, &texture));
+ m_texture = static_cast<unsigned int>(texture);
+ }
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ static bool textureEdgeClamp = GLEXT_texture_edge_clamp || GLEXT_EXT_texture_edge_clamp;
+
+ if (!m_isRepeated && !textureEdgeClamp)
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
+ err() << "Artifacts may occur along texture edges" << std::endl;
+ err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
+
+ warned = true;
+ }
+ }
+
+ static bool textureSrgb = GLEXT_texture_sRGB;
+
+ if (m_sRgb && !textureSrgb)
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+#ifndef SFML_OPENGL_ES
+ err() << "OpenGL extension EXT_texture_sRGB unavailable" << std::endl;
+#else
+ err() << "OpenGL ES extension EXT_sRGB unavailable" << std::endl;
+#endif
+ err() << "Automatic sRGB to linear conversion disabled" << std::endl;
+
+ warned = true;
+ }
+
+ m_sRgb = false;
+ }
+
+ // Initialize the texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexImage2D(GL_TEXTURE_2D, 0, (m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA), m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ m_cacheId = getUniqueId();
+
+ m_hasMipmap = false;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::loadFromFile(const std::string& filename, const IntRect& area)
+{
+ Image image;
+ return image.loadFromFile(filename) && loadFromImage(image, area);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::loadFromMemory(const void* data, std::size_t size, const IntRect& area)
+{
+ Image image;
+ return image.loadFromMemory(data, size) && loadFromImage(image, area);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::loadFromStream(InputStream& stream, const IntRect& area)
+{
+ Image image;
+ return image.loadFromStream(stream) && loadFromImage(image, area);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::loadFromImage(const Image& image, const IntRect& area)
+{
+ // Retrieve the image size
+ int width = static_cast<int>(image.getSize().x);
+ int height = static_cast<int>(image.getSize().y);
+
+ // Load the entire image if the source area is either empty or contains the whole image
+ if (area.width == 0 || (area.height == 0) ||
+ ((area.left <= 0) && (area.top <= 0) && (area.width >= width) && (area.height >= height)))
+ {
+ // Load the entire image
+ if (create(image.getSize().x, image.getSize().y))
+ {
+ update(image);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // Load a sub-area of the image
+
+ // Adjust the rectangle to the size of the image
+ IntRect rectangle = area;
+ if (rectangle.left < 0) rectangle.left = 0;
+ if (rectangle.top < 0) rectangle.top = 0;
+ if (rectangle.left + rectangle.width > width) rectangle.width = width - rectangle.left;
+ if (rectangle.top + rectangle.height > height) rectangle.height = height - rectangle.top;
+
+ // Create the texture and upload the pixels
+ if (create(rectangle.width, rectangle.height))
+ {
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Copy the pixels to the texture, row by row
+ const Uint8* pixels = image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top));
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ for (int i = 0; i < rectangle.height; ++i)
+ {
+ glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, rectangle.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
+ pixels += 4 * width;
+ }
+
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ m_hasMipmap = false;
+
+ // Force an OpenGL flush, so that the texture will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u Texture::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+Image Texture::copyToImage() const
+{
+ // Easy case: empty texture
+ if (!m_texture)
+ return Image();
+
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Create an array of pixels
+ std::vector<Uint8> pixels(m_size.x * m_size.y * 4);
+
+#ifdef SFML_OPENGL_ES
+
+ // OpenGL ES doesn't have the glGetTexImage function, the only way to read
+ // from a texture is to bind it to a FBO and use glReadPixels
+ GLuint frameBuffer = 0;
+ glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer));
+ if (frameBuffer)
+ {
+ GLint previousFrameBuffer;
+ glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, &previousFrameBuffer));
+
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
+ glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
+ glCheck(glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
+ glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
+
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, previousFrameBuffer));
+ }
+
+#else
+
+ if ((m_size == m_actualSize) && !m_pixelsFlipped)
+ {
+ // Texture is not padded nor flipped, we can use a direct copy
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
+ }
+ else
+ {
+ // Texture is either padded or flipped, we have to use a slower algorithm
+
+ // All the pixels will first be copied to a temporary array
+ std::vector<Uint8> allPixels(m_actualSize.x * m_actualSize.y * 4);
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0]));
+
+ // Then we copy the useful pixels from the temporary array to the final one
+ const Uint8* src = &allPixels[0];
+ Uint8* dst = &pixels[0];
+ int srcPitch = m_actualSize.x * 4;
+ int dstPitch = m_size.x * 4;
+
+ // Handle the case where source pixels are flipped vertically
+ if (m_pixelsFlipped)
+ {
+ src += srcPitch * (m_size.y - 1);
+ srcPitch = -srcPitch;
+ }
+
+ for (unsigned int i = 0; i < m_size.y; ++i)
+ {
+ std::memcpy(dst, src, dstPitch);
+ src += srcPitch;
+ dst += dstPitch;
+ }
+ }
+
+#endif // SFML_OPENGL_ES
+
+ // Create the image
+ Image image;
+ image.create(m_size.x, m_size.y, &pixels[0]);
+
+ return image;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Uint8* pixels)
+{
+ // Update the whole texture
+ update(pixels, m_size.x, m_size.y, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)
+{
+ assert(x + width <= m_size.x);
+ assert(y + height <= m_size.y);
+
+ if (pixels && m_texture)
+ {
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Copy pixels from the given array to the texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ m_hasMipmap = false;
+ m_pixelsFlipped = false;
+ m_cacheId = getUniqueId();
+
+ // Force an OpenGL flush, so that the texture data will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Texture& texture)
+{
+ // Update the whole texture
+ update(texture, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Texture& texture, unsigned int x, unsigned int y)
+{
+ assert(x + texture.m_size.x <= m_size.x);
+ assert(y + texture.m_size.y <= m_size.y);
+
+ if (!m_texture || !texture.m_texture)
+ return;
+
+#ifndef SFML_OPENGL_ES
+
+ {
+ TransientContextLock lock;
+
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+ }
+
+ if (GLEXT_framebuffer_object && GLEXT_framebuffer_blit)
+ {
+ TransientContextLock lock;
+
+ // Save the current bindings so we can restore them after we are done
+ GLint readFramebuffer = 0;
+ GLint drawFramebuffer = 0;
+
+ glCheck(glGetIntegerv(GLEXT_GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer));
+ glCheck(glGetIntegerv(GLEXT_GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer));
+
+ // Create the framebuffers
+ GLuint sourceFrameBuffer = 0;
+ GLuint destFrameBuffer = 0;
+ glCheck(GLEXT_glGenFramebuffers(1, &sourceFrameBuffer));
+ glCheck(GLEXT_glGenFramebuffers(1, &destFrameBuffer));
+
+ if (!sourceFrameBuffer || !destFrameBuffer)
+ {
+ err() << "Cannot copy texture, failed to create a frame buffer object" << std::endl;
+ return;
+ }
+
+ // Link the source texture to the source frame buffer
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, sourceFrameBuffer));
+ glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_READ_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_texture, 0));
+
+ // Link the destination texture to the destination frame buffer
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, destFrameBuffer));
+ glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_DRAW_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
+
+ // A final check, just to be sure...
+ GLenum sourceStatus;
+ glCheck(sourceStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_READ_FRAMEBUFFER));
+
+ GLenum destStatus;
+ glCheck(destStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_DRAW_FRAMEBUFFER));
+
+ if ((sourceStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE) && (destStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE))
+ {
+ // Blit the texture contents from the source to the destination texture
+ glCheck(GLEXT_glBlitFramebuffer(
+ 0, texture.m_pixelsFlipped ? texture.m_size.y : 0, texture.m_size.x, texture.m_pixelsFlipped ? 0 : texture.m_size.y, // Source rectangle, flip y if source is flipped
+ x, y, x + texture.m_size.x, y + texture.m_size.y, // Destination rectangle
+ GL_COLOR_BUFFER_BIT, GL_NEAREST
+ ));
+ }
+ else
+ {
+ err() << "Cannot copy texture, failed to link texture to frame buffer" << std::endl;
+ }
+
+ // Restore previously bound framebuffers
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, readFramebuffer));
+ glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, drawFramebuffer));
+
+ // Delete the framebuffers
+ glCheck(GLEXT_glDeleteFramebuffers(1, &sourceFrameBuffer));
+ glCheck(GLEXT_glDeleteFramebuffers(1, &destFrameBuffer));
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Set the parameters of this texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ m_hasMipmap = false;
+ m_pixelsFlipped = false;
+ m_cacheId = getUniqueId();
+
+ // Force an OpenGL flush, so that the texture data will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+
+ return;
+ }
+
+#endif // SFML_OPENGL_ES
+
+ update(texture.copyToImage(), x, y);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Image& image)
+{
+ // Update the whole texture
+ update(image.getPixelsPtr(), image.getSize().x, image.getSize().y, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Image& image, unsigned int x, unsigned int y)
+{
+ update(image.getPixelsPtr(), image.getSize().x, image.getSize().y, x, y);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Window& window)
+{
+ update(window, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::update(const Window& window, unsigned int x, unsigned int y)
+{
+ assert(x + window.getSize().x <= m_size.x);
+ assert(y + window.getSize().y <= m_size.y);
+
+ if (m_texture && window.setActive(true))
+ {
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ // Copy pixels from the back-buffer to the texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.getSize().x, window.getSize().y));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ m_hasMipmap = false;
+ m_pixelsFlipped = true;
+ m_cacheId = getUniqueId();
+
+ // Force an OpenGL flush, so that the texture will appear updated
+ // in all contexts immediately (solves problems in multi-threaded apps)
+ glCheck(glFlush());
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::setSmooth(bool smooth)
+{
+ if (smooth != m_isSmooth)
+ {
+ m_isSmooth = smooth;
+
+ if (m_texture)
+ {
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+
+ if (m_hasMipmap)
+ {
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
+ }
+ else
+ {
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::isSmooth() const
+{
+ return m_isSmooth;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::setSrgb(bool sRgb)
+{
+ m_sRgb = sRgb;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::isSrgb() const
+{
+ return m_sRgb;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::setRepeated(bool repeated)
+{
+ if (repeated != m_isRepeated)
+ {
+ m_isRepeated = repeated;
+
+ if (m_texture)
+ {
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ static bool textureEdgeClamp = GLEXT_texture_edge_clamp || GLEXT_EXT_texture_edge_clamp;
+
+ if (!m_isRepeated && !textureEdgeClamp)
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
+ err() << "Artifacts may occur along texture edges" << std::endl;
+ err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
+
+ warned = true;
+ }
+ }
+
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::isRepeated() const
+{
+ return m_isRepeated;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Texture::generateMipmap()
+{
+ if (!m_texture)
+ return false;
+
+ TransientContextLock lock;
+
+ // Make sure that extensions are initialized
+ priv::ensureExtensionsInit();
+
+ if (!GLEXT_framebuffer_object)
+ return false;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(GLEXT_glGenerateMipmap(GL_TEXTURE_2D));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
+
+ m_hasMipmap = true;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::invalidateMipmap()
+{
+ if (!m_hasMipmap)
+ return;
+
+ TransientContextLock lock;
+
+ // Make sure that the current texture binding will be preserved
+ priv::TextureSaver save;
+
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
+ glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
+
+ m_hasMipmap = false;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::bind(const Texture* texture, CoordinateType coordinateType)
+{
+ TransientContextLock lock;
+
+ if (texture && texture->m_texture)
+ {
+ // Bind the texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture));
+
+ // Check if we need to define a special texture matrix
+ if ((coordinateType == Pixels) || texture->m_pixelsFlipped)
+ {
+ GLfloat matrix[16] = {1.f, 0.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f};
+
+ // If non-normalized coordinates (= pixels) are requested, we need to
+ // setup scale factors that convert the range [0 .. size] to [0 .. 1]
+ if (coordinateType == Pixels)
+ {
+ matrix[0] = 1.f / texture->m_actualSize.x;
+ matrix[5] = 1.f / texture->m_actualSize.y;
+ }
+
+ // If pixels are flipped we must invert the Y axis
+ if (texture->m_pixelsFlipped)
+ {
+ matrix[5] = -matrix[5];
+ matrix[13] = static_cast<float>(texture->m_size.y) / texture->m_actualSize.y;
+ }
+
+ // Load the matrix
+ glCheck(glMatrixMode(GL_TEXTURE));
+ glCheck(glLoadMatrixf(matrix));
+
+ // Go back to model-view mode (sf::RenderTarget relies on it)
+ glCheck(glMatrixMode(GL_MODELVIEW));
+ }
+ }
+ else
+ {
+ // Bind no texture
+ glCheck(glBindTexture(GL_TEXTURE_2D, 0));
+
+ // Reset the texture matrix
+ glCheck(glMatrixMode(GL_TEXTURE));
+ glCheck(glLoadIdentity());
+
+ // Go back to model-view mode (sf::RenderTarget relies on it)
+ glCheck(glMatrixMode(GL_MODELVIEW));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Texture::getMaximumSize()
+{
+ Lock lock(maximumSizeMutex);
+
+ static bool checked = false;
+ static GLint size = 0;
+
+ if (!checked)
+ {
+ checked = true;
+
+ TransientContextLock lock;
+
+ glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
+ }
+
+ return static_cast<unsigned int>(size);
+}
+
+
+////////////////////////////////////////////////////////////
+Texture& Texture::operator =(const Texture& right)
+{
+ Texture temp(right);
+
+ swap(temp);
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+void Texture::swap(Texture& right)
+{
+ std::swap(m_size, right.m_size);
+ std::swap(m_actualSize, right.m_actualSize);
+ std::swap(m_texture, right.m_texture);
+ std::swap(m_isSmooth, right.m_isSmooth);
+ std::swap(m_sRgb, right.m_sRgb);
+ std::swap(m_isRepeated, right.m_isRepeated);
+ std::swap(m_pixelsFlipped, right.m_pixelsFlipped);
+ std::swap(m_fboAttachment, right.m_fboAttachment);
+ std::swap(m_hasMipmap, right.m_hasMipmap);
+
+ m_cacheId = getUniqueId();
+ right.m_cacheId = getUniqueId();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Texture::getNativeHandle() const
+{
+ return m_texture;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Texture::getValidSize(unsigned int size)
+{
+ if (GLEXT_texture_non_power_of_two)
+ {
+ // If hardware supports NPOT textures, then just return the unmodified size
+ return size;
+ }
+ else
+ {
+ // If hardware doesn't support NPOT textures, we calculate the nearest power of two
+ unsigned int powerOfTwo = 1;
+ while (powerOfTwo < size)
+ powerOfTwo *= 2;
+
+ return powerOfTwo;
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/TextureSaver.cpp b/src/SFML/Graphics/TextureSaver.cpp
new file mode 100644
index 0000000..2b7d8af
--- /dev/null
+++ b/src/SFML/Graphics/TextureSaver.cpp
@@ -0,0 +1,50 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/TextureSaver.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+TextureSaver::TextureSaver()
+{
+ glCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_textureBinding));
+}
+
+
+////////////////////////////////////////////////////////////
+TextureSaver::~TextureSaver()
+{
+ glCheck(glBindTexture(GL_TEXTURE_2D, m_textureBinding));
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Graphics/TextureSaver.hpp b/src/SFML/Graphics/TextureSaver.hpp
new file mode 100644
index 0000000..170fe46
--- /dev/null
+++ b/src/SFML/Graphics/TextureSaver.hpp
@@ -0,0 +1,75 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_TEXTURESAVER_HPP
+#define SFML_TEXTURESAVER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/GLCheck.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Automatic wrapper for saving and restoring the current texture binding
+///
+////////////////////////////////////////////////////////////
+class TextureSaver
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// The current texture binding is saved.
+ ///
+ ////////////////////////////////////////////////////////////
+ TextureSaver();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// The previous texture binding is restored.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~TextureSaver();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ GLint m_textureBinding; ///< Texture binding to restore
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_TEXTURESAVER_HPP
diff --git a/src/SFML/Graphics/Transform.cpp b/src/SFML/Graphics/Transform.cpp
new file mode 100644
index 0000000..22d3e70
--- /dev/null
+++ b/src/SFML/Graphics/Transform.cpp
@@ -0,0 +1,291 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Transform.hpp>
+#include <cmath>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+const Transform Transform::Identity;
+
+
+////////////////////////////////////////////////////////////
+Transform::Transform()
+{
+ // Identity matrix
+ m_matrix[0] = 1.f; m_matrix[4] = 0.f; m_matrix[8] = 0.f; m_matrix[12] = 0.f;
+ m_matrix[1] = 0.f; m_matrix[5] = 1.f; m_matrix[9] = 0.f; m_matrix[13] = 0.f;
+ m_matrix[2] = 0.f; m_matrix[6] = 0.f; m_matrix[10] = 1.f; m_matrix[14] = 0.f;
+ m_matrix[3] = 0.f; m_matrix[7] = 0.f; m_matrix[11] = 0.f; m_matrix[15] = 1.f;
+}
+
+
+////////////////////////////////////////////////////////////
+Transform::Transform(float a00, float a01, float a02,
+ float a10, float a11, float a12,
+ float a20, float a21, float a22)
+{
+ m_matrix[0] = a00; m_matrix[4] = a01; m_matrix[8] = 0.f; m_matrix[12] = a02;
+ m_matrix[1] = a10; m_matrix[5] = a11; m_matrix[9] = 0.f; m_matrix[13] = a12;
+ m_matrix[2] = 0.f; m_matrix[6] = 0.f; m_matrix[10] = 1.f; m_matrix[14] = 0.f;
+ m_matrix[3] = a20; m_matrix[7] = a21; m_matrix[11] = 0.f; m_matrix[15] = a22;
+}
+
+
+////////////////////////////////////////////////////////////
+const float* Transform::getMatrix() const
+{
+ return m_matrix;
+}
+
+
+////////////////////////////////////////////////////////////
+Transform Transform::getInverse() const
+{
+ // Compute the determinant
+ float det = m_matrix[0] * (m_matrix[15] * m_matrix[5] - m_matrix[7] * m_matrix[13]) -
+ m_matrix[1] * (m_matrix[15] * m_matrix[4] - m_matrix[7] * m_matrix[12]) +
+ m_matrix[3] * (m_matrix[13] * m_matrix[4] - m_matrix[5] * m_matrix[12]);
+
+ // Compute the inverse if the determinant is not zero
+ // (don't use an epsilon because the determinant may *really* be tiny)
+ if (det != 0.f)
+ {
+ return Transform( (m_matrix[15] * m_matrix[5] - m_matrix[7] * m_matrix[13]) / det,
+ -(m_matrix[15] * m_matrix[4] - m_matrix[7] * m_matrix[12]) / det,
+ (m_matrix[13] * m_matrix[4] - m_matrix[5] * m_matrix[12]) / det,
+ -(m_matrix[15] * m_matrix[1] - m_matrix[3] * m_matrix[13]) / det,
+ (m_matrix[15] * m_matrix[0] - m_matrix[3] * m_matrix[12]) / det,
+ -(m_matrix[13] * m_matrix[0] - m_matrix[1] * m_matrix[12]) / det,
+ (m_matrix[7] * m_matrix[1] - m_matrix[3] * m_matrix[5]) / det,
+ -(m_matrix[7] * m_matrix[0] - m_matrix[3] * m_matrix[4]) / det,
+ (m_matrix[5] * m_matrix[0] - m_matrix[1] * m_matrix[4]) / det);
+ }
+ else
+ {
+ return Identity;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f Transform::transformPoint(float x, float y) const
+{
+ return Vector2f(m_matrix[0] * x + m_matrix[4] * y + m_matrix[12],
+ m_matrix[1] * x + m_matrix[5] * y + m_matrix[13]);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f Transform::transformPoint(const Vector2f& point) const
+{
+ return transformPoint(point.x, point.y);
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect Transform::transformRect(const FloatRect& rectangle) const
+{
+ // Transform the 4 corners of the rectangle
+ const Vector2f points[] =
+ {
+ transformPoint(rectangle.left, rectangle.top),
+ transformPoint(rectangle.left, rectangle.top + rectangle.height),
+ transformPoint(rectangle.left + rectangle.width, rectangle.top),
+ transformPoint(rectangle.left + rectangle.width, rectangle.top + rectangle.height)
+ };
+
+ // Compute the bounding rectangle of the transformed points
+ float left = points[0].x;
+ float top = points[0].y;
+ float right = points[0].x;
+ float bottom = points[0].y;
+ for (int i = 1; i < 4; ++i)
+ {
+ if (points[i].x < left) left = points[i].x;
+ else if (points[i].x > right) right = points[i].x;
+ if (points[i].y < top) top = points[i].y;
+ else if (points[i].y > bottom) bottom = points[i].y;
+ }
+
+ return FloatRect(left, top, right - left, bottom - top);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::combine(const Transform& transform)
+{
+ const float* a = m_matrix;
+ const float* b = transform.m_matrix;
+
+ *this = Transform(a[0] * b[0] + a[4] * b[1] + a[12] * b[3],
+ a[0] * b[4] + a[4] * b[5] + a[12] * b[7],
+ a[0] * b[12] + a[4] * b[13] + a[12] * b[15],
+ a[1] * b[0] + a[5] * b[1] + a[13] * b[3],
+ a[1] * b[4] + a[5] * b[5] + a[13] * b[7],
+ a[1] * b[12] + a[5] * b[13] + a[13] * b[15],
+ a[3] * b[0] + a[7] * b[1] + a[15] * b[3],
+ a[3] * b[4] + a[7] * b[5] + a[15] * b[7],
+ a[3] * b[12] + a[7] * b[13] + a[15] * b[15]);
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::translate(float x, float y)
+{
+ Transform translation(1, 0, x,
+ 0, 1, y,
+ 0, 0, 1);
+
+ return combine(translation);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::translate(const Vector2f& offset)
+{
+ return translate(offset.x, offset.y);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::rotate(float angle)
+{
+ float rad = angle * 3.141592654f / 180.f;
+ float cos = std::cos(rad);
+ float sin = std::sin(rad);
+
+ Transform rotation(cos, -sin, 0,
+ sin, cos, 0,
+ 0, 0, 1);
+
+ return combine(rotation);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::rotate(float angle, float centerX, float centerY)
+{
+ float rad = angle * 3.141592654f / 180.f;
+ float cos = std::cos(rad);
+ float sin = std::sin(rad);
+
+ Transform rotation(cos, -sin, centerX * (1 - cos) + centerY * sin,
+ sin, cos, centerY * (1 - cos) - centerX * sin,
+ 0, 0, 1);
+
+ return combine(rotation);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::rotate(float angle, const Vector2f& center)
+{
+ return rotate(angle, center.x, center.y);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::scale(float scaleX, float scaleY)
+{
+ Transform scaling(scaleX, 0, 0,
+ 0, scaleY, 0,
+ 0, 0, 1);
+
+ return combine(scaling);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::scale(float scaleX, float scaleY, float centerX, float centerY)
+{
+ Transform scaling(scaleX, 0, centerX * (1 - scaleX),
+ 0, scaleY, centerY * (1 - scaleY),
+ 0, 0, 1);
+
+ return combine(scaling);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::scale(const Vector2f& factors)
+{
+ return scale(factors.x, factors.y);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& Transform::scale(const Vector2f& factors, const Vector2f& center)
+{
+ return scale(factors.x, factors.y, center.x, center.y);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform operator *(const Transform& left, const Transform& right)
+{
+ return Transform(left).combine(right);
+}
+
+
+////////////////////////////////////////////////////////////
+Transform& operator *=(Transform& left, const Transform& right)
+{
+ return left.combine(right);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2f operator *(const Transform& left, const Vector2f& right)
+{
+ return left.transformPoint(right);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const Transform& left, const Transform& right)
+{
+ const float* a = left.getMatrix();
+ const float* b = right.getMatrix();
+
+ return ((a[0] == b[0]) && (a[1] == b[1]) && (a[3] == b[3]) &&
+ (a[4] == b[4]) && (a[5] == b[5]) && (a[7] == b[7]) &&
+ (a[12] == b[12]) && (a[13] == b[13]) && (a[15] == b[15]));
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const Transform& left, const Transform& right)
+{
+ return !(left == right);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Transformable.cpp b/src/SFML/Graphics/Transformable.cpp
new file mode 100644
index 0000000..8101670
--- /dev/null
+++ b/src/SFML/Graphics/Transformable.cpp
@@ -0,0 +1,219 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Transformable.hpp>
+#include <cmath>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Transformable::Transformable() :
+m_origin (0, 0),
+m_position (0, 0),
+m_rotation (0),
+m_scale (1, 1),
+m_transform (),
+m_transformNeedUpdate (true),
+m_inverseTransform (),
+m_inverseTransformNeedUpdate(true)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Transformable::~Transformable()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setPosition(float x, float y)
+{
+ m_position.x = x;
+ m_position.y = y;
+ m_transformNeedUpdate = true;
+ m_inverseTransformNeedUpdate = true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setPosition(const Vector2f& position)
+{
+ setPosition(position.x, position.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setRotation(float angle)
+{
+ m_rotation = static_cast<float>(fmod(angle, 360));
+ if (m_rotation < 0)
+ m_rotation += 360.f;
+
+ m_transformNeedUpdate = true;
+ m_inverseTransformNeedUpdate = true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setScale(float factorX, float factorY)
+{
+ m_scale.x = factorX;
+ m_scale.y = factorY;
+ m_transformNeedUpdate = true;
+ m_inverseTransformNeedUpdate = true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setScale(const Vector2f& factors)
+{
+ setScale(factors.x, factors.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setOrigin(float x, float y)
+{
+ m_origin.x = x;
+ m_origin.y = y;
+ m_transformNeedUpdate = true;
+ m_inverseTransformNeedUpdate = true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::setOrigin(const Vector2f& origin)
+{
+ setOrigin(origin.x, origin.y);
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& Transformable::getPosition() const
+{
+ return m_position;
+}
+
+
+////////////////////////////////////////////////////////////
+float Transformable::getRotation() const
+{
+ return m_rotation;
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& Transformable::getScale() const
+{
+ return m_scale;
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& Transformable::getOrigin() const
+{
+ return m_origin;
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::move(float offsetX, float offsetY)
+{
+ setPosition(m_position.x + offsetX, m_position.y + offsetY);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::move(const Vector2f& offset)
+{
+ setPosition(m_position.x + offset.x, m_position.y + offset.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::rotate(float angle)
+{
+ setRotation(m_rotation + angle);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::scale(float factorX, float factorY)
+{
+ setScale(m_scale.x * factorX, m_scale.y * factorY);
+}
+
+
+////////////////////////////////////////////////////////////
+void Transformable::scale(const Vector2f& factor)
+{
+ setScale(m_scale.x * factor.x, m_scale.y * factor.y);
+}
+
+
+////////////////////////////////////////////////////////////
+const Transform& Transformable::getTransform() const
+{
+ // Recompute the combined transform if needed
+ if (m_transformNeedUpdate)
+ {
+ float angle = -m_rotation * 3.141592654f / 180.f;
+ float cosine = static_cast<float>(std::cos(angle));
+ float sine = static_cast<float>(std::sin(angle));
+ float sxc = m_scale.x * cosine;
+ float syc = m_scale.y * cosine;
+ float sxs = m_scale.x * sine;
+ float sys = m_scale.y * sine;
+ float tx = -m_origin.x * sxc - m_origin.y * sys + m_position.x;
+ float ty = m_origin.x * sxs - m_origin.y * syc + m_position.y;
+
+ m_transform = Transform( sxc, sys, tx,
+ -sxs, syc, ty,
+ 0.f, 0.f, 1.f);
+ m_transformNeedUpdate = false;
+ }
+
+ return m_transform;
+}
+
+
+////////////////////////////////////////////////////////////
+const Transform& Transformable::getInverseTransform() const
+{
+ // Recompute the inverse transform if needed
+ if (m_inverseTransformNeedUpdate)
+ {
+ m_inverseTransform = getTransform().getInverse();
+ m_inverseTransformNeedUpdate = false;
+ }
+
+ return m_inverseTransform;
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/Vertex.cpp b/src/SFML/Graphics/Vertex.cpp
new file mode 100644
index 0000000..2655f73
--- /dev/null
+++ b/src/SFML/Graphics/Vertex.cpp
@@ -0,0 +1,77 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/Vertex.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Vertex::Vertex() :
+position (0, 0),
+color (255, 255, 255),
+texCoords(0, 0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Vertex::Vertex(const Vector2f& thePosition) :
+position (thePosition),
+color (255, 255, 255),
+texCoords(0, 0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Vertex::Vertex(const Vector2f& thePosition, const Color& theColor) :
+position (thePosition),
+color (theColor),
+texCoords(0, 0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Vertex::Vertex(const Vector2f& thePosition, const Vector2f& theTexCoords) :
+position (thePosition),
+color (255, 255, 255),
+texCoords(theTexCoords)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Vertex::Vertex(const Vector2f& thePosition, const Color& theColor, const Vector2f& theTexCoords) :
+position (thePosition),
+color (theColor),
+texCoords(theTexCoords)
+{
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/VertexArray.cpp b/src/SFML/Graphics/VertexArray.cpp
new file mode 100644
index 0000000..58c98f7
--- /dev/null
+++ b/src/SFML/Graphics/VertexArray.cpp
@@ -0,0 +1,150 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+VertexArray::VertexArray() :
+m_vertices (),
+m_primitiveType(Points)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+VertexArray::VertexArray(PrimitiveType type, std::size_t vertexCount) :
+m_vertices (vertexCount),
+m_primitiveType(type)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t VertexArray::getVertexCount() const
+{
+ return m_vertices.size();
+}
+
+
+////////////////////////////////////////////////////////////
+Vertex& VertexArray::operator [](std::size_t index)
+{
+ return m_vertices[index];
+}
+
+
+////////////////////////////////////////////////////////////
+const Vertex& VertexArray::operator [](std::size_t index) const
+{
+ return m_vertices[index];
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexArray::clear()
+{
+ m_vertices.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexArray::resize(std::size_t vertexCount)
+{
+ m_vertices.resize(vertexCount);
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexArray::append(const Vertex& vertex)
+{
+ m_vertices.push_back(vertex);
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexArray::setPrimitiveType(PrimitiveType type)
+{
+ m_primitiveType = type;
+}
+
+
+////////////////////////////////////////////////////////////
+PrimitiveType VertexArray::getPrimitiveType() const
+{
+ return m_primitiveType;
+}
+
+
+////////////////////////////////////////////////////////////
+FloatRect VertexArray::getBounds() const
+{
+ if (!m_vertices.empty())
+ {
+ float left = m_vertices[0].position.x;
+ float top = m_vertices[0].position.y;
+ float right = m_vertices[0].position.x;
+ float bottom = m_vertices[0].position.y;
+
+ for (std::size_t i = 1; i < m_vertices.size(); ++i)
+ {
+ Vector2f position = m_vertices[i].position;
+
+ // Update left and right
+ if (position.x < left)
+ left = position.x;
+ else if (position.x > right)
+ right = position.x;
+
+ // Update top and bottom
+ if (position.y < top)
+ top = position.y;
+ else if (position.y > bottom)
+ bottom = position.y;
+ }
+
+ return FloatRect(left, top, right - left, bottom - top);
+ }
+ else
+ {
+ // Array is empty
+ return FloatRect();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexArray::draw(RenderTarget& target, RenderStates states) const
+{
+ if (!m_vertices.empty())
+ target.draw(&m_vertices[0], m_vertices.size(), m_primitiveType, states);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/VertexBuffer.cpp b/src/SFML/Graphics/VertexBuffer.cpp
new file mode 100644
index 0000000..8e07980
--- /dev/null
+++ b/src/SFML/Graphics/VertexBuffer.cpp
@@ -0,0 +1,363 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/VertexBuffer.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Graphics/Vertex.hpp>
+#include <SFML/Graphics/GLCheck.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <cstring>
+
+namespace
+{
+ sf::Mutex isAvailableMutex;
+
+ GLenum usageToGlEnum(sf::VertexBuffer::Usage usage)
+ {
+ switch (usage)
+ {
+ case sf::VertexBuffer::Static: return GLEXT_GL_STATIC_DRAW;
+ case sf::VertexBuffer::Dynamic: return GLEXT_GL_DYNAMIC_DRAW;
+ default: return GLEXT_GL_STREAM_DRAW;
+ }
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+VertexBuffer::VertexBuffer() :
+m_buffer (0),
+m_size (0),
+m_primitiveType(Points),
+m_usage (Stream)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::VertexBuffer(PrimitiveType type) :
+m_buffer (0),
+m_size (0),
+m_primitiveType(type),
+m_usage (Stream)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::VertexBuffer(VertexBuffer::Usage usage) :
+m_buffer (0),
+m_size (0),
+m_primitiveType(Points),
+m_usage (usage)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::VertexBuffer(PrimitiveType type, VertexBuffer::Usage usage) :
+m_buffer (0),
+m_size (0),
+m_primitiveType(type),
+m_usage (usage)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::VertexBuffer(const VertexBuffer& copy) :
+m_buffer (0),
+m_size (0),
+m_primitiveType(copy.m_primitiveType),
+m_usage (copy.m_usage)
+{
+ if (copy.m_buffer && copy.m_size)
+ {
+ if (!create(copy.m_size))
+ {
+ err() << "Could not create vertex buffer for copying" << std::endl;
+ return;
+ }
+
+ if (!update(copy))
+ err() << "Could not copy vertex buffer" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::~VertexBuffer()
+{
+ if (m_buffer)
+ {
+ TransientContextLock contextLock;
+
+ glCheck(GLEXT_glDeleteBuffers(1, &m_buffer));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool VertexBuffer::create(std::size_t vertexCount)
+{
+ if (!isAvailable())
+ return false;
+
+ TransientContextLock contextLock;
+
+ if (!m_buffer)
+ glCheck(GLEXT_glGenBuffers(1, &m_buffer));
+
+ if (!m_buffer)
+ {
+ err() << "Could not create vertex buffer, generation failed" << std::endl;
+ return false;
+ }
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
+ glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
+
+ m_size = vertexCount;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t VertexBuffer::getVertexCount() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+bool VertexBuffer::update(const Vertex* vertices)
+{
+ return update(vertices, m_size, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+bool VertexBuffer::update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset)
+{
+ // Sanity checks
+ if (!m_buffer)
+ return false;
+
+ if (!vertices)
+ return false;
+
+ if (offset && (offset + vertexCount > m_size))
+ return false;
+
+ TransientContextLock contextLock;
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
+
+ // Check if we need to resize or orphan the buffer
+ if (vertexCount >= m_size)
+ {
+ glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
+
+ m_size = vertexCount;
+ }
+
+ glCheck(GLEXT_glBufferSubData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * offset, sizeof(Vertex) * vertexCount, vertices));
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool VertexBuffer::update(const VertexBuffer& vertexBuffer)
+{
+#ifdef SFML_OPENGL_ES
+
+ return false;
+
+#else
+
+ if (!m_buffer || !vertexBuffer.m_buffer)
+ return false;
+
+ TransientContextLock contextLock;
+
+ // Make sure that extensions are initialized
+ sf::priv::ensureExtensionsInit();
+
+ if (GLEXT_copy_buffer)
+ {
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, vertexBuffer.m_buffer));
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, m_buffer));
+
+ glCheck(GLEXT_glCopyBufferSubData(GLEXT_GL_COPY_READ_BUFFER, GLEXT_GL_COPY_WRITE_BUFFER, 0, 0, sizeof(Vertex) * vertexBuffer.m_size));
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, 0));
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, 0));
+
+ return true;
+ }
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
+ glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexBuffer.m_size, 0, usageToGlEnum(m_usage)));
+
+ void* destination = 0;
+ glCheck(destination = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_WRITE_ONLY));
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer.m_buffer));
+
+ void* source = 0;
+ glCheck(source = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_READ_ONLY));
+
+ std::memcpy(destination, source, sizeof(Vertex) * vertexBuffer.m_size);
+
+ GLboolean sourceResult = GL_FALSE;
+ glCheck(sourceResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
+
+ GLboolean destinationResult = GL_FALSE;
+ glCheck(destinationResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
+
+ if ((sourceResult == GL_FALSE) || (destinationResult == GL_FALSE))
+ return false;
+
+ return true;
+
+#endif // SFML_OPENGL_ES
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer& VertexBuffer::operator =(const VertexBuffer& right)
+{
+ VertexBuffer temp(right);
+
+ swap(temp);
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexBuffer::swap(VertexBuffer& right)
+{
+ std::swap(m_size, right.m_size);
+ std::swap(m_buffer, right.m_buffer);
+ std::swap(m_primitiveType, right.m_primitiveType);
+ std::swap(m_usage, right.m_usage);
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int VertexBuffer::getNativeHandle() const
+{
+ return m_buffer;
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexBuffer::bind(const VertexBuffer* vertexBuffer)
+{
+ if (!isAvailable())
+ return;
+
+ TransientContextLock lock;
+
+ glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer ? vertexBuffer->m_buffer : 0));
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexBuffer::setPrimitiveType(PrimitiveType type)
+{
+ m_primitiveType = type;
+}
+
+
+////////////////////////////////////////////////////////////
+PrimitiveType VertexBuffer::getPrimitiveType() const
+{
+ return m_primitiveType;
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexBuffer::setUsage(VertexBuffer::Usage usage)
+{
+ m_usage = usage;
+}
+
+
+////////////////////////////////////////////////////////////
+VertexBuffer::Usage VertexBuffer::getUsage() const
+{
+ return m_usage;
+}
+
+
+////////////////////////////////////////////////////////////
+bool VertexBuffer::isAvailable()
+{
+ Lock lock(isAvailableMutex);
+
+ static bool checked = false;
+ static bool available = false;
+
+ if (!checked)
+ {
+ checked = true;
+
+ TransientContextLock contextLock;
+
+ // Make sure that extensions are initialized
+ sf::priv::ensureExtensionsInit();
+
+ available = GLEXT_vertex_buffer_object;
+ }
+
+ return available;
+}
+
+
+////////////////////////////////////////////////////////////
+void VertexBuffer::draw(RenderTarget& target, RenderStates states) const
+{
+ if (m_buffer && m_size)
+ target.draw(*this, 0, m_size, states);
+}
+
+} // namespace sf
diff --git a/src/SFML/Graphics/View.cpp b/src/SFML/Graphics/View.cpp
new file mode 100644
index 0000000..0fcf654
--- /dev/null
+++ b/src/SFML/Graphics/View.cpp
@@ -0,0 +1,240 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/View.hpp>
+#include <cmath>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+View::View() :
+m_center (),
+m_size (),
+m_rotation (0),
+m_viewport (0, 0, 1, 1),
+m_transformUpdated (false),
+m_invTransformUpdated(false)
+{
+ reset(FloatRect(0, 0, 1000, 1000));
+}
+
+
+////////////////////////////////////////////////////////////
+View::View(const FloatRect& rectangle) :
+m_center (),
+m_size (),
+m_rotation (0),
+m_viewport (0, 0, 1, 1),
+m_transformUpdated (false),
+m_invTransformUpdated(false)
+{
+ reset(rectangle);
+}
+
+
+////////////////////////////////////////////////////////////
+View::View(const Vector2f& center, const Vector2f& size) :
+m_center (center),
+m_size (size),
+m_rotation (0),
+m_viewport (0, 0, 1, 1),
+m_transformUpdated (false),
+m_invTransformUpdated(false)
+{
+
+}
+
+////////////////////////////////////////////////////////////
+void View::setCenter(float x, float y)
+{
+ m_center.x = x;
+ m_center.y = y;
+
+ m_transformUpdated = false;
+ m_invTransformUpdated = false;
+}
+
+
+////////////////////////////////////////////////////////////
+void View::setCenter(const Vector2f& center)
+{
+ setCenter(center.x, center.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void View::setSize(float width, float height)
+{
+ m_size.x = width;
+ m_size.y = height;
+
+ m_transformUpdated = false;
+ m_invTransformUpdated = false;
+}
+
+
+////////////////////////////////////////////////////////////
+void View::setSize(const Vector2f& size)
+{
+ setSize(size.x, size.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void View::setRotation(float angle)
+{
+ m_rotation = static_cast<float>(fmod(angle, 360));
+ if (m_rotation < 0)
+ m_rotation += 360.f;
+
+ m_transformUpdated = false;
+ m_invTransformUpdated = false;
+}
+
+
+////////////////////////////////////////////////////////////
+void View::setViewport(const FloatRect& viewport)
+{
+ m_viewport = viewport;
+}
+
+
+////////////////////////////////////////////////////////////
+void View::reset(const FloatRect& rectangle)
+{
+ m_center.x = rectangle.left + rectangle.width / 2.f;
+ m_center.y = rectangle.top + rectangle.height / 2.f;
+ m_size.x = rectangle.width;
+ m_size.y = rectangle.height;
+ m_rotation = 0;
+
+ m_transformUpdated = false;
+ m_invTransformUpdated = false;
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& View::getCenter() const
+{
+ return m_center;
+}
+
+
+////////////////////////////////////////////////////////////
+const Vector2f& View::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+float View::getRotation() const
+{
+ return m_rotation;
+}
+
+
+////////////////////////////////////////////////////////////
+const FloatRect& View::getViewport() const
+{
+ return m_viewport;
+}
+
+
+////////////////////////////////////////////////////////////
+void View::move(float offsetX, float offsetY)
+{
+ setCenter(m_center.x + offsetX, m_center.y + offsetY);
+}
+
+
+////////////////////////////////////////////////////////////
+void View::move(const Vector2f& offset)
+{
+ setCenter(m_center + offset);
+}
+
+
+////////////////////////////////////////////////////////////
+void View::rotate(float angle)
+{
+ setRotation(m_rotation + angle);
+}
+
+
+////////////////////////////////////////////////////////////
+void View::zoom(float factor)
+{
+ setSize(m_size.x * factor, m_size.y * factor);
+}
+
+
+////////////////////////////////////////////////////////////
+const Transform& View::getTransform() const
+{
+ // Recompute the matrix if needed
+ if (!m_transformUpdated)
+ {
+ // Rotation components
+ float angle = m_rotation * 3.141592654f / 180.f;
+ float cosine = static_cast<float>(std::cos(angle));
+ float sine = static_cast<float>(std::sin(angle));
+ float tx = -m_center.x * cosine - m_center.y * sine + m_center.x;
+ float ty = m_center.x * sine - m_center.y * cosine + m_center.y;
+
+ // Projection components
+ float a = 2.f / m_size.x;
+ float b = -2.f / m_size.y;
+ float c = -a * m_center.x;
+ float d = -b * m_center.y;
+
+ // Rebuild the projection matrix
+ m_transform = Transform( a * cosine, a * sine, a * tx + c,
+ -b * sine, b * cosine, b * ty + d,
+ 0.f, 0.f, 1.f);
+ m_transformUpdated = true;
+ }
+
+ return m_transform;
+}
+
+
+////////////////////////////////////////////////////////////
+const Transform& View::getInverseTransform() const
+{
+ // Recompute the matrix if needed
+ if (!m_invTransformUpdated)
+ {
+ m_inverseTransform = getTransform().getInverse();
+ m_invTransformUpdated = true;
+ }
+
+ return m_inverseTransform;
+}
+
+} // namespace sf
diff --git a/src/SFML/Main/CMakeLists.txt b/src/SFML/Main/CMakeLists.txt
new file mode 100644
index 0000000..6542e59
--- /dev/null
+++ b/src/SFML/Main/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Main)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Main)
+
+# sources
+if(SFML_OS_WINDOWS)
+ set(SRC ${SRC} ${SRCROOT}/MainWin32.cpp)
+elseif(SFML_OS_IOS)
+ set(SRC ${SRC} ${SRCROOT}/MainiOS.mm)
+elseif(SFML_OS_ANDROID)
+ set(SRC ${SRC} ${SRCROOT}/MainAndroid.cpp)
+else()
+ return()
+endif()
+
+# define the sfml-main target
+sfml_add_library(sfml-main STATIC SOURCES ${SRC})
+
+# overwrite sfml-main suffix for backward compatibility with FindSFML.cmake
+set_target_properties(sfml-main PROPERTIES
+ DEBUG_POSTFIX -d
+ RELEASE_POSTFIX ""
+ MINSIZEREL_POSTFIX ""
+ RELWITHDEBINFO_POSTFIX "")
+
+# because of a current limitation on Android (which prevents one library
+# from depending on shared libraries), we need a boostrap activity which
+# will load our shared libraries manually
+if(SFML_OS_ANDROID)
+ sfml_add_library(sfml-activity SOURCES ${SRCROOT}/SFMLActivity.cpp)
+endif()
diff --git a/src/SFML/Main/MainAndroid.cpp b/src/SFML/Main/MainAndroid.cpp
new file mode 100644
index 0000000..5e62133
--- /dev/null
+++ b/src/SFML/Main/MainAndroid.cpp
@@ -0,0 +1,567 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Android specific: we define the ANativeActivity_onCreate
+// entry point, handling all the native activity stuff, then
+// we call the user defined (and portable) main function in
+// an external thread so developers can keep a portable code
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#ifdef SFML_SYSTEM_ANDROID
+
+#include <SFML/System/Android/Activity.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Thread.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <android/window.h>
+#include <android/native_activity.h>
+#include <cstring>
+
+
+extern int main(int argc, char *argv[]);
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+int getAndroidApiLevel(ANativeActivity* activity)
+{
+ JNIEnv* lJNIEnv = activity->env;
+
+ jclass versionClass = lJNIEnv->FindClass("android/os/Build$VERSION");
+ if (versionClass == NULL)
+ return 0;
+
+ jfieldID sdkIntFieldID = lJNIEnv->GetStaticFieldID(versionClass, "SDK_INT", "I");
+ if (sdkIntFieldID == NULL)
+ return 0;
+
+ jint sdkInt = 0;
+ sdkInt = lJNIEnv->GetStaticIntField(versionClass, sdkIntFieldID);
+
+ return sdkInt;
+}
+
+
+////////////////////////////////////////////////////////////
+ActivityStates* retrieveStates(ANativeActivity* activity)
+{
+ // Hide the ugly cast we find in each callback function
+ return (ActivityStates*)activity->instance;
+}
+
+
+////////////////////////////////////////////////////////////
+static void initializeMain(ActivityStates* states)
+{
+ // Protect from concurrent access
+ Lock lock(states->mutex);
+
+ // Prepare and share the looper to be read later
+ ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ states->looper = looper;
+
+ /**
+ * Acquire increments a reference counter on the looper. This keeps android
+ * from collecting it before the activity thread has a chance to detach its
+ * input queue.
+ */
+ ALooper_acquire(states->looper);
+
+ // Get the default configuration
+ states->config = AConfiguration_new();
+ AConfiguration_fromAssetManager(states->config, states->activity->assetManager);
+}
+
+
+////////////////////////////////////////////////////////////
+static void terminateMain(ActivityStates* states)
+{
+ // Protect from concurrent access
+ Lock lock(states->mutex);
+
+ // The main thread has finished, we must explicitly ask the activity to finish
+ states->mainOver = true;
+ ANativeActivity_finish(states->activity);
+}
+
+
+////////////////////////////////////////////////////////////
+void* main(ActivityStates* states)
+{
+ // Initialize the thread before giving the hand
+ initializeMain(states);
+
+ sleep(seconds(0.5));
+ ::main(0, NULL);
+
+ // Terminate properly the main thread and wait until it's done
+ terminateMain(states);
+
+ {
+ Lock lock(states->mutex);
+
+ states->terminated = true;
+ }
+
+ return NULL;
+}
+
+} // namespace priv
+} // namespace sf
+
+
+////////////////////////////////////////////////////////////
+void goToFullscreenMode(ANativeActivity* activity)
+{
+ // Get the current Android API level.
+ int apiLevel = sf::priv::getAndroidApiLevel(activity);
+
+ // Hide the status bar
+ ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FULLSCREEN,
+ AWINDOW_FLAG_FULLSCREEN);
+
+ // Hide the navigation bar
+ JavaVM* lJavaVM = activity->vm;
+ JNIEnv* lJNIEnv = activity->env;
+
+ jobject objectActivity = activity->clazz;
+ jclass classActivity = lJNIEnv->GetObjectClass(objectActivity);
+
+ jmethodID methodGetWindow = lJNIEnv->GetMethodID(classActivity, "getWindow", "()Landroid/view/Window;");
+ jobject objectWindow = lJNIEnv->CallObjectMethod(objectActivity, methodGetWindow);
+
+ jclass classWindow = lJNIEnv->FindClass("android/view/Window");
+ jmethodID methodGetDecorView = lJNIEnv->GetMethodID(classWindow, "getDecorView", "()Landroid/view/View;");
+ jobject objectDecorView = lJNIEnv->CallObjectMethod(objectWindow, methodGetDecorView);
+
+ jclass classView = lJNIEnv->FindClass("android/view/View");
+
+ // Default flags
+ jint flags = 0;
+
+ // API Level 14
+ if (apiLevel >= 14)
+ {
+ jfieldID FieldSYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_LOW_PROFILE", "I");
+ jint SYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_LOW_PROFILE);
+ flags |= SYSTEM_UI_FLAG_LOW_PROFILE;
+ }
+
+ // API Level 16
+ if (apiLevel >= 16)
+ {
+ jfieldID FieldSYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
+ jint SYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_FULLSCREEN);
+ flags |= SYSTEM_UI_FLAG_FULLSCREEN;
+ }
+
+ // API Level 19
+ if (apiLevel >= 19)
+ {
+ jfieldID FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");
+ jint SYSTEM_UI_FLAG_IMMERSIVE_STICKY = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ flags |= SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ }
+
+ jmethodID methodsetSystemUiVisibility = lJNIEnv->GetMethodID(classView, "setSystemUiVisibility", "(I)V");
+ lJNIEnv->CallVoidMethod(objectDecorView, methodsetSystemUiVisibility, flags);
+}
+
+////////////////////////////////////////////////////////////
+
+void getScreenSizeInPixels(ANativeActivity* activity, int* width, int* height)
+{
+ // Perform the following Java code:
+ //
+ // DisplayMetrics dm = new DisplayMetrics();
+ // getWindowManager().getDefaultDisplay().getMetrics(dm);
+
+ JavaVM* lJavaVM = activity->vm;
+ JNIEnv* lJNIEnv = activity->env;
+
+ jobject objectActivity = activity->clazz;
+ jclass classActivity = lJNIEnv->GetObjectClass(objectActivity);
+
+ jclass classDisplayMetrics = lJNIEnv->FindClass("android/util/DisplayMetrics");
+ jmethodID initDisplayMetrics = lJNIEnv->GetMethodID(classDisplayMetrics, "<init>", "()V");
+ jobject objectDisplayMetrics = lJNIEnv->NewObject(classDisplayMetrics, initDisplayMetrics);
+
+ jmethodID methodGetWindowManager = lJNIEnv->GetMethodID(classActivity, "getWindowManager", "()Landroid/view/WindowManager;");
+ jobject objectWindowManager = lJNIEnv->CallObjectMethod(objectActivity, methodGetWindowManager);
+
+ jclass classWindowManager = lJNIEnv->FindClass("android/view/WindowManager");
+ jmethodID methodGetDefaultDisplay = lJNIEnv->GetMethodID(classWindowManager, "getDefaultDisplay", "()Landroid/view/Display;");
+ jobject objectDisplay = lJNIEnv->CallObjectMethod(objectWindowManager, methodGetDefaultDisplay);
+
+ jclass classDisplay = lJNIEnv->FindClass("android/view/Display");
+ jmethodID methodGetMetrics = lJNIEnv->GetMethodID(classDisplay, "getMetrics", "(Landroid/util/DisplayMetrics;)V");
+ lJNIEnv->CallVoidMethod(objectDisplay, methodGetMetrics, objectDisplayMetrics);
+
+ jfieldID fieldWidthPixels = lJNIEnv->GetFieldID(classDisplayMetrics, "widthPixels", "I");
+ jfieldID fieldHeightPixels = lJNIEnv->GetFieldID(classDisplayMetrics, "heightPixels", "I");
+
+ *width = lJNIEnv->GetIntField(objectDisplayMetrics, fieldWidthPixels);
+ *height = lJNIEnv->GetIntField(objectDisplayMetrics, fieldHeightPixels);
+}
+
+
+////////////////////////////////////////////////////////////
+static void onStart(ANativeActivity* activity)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void onResume(ANativeActivity* activity)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+ sf::Lock lock(states->mutex);
+
+ if (states->fullscreen)
+ goToFullscreenMode(activity);
+
+ // Send an event to warn people the activity has been resumed
+ sf::Event event;
+ event.type = sf::Event::MouseEntered;
+
+ states->forwardEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+static void onPause(ANativeActivity* activity)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+ sf::Lock lock(states->mutex);
+
+ // Send an event to warn people the activity has been paused
+ sf::Event event;
+ event.type = sf::Event::MouseLeft;
+
+ states->forwardEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+static void onStop(ANativeActivity* activity)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void onDestroy(ANativeActivity* activity)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+
+ // Send an event to warn people the activity is being destroyed
+ {
+ sf::Lock lock(states->mutex);
+
+ // If the main thread hasn't yet finished, send the event and wait for
+ // it to finish.
+ if (!states->mainOver)
+ {
+ sf::Event event;
+ event.type = sf::Event::Closed;
+
+ states->forwardEvent(event);
+ }
+ }
+
+ // Wait for the main thread to be terminated
+ states->mutex.lock();
+
+ while (!states->terminated)
+ {
+ states->mutex.unlock();
+ sf::sleep(sf::milliseconds(20));
+ states->mutex.lock();
+ }
+
+ states->mutex.unlock();
+
+ // Terminate EGL display
+ eglTerminate(states->display);
+
+ // Delete our allocated states
+ delete states;
+
+ // Reset the activity pointer for all modules
+ sf::priv::getActivity(NULL, true);
+
+ // The application should now terminate
+}
+
+
+////////////////////////////////////////////////////////////
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
+{
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+ sf::Lock lock(states->mutex);
+
+ // Update the activity states
+ states->window = window;
+
+ // Notify SFML mechanism
+ sf::Event event;
+ event.type = sf::Event::GainedFocus;
+ states->forwardEvent(event);
+
+ // Wait for the event to be taken into account by SFML
+ states->updated = false;
+ while(!(states->updated | states->terminated))
+ {
+ states->mutex.unlock();
+ sf::sleep(sf::milliseconds(10));
+ states->mutex.lock();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
+{
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+ sf::Lock lock(states->mutex);
+
+ // Update the activity states
+ states->window = NULL;
+
+ // Notify SFML mechanism
+ sf::Event event;
+ event.type = sf::Event::LostFocus;
+ states->forwardEvent(event);
+
+ // Wait for the event to be taken into account by SFML
+ states->updated = false;
+ while(!(states->updated | states->terminated))
+ {
+ states->mutex.unlock();
+ sf::sleep(sf::milliseconds(10));
+ states->mutex.lock();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+
+ // Attach the input queue
+ {
+ sf::Lock lock(states->mutex);
+
+ AInputQueue_attachLooper(queue, states->looper, 1, states->processEvent, NULL);
+ states->inputQueue = queue;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+
+ // Detach the input queue
+ {
+ sf::Lock lock(states->mutex);
+
+ AInputQueue_detachLooper(queue);
+ states->inputQueue = NULL;
+
+ ALooper_release(states->looper);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+static void onWindowFocusChanged(ANativeActivity* activity, int focused)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void onContentRectChanged(ANativeActivity* activity, const ARect* rect)
+{
+ // Retrieve our activity states from the activity instance
+ sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
+ sf::Lock lock(states->mutex);
+
+ // Make sure the window still exists before we access the dimensions on it
+ if (states->window != NULL) {
+ // Send an event to warn people about the window move/resize
+ sf::Event event;
+ event.type = sf::Event::Resized;
+ event.size.width = ANativeWindow_getWidth(states->window);
+ event.size.height = ANativeWindow_getHeight(states->window);
+
+ states->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+static void onConfigurationChanged(ANativeActivity* activity)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
+{
+ *outLen = 0;
+
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+static void onLowMemory(ANativeActivity* activity)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
+{
+ // Create an activity states (will keep us in the know, about events we care)
+ sf::priv::ActivityStates* states = NULL;
+ states = new sf::priv::ActivityStates;
+
+ // Initialize the states value
+ states->activity = NULL;
+ states->window = NULL;
+ states->looper = NULL;
+ states->inputQueue = NULL;
+ states->config = NULL;
+
+ for (unsigned int i = 0; i < sf::Mouse::ButtonCount; i++)
+ states->isButtonPressed[i] = false;
+
+ states->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ if (savedState != NULL)
+ {
+ states->savedState = malloc(savedStateSize);
+ states->savedStateSize = savedStateSize;
+ std::memcpy(states->savedState, savedState, savedStateSize);
+ }
+
+ states->mainOver = false;
+
+ states->initialized = false;
+ states->terminated = false;
+
+ // Share it across the SFML modules
+ sf::priv::getActivity(states, true);
+
+ // These functions will update the activity states and therefore, will allow
+ // SFML to be kept in the know
+ activity->callbacks->onStart = onStart;
+ activity->callbacks->onResume = onResume;
+ activity->callbacks->onPause = onPause;
+ activity->callbacks->onStop = onStop;
+ activity->callbacks->onDestroy = onDestroy;
+
+ activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+ activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+ activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
+ activity->callbacks->onNativeWindowResized = onNativeWindowResized;
+
+ activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+ activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+
+ activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+ activity->callbacks->onContentRectChanged = onContentRectChanged;
+ activity->callbacks->onConfigurationChanged = onConfigurationChanged;
+
+ activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+ activity->callbacks->onLowMemory = onLowMemory;
+
+ // Share this activity with the callback functions
+ states->activity = activity;
+
+ // Keep the screen turned on and bright
+ ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON,
+ AWINDOW_FLAG_KEEP_SCREEN_ON);
+
+ // Initialize the display
+ eglInitialize(states->display, NULL, NULL);
+
+ getScreenSizeInPixels(activity, &states->screenSize.x, &states->screenSize.y);
+
+ // Redirect error messages to logcat
+ sf::err().rdbuf(&states->logcat);
+
+ // Launch the main thread
+ sf::Thread* thread = new sf::Thread(sf::priv::main, states);
+ thread->launch();
+
+ // Wait for the main thread to be initialized
+ states->mutex.lock();
+
+ while (!(states->initialized | states->terminated))
+ {
+ states->mutex.unlock();
+ sf::sleep(sf::milliseconds(20));
+ states->mutex.lock();
+ }
+
+ states->mutex.unlock();
+
+ // Share this state with the callback functions
+ activity->instance = states;
+}
+
+#endif // SFML_SYSTEM_ANDROID
diff --git a/src/SFML/Main/MainWin32.cpp b/src/SFML/Main/MainWin32.cpp
new file mode 100644
index 0000000..fefc1b7
--- /dev/null
+++ b/src/SFML/Main/MainWin32.cpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Laurent Gomila (laurent@sfml-dev.org)
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Windows specific: we define the WinMain entry point,
+// so that developers can use the standard main function
+// even in a Win32 Application project, and thus keep a
+// portable code
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#ifdef SFML_SYSTEM_WINDOWS
+
+#include <windows.h>
+
+extern int main(int argc, char* argv[]);
+
+////////////////////////////////////////////////////////////
+int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
+{
+ return main(__argc, __argv);
+}
+
+#endif // SFML_SYSTEM_WINDOWS
+
diff --git a/src/SFML/Main/MainiOS.mm b/src/SFML/Main/MainiOS.mm
new file mode 100644
index 0000000..fa88e69
--- /dev/null
+++ b/src/SFML/Main/MainiOS.mm
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Laurent Gomila (laurent@sfml-dev.prg)
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// iOS specific: SFML needs to hook the main function, to
+// launch the iOS application (event loop), and then call the
+// user main from inside it.
+//
+// Our strategy is to rename the user main to 'sfmlMain' with
+// a macro (see Main.hpp), and call this modified main ourselves.
+//
+// Note that half of this trick (the sfmlMain placeholders and
+// the application delegate) is defined sfml-window; see there
+// for the full implementation.
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#ifdef SFML_SYSTEM_IOS
+
+#include <UIKit/UIKit.h>
+
+
+////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+ // Note: we intentionally drop command line arguments,
+ // there's no such thing as a command line on an iOS device :)
+
+ // Important: "SFAppDelegate" must always match the name of the
+ // application delegate class defined in sfml-window
+
+ return UIApplicationMain(argc, argv, nil, @"SFAppDelegate");
+}
+
+#endif // SFML_SYSTEM_IOS
diff --git a/src/SFML/Main/SFMLActivity.cpp b/src/SFML/Main/SFMLActivity.cpp
new file mode 100644
index 0000000..caf191b
--- /dev/null
+++ b/src/SFML/Main/SFMLActivity.cpp
@@ -0,0 +1,207 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#include <SFML/Config.hpp>
+#include <android/native_activity.h>
+#include <android/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <jni.h>
+#include <string>
+
+#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "sfml-activity", __VA_ARGS__))
+
+namespace {
+ typedef void (*activityOnCreatePointer)(ANativeActivity*, void*, size_t);
+}
+
+const char *getLibraryName(JNIEnv* lJNIEnv, jobject& objectActivityInfo)
+{
+ // This function reads the value of meta-data "sfml.app.lib_name"
+ // found in the Android Manifest file and returns it. It performs the
+ // following Java code using the JNI interface:
+ //
+ // ai.metaData.getString("sfml.app.lib_name");
+ static char name[256];
+
+ // Get metaData instance from the ActivityInfo object
+ jclass classActivityInfo = lJNIEnv->FindClass("android/content/pm/ActivityInfo");
+ jfieldID fieldMetaData = lJNIEnv->GetFieldID(classActivityInfo, "metaData", "Landroid/os/Bundle;");
+ jobject objectMetaData = lJNIEnv->GetObjectField(objectActivityInfo, fieldMetaData);
+
+ // Create a java string object containing "sfml.app.lib_name"
+ jobject objectName = lJNIEnv->NewStringUTF("sfml.app.lib_name");
+
+ // Get the value of meta-data named "sfml.app.lib_name"
+ jclass classBundle = lJNIEnv->FindClass("android/os/Bundle");
+ jmethodID methodGetString = lJNIEnv->GetMethodID(classBundle, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
+ jstring valueString = (jstring)lJNIEnv->CallObjectMethod(objectMetaData, methodGetString, objectName);
+
+ // No meta-data "sfml.app.lib_name" was found so we abort and inform the user
+ if (valueString == NULL)
+ {
+ LOGE("No meta-data 'sfml.app.lib_name' found in AndroidManifest.xml file");
+ exit(1);
+ }
+
+ // Convert the application name to a C++ string and return it
+ const jsize applicationNameLength = lJNIEnv->GetStringUTFLength(valueString);
+ const char* applicationName = lJNIEnv->GetStringUTFChars(valueString, NULL);
+
+ if (applicationNameLength >= 256)
+ {
+ LOGE("The value of 'sfml.app.lib_name' must not be longer than 255 characters.");
+ exit(1);
+ }
+
+ strncpy(name, applicationName, applicationNameLength);
+ name[applicationNameLength] = '\0';
+ lJNIEnv->ReleaseStringUTFChars(valueString, applicationName);
+
+ return name;
+}
+
+void* loadLibrary(const char* libraryName, JNIEnv* lJNIEnv, jobject& ObjectActivityInfo)
+{
+ // Find out the absolute path of the library
+ jclass ClassActivityInfo = lJNIEnv->FindClass("android/content/pm/ActivityInfo");
+ jfieldID FieldApplicationInfo = lJNIEnv->GetFieldID(ClassActivityInfo, "applicationInfo", "Landroid/content/pm/ApplicationInfo;");
+ jobject ObjectApplicationInfo = lJNIEnv->GetObjectField(ObjectActivityInfo, FieldApplicationInfo);
+
+ jclass ClassApplicationInfo = lJNIEnv->FindClass("android/content/pm/ApplicationInfo");
+ jfieldID FieldNativeLibraryDir = lJNIEnv->GetFieldID(ClassApplicationInfo, "nativeLibraryDir", "Ljava/lang/String;");
+
+ jobject ObjectDirPath = lJNIEnv->GetObjectField(ObjectApplicationInfo, FieldNativeLibraryDir);
+
+ jclass ClassSystem = lJNIEnv->FindClass("java/lang/System");
+ jmethodID StaticMethodMapLibraryName = lJNIEnv->GetStaticMethodID(ClassSystem, "mapLibraryName", "(Ljava/lang/String;)Ljava/lang/String;");
+
+ jstring LibNameObject = lJNIEnv->NewStringUTF(libraryName);
+ jobject ObjectName = lJNIEnv->CallStaticObjectMethod(ClassSystem, StaticMethodMapLibraryName, LibNameObject);
+
+ jclass ClassFile = lJNIEnv->FindClass("java/io/File");
+ jmethodID FileConstructor = lJNIEnv->GetMethodID(ClassFile, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
+ jobject ObjectFile = lJNIEnv->NewObject(ClassFile, FileConstructor, ObjectDirPath, ObjectName);
+
+ // Get the library absolute path and convert it
+ jmethodID MethodGetPath = lJNIEnv->GetMethodID(ClassFile, "getPath", "()Ljava/lang/String;");
+ jstring javaLibraryPath = static_cast<jstring>(lJNIEnv->CallObjectMethod(ObjectFile, MethodGetPath));
+ const char* libraryPath = lJNIEnv->GetStringUTFChars(javaLibraryPath, NULL);
+
+ // Manually load the library
+ void * handle = dlopen(libraryPath, RTLD_NOW | RTLD_GLOBAL);
+ if (!handle)
+ {
+ LOGE("dlopen(\"%s\"): %s", libraryPath, dlerror());
+ exit(1);
+ }
+
+ // Release the Java string
+ lJNIEnv->ReleaseStringUTFChars(javaLibraryPath, libraryPath);
+
+ return handle;
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
+{
+ // Before we can load a library, we need to find out its location. As
+ // we're powerless here in C/C++, we need the JNI interface to communicate
+ // with the attached Java virtual machine and perform some Java calls in
+ // order to retrieve the absolute path of our libraries.
+ //
+ // Here's the snippet of Java code it performs:
+ // --------------------------------------------
+ // ai = getPackageManager().getActivityInfo(getIntent().getComponent(), PackageManager.GET_META_DATA);
+ // File libraryFile = new File(ai.applicationInfo.nativeLibraryDir, System.mapLibraryName(libname));
+ // String path = libraryFile.getPath();
+ //
+ // With libname being the library name such as "jpeg".
+
+ // Retrieve JNI environment and JVM instance
+ JavaVM* lJavaVM = activity->vm;
+ JNIEnv* lJNIEnv = activity->env;
+
+ // Retrieve the NativeActivity
+ jobject ObjectNativeActivity = activity->clazz;
+ jclass ClassNativeActivity = lJNIEnv->GetObjectClass(ObjectNativeActivity);
+
+ // Retrieve the ActivityInfo
+ jmethodID MethodGetPackageManager = lJNIEnv->GetMethodID(ClassNativeActivity, "getPackageManager", "()Landroid/content/pm/PackageManager;");
+ jobject ObjectPackageManager = lJNIEnv->CallObjectMethod(ObjectNativeActivity, MethodGetPackageManager);
+
+ jmethodID MethodGetIndent = lJNIEnv->GetMethodID(ClassNativeActivity, "getIntent", "()Landroid/content/Intent;");
+ jobject ObjectIntent = lJNIEnv->CallObjectMethod(ObjectNativeActivity, MethodGetIndent);
+
+ jclass ClassIntent = lJNIEnv->FindClass("android/content/Intent");
+ jmethodID MethodGetComponent = lJNIEnv->GetMethodID(ClassIntent, "getComponent", "()Landroid/content/ComponentName;");
+
+ jobject ObjectComponentName = lJNIEnv->CallObjectMethod(ObjectIntent, MethodGetComponent);
+
+ jclass ClassPackageManager = lJNIEnv->FindClass("android/content/pm/PackageManager");
+
+ jfieldID FieldGET_META_DATA = lJNIEnv->GetStaticFieldID(ClassPackageManager, "GET_META_DATA", "I");
+ jint GET_META_DATA = lJNIEnv->GetStaticIntField(ClassPackageManager, FieldGET_META_DATA);
+
+ jmethodID MethodGetActivityInfo = lJNIEnv->GetMethodID(ClassPackageManager, "getActivityInfo", "(Landroid/content/ComponentName;I)Landroid/content/pm/ActivityInfo;");
+ jobject ObjectActivityInfo = lJNIEnv->CallObjectMethod(ObjectPackageManager, MethodGetActivityInfo, ObjectComponentName, GET_META_DATA);
+
+ // Load our libraries in reverse order
+#if defined(STL_LIBRARY)
+#define _SFML_QS(s) _SFML_S(s)
+#define _SFML_S(s) #s
+ loadLibrary(_SFML_QS(STL_LIBRARY), lJNIEnv, ObjectActivityInfo);
+#undef _SFML_S
+#undef _SFML_QS
+#endif
+ loadLibrary("openal", lJNIEnv, ObjectActivityInfo);
+
+#if !defined(SFML_DEBUG)
+ loadLibrary("sfml-system", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-window", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-graphics", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-audio", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-network", lJNIEnv, ObjectActivityInfo);
+#else
+ loadLibrary("sfml-system-d", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-window-d", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-graphics-d", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-audio-d", lJNIEnv, ObjectActivityInfo);
+ loadLibrary("sfml-network-d", lJNIEnv, ObjectActivityInfo);
+#endif
+
+ void* handle = loadLibrary(getLibraryName(lJNIEnv, ObjectActivityInfo), lJNIEnv, ObjectActivityInfo);
+
+ // Call the original ANativeActivity_onCreate function
+ activityOnCreatePointer ANativeActivity_onCreate = (activityOnCreatePointer)dlsym(handle, "ANativeActivity_onCreate");
+
+ if (!ANativeActivity_onCreate)
+ {
+ LOGE("sfml-activity: Undefined symbol ANativeActivity_onCreate");
+ exit(1);
+ }
+
+ ANativeActivity_onCreate(activity, savedState, savedStateSize);
+}
diff --git a/src/SFML/Network/CMakeLists.txt b/src/SFML/Network/CMakeLists.txt
new file mode 100644
index 0000000..6626d73
--- /dev/null
+++ b/src/SFML/Network/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Network)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Network)
+
+# all source files
+set(SRC
+ ${INCROOT}/Export.hpp
+ ${SRCROOT}/Ftp.cpp
+ ${INCROOT}/Ftp.hpp
+ ${SRCROOT}/Http.cpp
+ ${INCROOT}/Http.hpp
+ ${SRCROOT}/IpAddress.cpp
+ ${INCROOT}/IpAddress.hpp
+ ${SRCROOT}/Packet.cpp
+ ${INCROOT}/Packet.hpp
+ ${SRCROOT}/Socket.cpp
+ ${INCROOT}/Socket.hpp
+ ${SRCROOT}/SocketImpl.hpp
+ ${INCROOT}/SocketHandle.hpp
+ ${SRCROOT}/SocketSelector.cpp
+ ${INCROOT}/SocketSelector.hpp
+ ${SRCROOT}/TcpListener.cpp
+ ${INCROOT}/TcpListener.hpp
+ ${SRCROOT}/TcpSocket.cpp
+ ${INCROOT}/TcpSocket.hpp
+ ${SRCROOT}/UdpSocket.cpp
+ ${INCROOT}/UdpSocket.hpp
+)
+
+# add platform specific sources
+if(SFML_OS_WINDOWS)
+ set(SRC
+ ${SRC}
+ ${SRCROOT}/Win32/SocketImpl.cpp
+ ${SRCROOT}/Win32/SocketImpl.hpp
+ )
+else()
+ set(SRC
+ ${SRC}
+ ${SRCROOT}/Unix/SocketImpl.cpp
+ ${SRCROOT}/Unix/SocketImpl.hpp
+ )
+endif()
+
+source_group("" FILES ${SRC})
+
+# define the sfml-network target
+sfml_add_library(sfml-network
+ SOURCES ${SRC})
+
+# setup dependencies
+target_link_libraries(sfml-network PUBLIC sfml-system)
+if(SFML_OS_WINDOWS)
+ target_link_libraries(sfml-network PRIVATE ws2_32)
+endif()
diff --git a/src/SFML/Network/Ftp.cpp b/src/SFML/Network/Ftp.cpp
new file mode 100644
index 0000000..41a630f
--- /dev/null
+++ b/src/SFML/Network/Ftp.cpp
@@ -0,0 +1,653 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Ftp.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cctype>
+#include <fstream>
+#include <iterator>
+#include <sstream>
+#include <cstdio>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+class Ftp::DataChannel : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ DataChannel(Ftp& owner);
+
+ ////////////////////////////////////////////////////////////
+ Ftp::Response open(Ftp::TransferMode mode);
+
+ ////////////////////////////////////////////////////////////
+ void send(std::istream& stream);
+
+ ////////////////////////////////////////////////////////////
+ void receive(std::ostream& stream);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Ftp& m_ftp; ///< Reference to the owner Ftp instance
+ TcpSocket m_dataSocket; ///< Socket used for data transfers
+};
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response::Response(Status code, const std::string& message) :
+m_status (code),
+m_message(message)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+bool Ftp::Response::isOk() const
+{
+ return m_status < 400;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response::Status Ftp::Response::getStatus() const
+{
+ return m_status;
+}
+
+
+////////////////////////////////////////////////////////////
+const std::string& Ftp::Response::getMessage() const
+{
+ return m_message;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse::DirectoryResponse(const Ftp::Response& response) :
+Ftp::Response(response)
+{
+ if (isOk())
+ {
+ // Extract the directory from the server response
+ std::string::size_type begin = getMessage().find('"', 0);
+ std::string::size_type end = getMessage().find('"', begin + 1);
+ m_directory = getMessage().substr(begin + 1, end - begin - 1);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::string& Ftp::DirectoryResponse::getDirectory() const
+{
+ return m_directory;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse::ListingResponse(const Ftp::Response& response, const std::string& data) :
+Ftp::Response(response)
+{
+ if (isOk())
+ {
+ // Fill the array of strings
+ std::string::size_type lastPos = 0;
+ for (std::string::size_type pos = data.find("\r\n"); pos != std::string::npos; pos = data.find("\r\n", lastPos))
+ {
+ m_listing.push_back(data.substr(lastPos, pos - lastPos));
+ lastPos = pos + 2;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::vector<std::string>& Ftp::ListingResponse::getListing() const
+{
+ return m_listing;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::~Ftp()
+{
+ disconnect();
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::connect(const IpAddress& server, unsigned short port, Time timeout)
+{
+ // Connect to the server
+ if (m_commandSocket.connect(server, port, timeout) != Socket::Done)
+ return Response(Response::ConnectionFailed);
+
+ // Get the response to the connection
+ return getResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::login()
+{
+ return login("anonymous", "user@sfml-dev.org");
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::login(const std::string& name, const std::string& password)
+{
+ Response response = sendCommand("USER", name);
+ if (response.isOk())
+ response = sendCommand("PASS", password);
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::disconnect()
+{
+ // Send the exit command
+ Response response = sendCommand("QUIT");
+ if (response.isOk())
+ m_commandSocket.disconnect();
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::keepAlive()
+{
+ return sendCommand("NOOP");
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse Ftp::getWorkingDirectory()
+{
+ return DirectoryResponse(sendCommand("PWD"));
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse Ftp::getDirectoryListing(const std::string& directory)
+{
+ // Open a data channel on default port (20) using ASCII transfer mode
+ std::ostringstream directoryData;
+ DataChannel data(*this);
+ Response response = data.open(Ascii);
+ if (response.isOk())
+ {
+ // Tell the server to send us the listing
+ response = sendCommand("NLST", directory);
+ if (response.isOk())
+ {
+ // Receive the listing
+ data.receive(directoryData);
+
+ // Get the response from the server
+ response = getResponse();
+ }
+ }
+
+ return ListingResponse(response, directoryData.str());
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::changeDirectory(const std::string& directory)
+{
+ return sendCommand("CWD", directory);
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::parentDirectory()
+{
+ return sendCommand("CDUP");
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::createDirectory(const std::string& name)
+{
+ return sendCommand("MKD", name);
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::deleteDirectory(const std::string& name)
+{
+ return sendCommand("RMD", name);
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::renameFile(const std::string& file, const std::string& newName)
+{
+ Response response = sendCommand("RNFR", file);
+ if (response.isOk())
+ response = sendCommand("RNTO", newName);
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::deleteFile(const std::string& name)
+{
+ return sendCommand("DELE", name);
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::download(const std::string& remoteFile, const std::string& localPath, TransferMode mode)
+{
+ // Open a data channel using the given transfer mode
+ DataChannel data(*this);
+ Response response = data.open(mode);
+ if (response.isOk())
+ {
+ // Tell the server to start the transfer
+ response = sendCommand("RETR", remoteFile);
+ if (response.isOk())
+ {
+ // Extract the filename from the file path
+ std::string filename = remoteFile;
+ std::string::size_type pos = filename.find_last_of("/\\");
+ if (pos != std::string::npos)
+ filename = filename.substr(pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string path = localPath;
+ if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
+ path += "/";
+
+ // Create the file and truncate it if necessary
+ std::ofstream file((path + filename).c_str(), std::ios_base::binary | std::ios_base::trunc);
+ if (!file)
+ return Response(Response::InvalidFile);
+
+ // Receive the file data
+ data.receive(file);
+
+ // Close the file
+ file.close();
+
+ // Get the response from the server
+ response = getResponse();
+
+ // If the download was unsuccessful, delete the partial file
+ if (!response.isOk())
+ std::remove((path + filename).c_str());
+ }
+ }
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::upload(const std::string& localFile, const std::string& remotePath, TransferMode mode, bool append)
+{
+ // Get the contents of the file to send
+ std::ifstream file(localFile.c_str(), std::ios_base::binary);
+ if (!file)
+ return Response(Response::InvalidFile);
+
+ // Extract the filename from the file path
+ std::string filename = localFile;
+ std::string::size_type pos = filename.find_last_of("/\\");
+ if (pos != std::string::npos)
+ filename = filename.substr(pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string path = remotePath;
+ if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
+ path += "/";
+
+ // Open a data channel using the given transfer mode
+ DataChannel data(*this);
+ Response response = data.open(mode);
+ if (response.isOk())
+ {
+ // Tell the server to start the transfer
+ response = sendCommand(append ? "APPE" : "STOR", path + filename);
+ if (response.isOk())
+ {
+ // Send the file data
+ data.send(file);
+
+ // Get the response from the server
+ response = getResponse();
+ }
+ }
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::sendCommand(const std::string& command, const std::string& parameter)
+{
+ // Build the command string
+ std::string commandStr;
+ if (parameter != "")
+ commandStr = command + " " + parameter + "\r\n";
+ else
+ commandStr = command + "\r\n";
+
+ // Send it to the server
+ if (m_commandSocket.send(commandStr.c_str(), commandStr.length()) != Socket::Done)
+ return Response(Response::ConnectionClosed);
+
+ // Get the response
+ return getResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::getResponse()
+{
+ // We'll use a variable to keep track of the last valid code.
+ // It is useful in case of multi-lines responses, because the end of such a response
+ // will start by the same code
+ unsigned int lastCode = 0;
+ bool isInsideMultiline = false;
+ std::string message;
+
+ for (;;)
+ {
+ // Receive the response from the server
+ char buffer[1024];
+ std::size_t length;
+
+ if (m_receiveBuffer.empty())
+ {
+ if (m_commandSocket.receive(buffer, sizeof(buffer), length) != Socket::Done)
+ return Response(Response::ConnectionClosed);
+ }
+ else
+ {
+ std::copy(m_receiveBuffer.begin(), m_receiveBuffer.end(), buffer);
+ length = m_receiveBuffer.size();
+ m_receiveBuffer.clear();
+ }
+
+ // There can be several lines inside the received buffer, extract them all
+ std::istringstream in(std::string(buffer, length), std::ios_base::binary);
+ while (in)
+ {
+ // Try to extract the code
+ unsigned int code;
+ if (in >> code)
+ {
+ // Extract the separator
+ char separator;
+ in.get(separator);
+
+ // The '-' character means a multiline response
+ if ((separator == '-') && !isInsideMultiline)
+ {
+ // Set the multiline flag
+ isInsideMultiline = true;
+
+ // Keep track of the code
+ if (lastCode == 0)
+ lastCode = code;
+
+ // Extract the line
+ std::getline(in, message);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ message.erase(message.length() - 1);
+ message = separator + message + "\n";
+ }
+ else
+ {
+ // We must make sure that the code is the same, otherwise it means
+ // we haven't reached the end of the multiline response
+ if ((separator != '-') && ((code == lastCode) || (lastCode == 0)))
+ {
+ // Extract the line
+ std::string line;
+ std::getline(in, line);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ line.erase(line.length() - 1);
+
+ // Append it to the message
+ if (code == lastCode)
+ {
+ std::ostringstream out;
+ out << code << separator << line;
+ message += out.str();
+ }
+ else
+ {
+ message = separator + line;
+ }
+
+ // Save the remaining data for the next time getResponse() is called
+ m_receiveBuffer.assign(buffer + static_cast<std::size_t>(in.tellg()), length - static_cast<std::size_t>(in.tellg()));
+
+ // Return the response code and message
+ return Response(static_cast<Response::Status>(code), message);
+ }
+ else
+ {
+ // The line we just read was actually not a response,
+ // only a new part of the current multiline response
+
+ // Extract the line
+ std::string line;
+ std::getline(in, line);
+
+ if (!line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ line.erase(line.length() - 1);
+
+ // Append it to the current message
+ std::ostringstream out;
+ out << code << separator << line << "\n";
+ message += out.str();
+ }
+ }
+ }
+ }
+ else if (lastCode != 0)
+ {
+ // It seems we are in the middle of a multiline response
+
+ // Clear the error bits of the stream
+ in.clear();
+
+ // Extract the line
+ std::string line;
+ std::getline(in, line);
+
+ if (!line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ line.erase(line.length() - 1);
+
+ // Append it to the current message
+ message += line + "\n";
+ }
+ }
+ else
+ {
+ // Error: cannot extract the code, and we are not in a multiline response
+ return Response(Response::InvalidResponse);
+ }
+ }
+ }
+
+ // We never reach there
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::DataChannel::DataChannel(Ftp& owner) :
+m_ftp(owner)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DataChannel::open(Ftp::TransferMode mode)
+{
+ // Open a data connection in active mode (we connect to the server)
+ Ftp::Response response = m_ftp.sendCommand("PASV");
+ if (response.isOk())
+ {
+ // Extract the connection address and port from the response
+ std::string::size_type begin = response.getMessage().find_first_of("0123456789");
+ if (begin != std::string::npos)
+ {
+ Uint8 data[6] = {0, 0, 0, 0, 0, 0};
+ std::string str = response.getMessage().substr(begin);
+ std::size_t index = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ // Extract the current number
+ while (isdigit(str[index]))
+ {
+ data[i] = data[i] * 10 + (str[index] - '0');
+ index++;
+ }
+
+ // Skip separator
+ index++;
+ }
+
+ // Reconstruct connection port and address
+ unsigned short port = data[4] * 256 + data[5];
+ IpAddress address(static_cast<Uint8>(data[0]),
+ static_cast<Uint8>(data[1]),
+ static_cast<Uint8>(data[2]),
+ static_cast<Uint8>(data[3]));
+
+ // Connect the data channel to the server
+ if (m_dataSocket.connect(address, port) == Socket::Done)
+ {
+ // Translate the transfer mode to the corresponding FTP parameter
+ std::string modeStr;
+ switch (mode)
+ {
+ case Ftp::Binary: modeStr = "I"; break;
+ case Ftp::Ascii: modeStr = "A"; break;
+ case Ftp::Ebcdic: modeStr = "E"; break;
+ }
+
+ // Set the transfer mode
+ response = m_ftp.sendCommand("TYPE", modeStr);
+ }
+ else
+ {
+ // Failed to connect to the server
+ response = Ftp::Response(Ftp::Response::ConnectionFailed);
+ }
+ }
+ }
+
+ return response;
+}
+
+
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::receive(std::ostream& stream)
+{
+ // Receive data
+ char buffer[1024];
+ std::size_t received;
+ while (m_dataSocket.receive(buffer, sizeof(buffer), received) == Socket::Done)
+ {
+ stream.write(buffer, static_cast<std::streamsize>(received));
+
+ if (!stream.good())
+ {
+ err() << "FTP Error: Writing to the file has failed" << std::endl;
+ break;
+ }
+ }
+
+ // Close the data socket
+ m_dataSocket.disconnect();
+}
+
+
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::send(std::istream& stream)
+{
+ // Send data
+ char buffer[1024];
+ std::size_t count;
+
+ for (;;)
+ {
+ // read some data from the stream
+ stream.read(buffer, sizeof(buffer));
+
+ if (!stream.good() && !stream.eof())
+ {
+ err() << "FTP Error: Reading from the file has failed" << std::endl;
+ break;
+ }
+
+ count = static_cast<std::size_t>(stream.gcount());
+
+ if (count > 0)
+ {
+ // we could read more data from the stream: send them
+ if (m_dataSocket.send(buffer, count) != Socket::Done)
+ break;
+ }
+ else
+ {
+ // no more data: exit the loop
+ break;
+ }
+ }
+
+ // Close the data socket
+ m_dataSocket.disconnect();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Http.cpp b/src/SFML/Network/Http.cpp
new file mode 100644
index 0000000..7fdc81a
--- /dev/null
+++ b/src/SFML/Network/Http.cpp
@@ -0,0 +1,415 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Http.hpp>
+#include <SFML/System/Err.hpp>
+#include <cctype>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+#include <limits>
+
+
+namespace
+{
+ // Convert a string to lower case
+ std::string toLower(std::string str)
+ {
+ for (std::string::iterator i = str.begin(); i != str.end(); ++i)
+ *i = static_cast<char>(std::tolower(*i));
+ return str;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Http::Request::Request(const std::string& uri, Method method, const std::string& body)
+{
+ setMethod(method);
+ setUri(uri);
+ setHttpVersion(1, 0);
+ setBody(body);
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Request::setField(const std::string& field, const std::string& value)
+{
+ m_fields[toLower(field)] = value;
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Request::setMethod(Http::Request::Method method)
+{
+ m_method = method;
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Request::setUri(const std::string& uri)
+{
+ m_uri = uri;
+
+ // Make sure it starts with a '/'
+ if (m_uri.empty() || (m_uri[0] != '/'))
+ m_uri.insert(0, "/");
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Request::setHttpVersion(unsigned int major, unsigned int minor)
+{
+ m_majorVersion = major;
+ m_minorVersion = minor;
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Request::setBody(const std::string& body)
+{
+ m_body = body;
+}
+
+
+////////////////////////////////////////////////////////////
+std::string Http::Request::prepare() const
+{
+ std::ostringstream out;
+
+ // Convert the method to its string representation
+ std::string method;
+ switch (m_method)
+ {
+ case Get: method = "GET"; break;
+ case Post: method = "POST"; break;
+ case Head: method = "HEAD"; break;
+ case Put: method = "PUT"; break;
+ case Delete: method = "DELETE"; break;
+ }
+
+ // Write the first line containing the request type
+ out << method << " " << m_uri << " ";
+ out << "HTTP/" << m_majorVersion << "." << m_minorVersion << "\r\n";
+
+ // Write fields
+ for (FieldTable::const_iterator i = m_fields.begin(); i != m_fields.end(); ++i)
+ {
+ out << i->first << ": " << i->second << "\r\n";
+ }
+
+ // Use an extra \r\n to separate the header from the body
+ out << "\r\n";
+
+ // Add the body
+ out << m_body;
+
+ return out.str();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Http::Request::hasField(const std::string& field) const
+{
+ return m_fields.find(toLower(field)) != m_fields.end();
+}
+
+
+////////////////////////////////////////////////////////////
+Http::Response::Response() :
+m_status (ConnectionFailed),
+m_majorVersion(0),
+m_minorVersion(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::getField(const std::string& field) const
+{
+ FieldTable::const_iterator it = m_fields.find(toLower(field));
+ if (it != m_fields.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ static const std::string empty = "";
+ return empty;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Http::Response::Status Http::Response::getStatus() const
+{
+ return m_status;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::getMajorHttpVersion() const
+{
+ return m_majorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::getMinorHttpVersion() const
+{
+ return m_minorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::getBody() const
+{
+ return m_body;
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Response::parse(const std::string& data)
+{
+ std::istringstream in(data);
+
+ // Extract the HTTP version from the first line
+ std::string version;
+ if (in >> version)
+ {
+ if ((version.size() >= 8) && (version[6] == '.') &&
+ (toLower(version.substr(0, 5)) == "http/") &&
+ isdigit(version[5]) && isdigit(version[7]))
+ {
+ m_majorVersion = version[5] - '0';
+ m_minorVersion = version[7] - '0';
+ }
+ else
+ {
+ // Invalid HTTP version
+ m_status = InvalidResponse;
+ return;
+ }
+ }
+
+ // Extract the status code from the first line
+ int status;
+ if (in >> status)
+ {
+ m_status = static_cast<Status>(status);
+ }
+ else
+ {
+ // Invalid status code
+ m_status = InvalidResponse;
+ return;
+ }
+
+ // Ignore the end of the first line
+ in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ // Parse the other lines, which contain fields, one by one
+ parseFields(in);
+
+ m_body.clear();
+
+ // Determine whether the transfer is chunked
+ if (toLower(getField("transfer-encoding")) != "chunked")
+ {
+ // Not chunked - just read everything at once
+ std::copy(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), std::back_inserter(m_body));
+ }
+ else
+ {
+ // Chunked - have to read chunk by chunk
+ std::size_t length;
+
+ // Read all chunks, identified by a chunk-size not being 0
+ while (in >> std::hex >> length)
+ {
+ // Drop the rest of the line (chunk-extension)
+ in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ // Copy the actual content data
+ std::istreambuf_iterator<char> it(in);
+ std::istreambuf_iterator<char> itEnd;
+ for (std::size_t i = 0; ((i < length) && (it != itEnd)); i++)
+ m_body.push_back(*it++);
+ }
+
+ // Drop the rest of the line (chunk-extension)
+ in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ // Read all trailers (if present)
+ parseFields(in);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::Response::parseFields(std::istream &in)
+{
+ std::string line;
+ while (std::getline(in, line) && (line.size() > 2))
+ {
+ std::string::size_type pos = line.find(": ");
+ if (pos != std::string::npos)
+ {
+ // Extract the field name and its value
+ std::string field = line.substr(0, pos);
+ std::string value = line.substr(pos + 2);
+
+ // Remove any trailing \r
+ if (!value.empty() && (*value.rbegin() == '\r'))
+ value.erase(value.size() - 1);
+
+ // Add the field
+ m_fields[toLower(field)] = value;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Http::Http() :
+m_host(),
+m_port(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Http::Http(const std::string& host, unsigned short port)
+{
+ setHost(host, port);
+}
+
+
+////////////////////////////////////////////////////////////
+void Http::setHost(const std::string& host, unsigned short port)
+{
+ // Check the protocol
+ if (toLower(host.substr(0, 7)) == "http://")
+ {
+ // HTTP protocol
+ m_hostName = host.substr(7);
+ m_port = (port != 0 ? port : 80);
+ }
+ else if (toLower(host.substr(0, 8)) == "https://")
+ {
+ // HTTPS protocol -- unsupported (requires encryption and certificates and stuff...)
+ err() << "HTTPS protocol is not supported by sf::Http" << std::endl;
+ m_hostName = "";
+ m_port = 0;
+ }
+ else
+ {
+ // Undefined protocol - use HTTP
+ m_hostName = host;
+ m_port = (port != 0 ? port : 80);
+ }
+
+ // Remove any trailing '/' from the host name
+ if (!m_hostName.empty() && (*m_hostName.rbegin() == '/'))
+ m_hostName.erase(m_hostName.size() - 1);
+
+ m_host = IpAddress(m_hostName);
+}
+
+
+////////////////////////////////////////////////////////////
+Http::Response Http::sendRequest(const Http::Request& request, Time timeout)
+{
+ // First make sure that the request is valid -- add missing mandatory fields
+ Request toSend(request);
+ if (!toSend.hasField("From"))
+ {
+ toSend.setField("From", "user@sfml-dev.org");
+ }
+ if (!toSend.hasField("User-Agent"))
+ {
+ toSend.setField("User-Agent", "libsfml-network/2.x");
+ }
+ if (!toSend.hasField("Host"))
+ {
+ toSend.setField("Host", m_hostName);
+ }
+ if (!toSend.hasField("Content-Length"))
+ {
+ std::ostringstream out;
+ out << toSend.m_body.size();
+ toSend.setField("Content-Length", out.str());
+ }
+ if ((toSend.m_method == Request::Post) && !toSend.hasField("Content-Type"))
+ {
+ toSend.setField("Content-Type", "application/x-www-form-urlencoded");
+ }
+ if ((toSend.m_majorVersion * 10 + toSend.m_minorVersion >= 11) && !toSend.hasField("Connection"))
+ {
+ toSend.setField("Connection", "close");
+ }
+
+ // Prepare the response
+ Response received;
+
+ // Connect the socket to the host
+ if (m_connection.connect(m_host, m_port, timeout) == Socket::Done)
+ {
+ // Convert the request to string and send it through the connected socket
+ std::string requestStr = toSend.prepare();
+
+ if (!requestStr.empty())
+ {
+ // Send it through the socket
+ if (m_connection.send(requestStr.c_str(), requestStr.size()) == Socket::Done)
+ {
+ // Wait for the server's response
+ std::string receivedStr;
+ std::size_t size = 0;
+ char buffer[1024];
+ while (m_connection.receive(buffer, sizeof(buffer), size) == Socket::Done)
+ {
+ receivedStr.append(buffer, buffer + size);
+ }
+
+ // Build the Response object from the received data
+ received.parse(receivedStr);
+ }
+ }
+
+ // Close the connection
+ m_connection.disconnect();
+ }
+
+ return received;
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/IpAddress.cpp b/src/SFML/Network/IpAddress.cpp
new file mode 100644
index 0000000..9556138
--- /dev/null
+++ b/src/SFML/Network/IpAddress.cpp
@@ -0,0 +1,271 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/Network/Http.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <cstring>
+#include <utility>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+const IpAddress IpAddress::None;
+const IpAddress IpAddress::Any(0, 0, 0, 0);
+const IpAddress IpAddress::LocalHost(127, 0, 0, 1);
+const IpAddress IpAddress::Broadcast(255, 255, 255, 255);
+
+
+////////////////////////////////////////////////////////////
+IpAddress::IpAddress() :
+m_address(0),
+m_valid (false)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress::IpAddress(const std::string& address) :
+m_address(0),
+m_valid (false)
+{
+ resolve(address);
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress::IpAddress(const char* address) :
+m_address(0),
+m_valid (false)
+{
+ resolve(address);
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress::IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3) :
+m_address(htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)),
+m_valid (true)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress::IpAddress(Uint32 address) :
+m_address(htonl(address)),
+m_valid (true)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+std::string IpAddress::toString() const
+{
+ in_addr address;
+ address.s_addr = m_address;
+
+ return inet_ntoa(address);
+}
+
+
+////////////////////////////////////////////////////////////
+Uint32 IpAddress::toInteger() const
+{
+ return ntohl(m_address);
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress IpAddress::getLocalAddress()
+{
+ // The method here is to connect a UDP socket to anyone (here to localhost),
+ // and get the local socket address with the getsockname function.
+ // UDP connection will not send anything to the network, so this function won't cause any overhead.
+
+ IpAddress localAddress;
+
+ // Create the socket
+ SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sock == priv::SocketImpl::invalidSocket())
+ return localAddress;
+
+ // Connect the socket to localhost on any port
+ sockaddr_in address = priv::SocketImpl::createAddress(ntohl(INADDR_LOOPBACK), 9);
+ if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
+ {
+ priv::SocketImpl::close(sock);
+ return localAddress;
+ }
+
+ // Get the local address of the socket connection
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
+ {
+ priv::SocketImpl::close(sock);
+ return localAddress;
+ }
+
+ // Close the socket
+ priv::SocketImpl::close(sock);
+
+ // Finally build the IP address
+ localAddress = IpAddress(ntohl(address.sin_addr.s_addr));
+
+ return localAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress IpAddress::getPublicAddress(Time timeout)
+{
+ // The trick here is more complicated, because the only way
+ // to get our public IP address is to get it from a distant computer.
+ // Here we get the web page from http://www.sfml-dev.org/ip-provider.php
+ // and parse the result to extract our IP address
+ // (not very hard: the web page contains only our IP address).
+
+ Http server("www.sfml-dev.org");
+ Http::Request request("/ip-provider.php", Http::Request::Get);
+ Http::Response page = server.sendRequest(request, timeout);
+ if (page.getStatus() == Http::Response::Ok)
+ return IpAddress(page.getBody());
+
+ // Something failed: return an invalid address
+ return IpAddress();
+}
+
+
+////////////////////////////////////////////////////////////
+void IpAddress::resolve(const std::string& address)
+{
+ m_address = 0;
+ m_valid = false;
+
+ if (address == "255.255.255.255")
+ {
+ // The broadcast address needs to be handled explicitly,
+ // because it is also the value returned by inet_addr on error
+ m_address = INADDR_BROADCAST;
+ m_valid = true;
+ }
+ else if (address == "0.0.0.0")
+ {
+ m_address = INADDR_ANY;
+ m_valid = true;
+ }
+ else
+ {
+ // Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx")
+ Uint32 ip = inet_addr(address.c_str());
+ if (ip != INADDR_NONE)
+ {
+ m_address = ip;
+ m_valid = true;
+ }
+ else
+ {
+ // Not a valid address, try to convert it as a host name
+ addrinfo hints;
+ std::memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ addrinfo* result = NULL;
+ if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0)
+ {
+ if (result)
+ {
+ ip = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr;
+ freeaddrinfo(result);
+ m_address = ip;
+ m_valid = true;
+ }
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const IpAddress& left, const IpAddress& right)
+{
+ return !(left < right) && !(right < left);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const IpAddress& left, const IpAddress& right)
+{
+ return !(left == right);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <(const IpAddress& left, const IpAddress& right)
+{
+ return std::make_pair(left.m_valid, left.m_address) < std::make_pair(right.m_valid, right.m_address);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >(const IpAddress& left, const IpAddress& right)
+{
+ return right < left;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <=(const IpAddress& left, const IpAddress& right)
+{
+ return !(right < left);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >=(const IpAddress& left, const IpAddress& right)
+{
+ return !(left < right);
+}
+
+
+////////////////////////////////////////////////////////////
+std::istream& operator >>(std::istream& stream, IpAddress& address)
+{
+ std::string str;
+ stream >> str;
+ address = IpAddress(str);
+
+ return stream;
+}
+
+
+////////////////////////////////////////////////////////////
+std::ostream& operator <<(std::ostream& stream, const IpAddress& address)
+{
+ return stream << address.toString();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Packet.cpp b/src/SFML/Network/Packet.cpp
new file mode 100644
index 0000000..0dc2bbc
--- /dev/null
+++ b/src/SFML/Network/Packet.cpp
@@ -0,0 +1,596 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <cstring>
+#include <cwchar>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Packet::Packet() :
+m_readPos(0),
+m_sendPos(0),
+m_isValid(true)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Packet::~Packet()
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+void Packet::append(const void* data, std::size_t sizeInBytes)
+{
+ if (data && (sizeInBytes > 0))
+ {
+ std::size_t start = m_data.size();
+ m_data.resize(start + sizeInBytes);
+ std::memcpy(&m_data[start], data, sizeInBytes);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Packet::clear()
+{
+ m_data.clear();
+ m_readPos = 0;
+ m_isValid = true;
+}
+
+
+////////////////////////////////////////////////////////////
+const void* Packet::getData() const
+{
+ return !m_data.empty() ? &m_data[0] : NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t Packet::getDataSize() const
+{
+ return m_data.size();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Packet::endOfPacket() const
+{
+ return m_readPos >= m_data.size();
+}
+
+
+////////////////////////////////////////////////////////////
+Packet::operator BoolType() const
+{
+ return m_isValid ? &Packet::checkSize : NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(bool& data)
+{
+ Uint8 value;
+ if (*this >> value)
+ data = (value != 0);
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Int8& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = *reinterpret_cast<const Int8*>(&m_data[m_readPos]);
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Uint8& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = *reinterpret_cast<const Uint8*>(&m_data[m_readPos]);
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Int16& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = ntohs(*reinterpret_cast<const Int16*>(&m_data[m_readPos]));
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Uint16& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = ntohs(*reinterpret_cast<const Uint16*>(&m_data[m_readPos]));
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Int32& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = ntohl(*reinterpret_cast<const Int32*>(&m_data[m_readPos]));
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Uint32& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = ntohl(*reinterpret_cast<const Uint32*>(&m_data[m_readPos]));
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Int64& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ // Since ntohll is not available everywhere, we have to convert
+ // to network byte order (big endian) manually
+ const Uint8* bytes = reinterpret_cast<const Uint8*>(&m_data[m_readPos]);
+ data = (static_cast<Int64>(bytes[0]) << 56) |
+ (static_cast<Int64>(bytes[1]) << 48) |
+ (static_cast<Int64>(bytes[2]) << 40) |
+ (static_cast<Int64>(bytes[3]) << 32) |
+ (static_cast<Int64>(bytes[4]) << 24) |
+ (static_cast<Int64>(bytes[5]) << 16) |
+ (static_cast<Int64>(bytes[6]) << 8) |
+ (static_cast<Int64>(bytes[7]) );
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(Uint64& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ // Since ntohll is not available everywhere, we have to convert
+ // to network byte order (big endian) manually
+ const Uint8* bytes = reinterpret_cast<const Uint8*>(&m_data[m_readPos]);
+ data = (static_cast<Uint64>(bytes[0]) << 56) |
+ (static_cast<Uint64>(bytes[1]) << 48) |
+ (static_cast<Uint64>(bytes[2]) << 40) |
+ (static_cast<Uint64>(bytes[3]) << 32) |
+ (static_cast<Uint64>(bytes[4]) << 24) |
+ (static_cast<Uint64>(bytes[5]) << 16) |
+ (static_cast<Uint64>(bytes[6]) << 8) |
+ (static_cast<Uint64>(bytes[7]) );
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(float& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = *reinterpret_cast<const float*>(&m_data[m_readPos]);
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(double& data)
+{
+ if (checkSize(sizeof(data)))
+ {
+ data = *reinterpret_cast<const double*>(&m_data[m_readPos]);
+ m_readPos += sizeof(data);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(char* data)
+{
+ // First extract string length
+ Uint32 length = 0;
+ *this >> length;
+
+ if ((length > 0) && checkSize(length))
+ {
+ // Then extract characters
+ std::memcpy(data, &m_data[m_readPos], length);
+ data[length] = '\0';
+
+ // Update reading position
+ m_readPos += length;
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(std::string& data)
+{
+ // First extract string length
+ Uint32 length = 0;
+ *this >> length;
+
+ data.clear();
+ if ((length > 0) && checkSize(length))
+ {
+ // Then extract characters
+ data.assign(&m_data[m_readPos], length);
+
+ // Update reading position
+ m_readPos += length;
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(wchar_t* data)
+{
+ // First extract string length
+ Uint32 length = 0;
+ *this >> length;
+
+ if ((length > 0) && checkSize(length * sizeof(Uint32)))
+ {
+ // Then extract characters
+ for (Uint32 i = 0; i < length; ++i)
+ {
+ Uint32 character = 0;
+ *this >> character;
+ data[i] = static_cast<wchar_t>(character);
+ }
+ data[length] = L'\0';
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(std::wstring& data)
+{
+ // First extract string length
+ Uint32 length = 0;
+ *this >> length;
+
+ data.clear();
+ if ((length > 0) && checkSize(length * sizeof(Uint32)))
+ {
+ // Then extract characters
+ for (Uint32 i = 0; i < length; ++i)
+ {
+ Uint32 character = 0;
+ *this >> character;
+ data += static_cast<wchar_t>(character);
+ }
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(String& data)
+{
+ // First extract the string length
+ Uint32 length = 0;
+ *this >> length;
+
+ data.clear();
+ if ((length > 0) && checkSize(length * sizeof(Uint32)))
+ {
+ // Then extract characters
+ for (Uint32 i = 0; i < length; ++i)
+ {
+ Uint32 character = 0;
+ *this >> character;
+ data += character;
+ }
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(bool data)
+{
+ *this << static_cast<Uint8>(data);
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Int8 data)
+{
+ append(&data, sizeof(data));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Uint8 data)
+{
+ append(&data, sizeof(data));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Int16 data)
+{
+ Int16 toWrite = htons(data);
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Uint16 data)
+{
+ Uint16 toWrite = htons(data);
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Int32 data)
+{
+ Int32 toWrite = htonl(data);
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Uint32 data)
+{
+ Uint32 toWrite = htonl(data);
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Int64 data)
+{
+ // Since htonll is not available everywhere, we have to convert
+ // to network byte order (big endian) manually
+ Uint8 toWrite[] =
+ {
+ static_cast<Uint8>((data >> 56) & 0xFF),
+ static_cast<Uint8>((data >> 48) & 0xFF),
+ static_cast<Uint8>((data >> 40) & 0xFF),
+ static_cast<Uint8>((data >> 32) & 0xFF),
+ static_cast<Uint8>((data >> 24) & 0xFF),
+ static_cast<Uint8>((data >> 16) & 0xFF),
+ static_cast<Uint8>((data >> 8) & 0xFF),
+ static_cast<Uint8>((data ) & 0xFF)
+ };
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(Uint64 data)
+{
+ // Since htonll is not available everywhere, we have to convert
+ // to network byte order (big endian) manually
+ Uint8 toWrite[] =
+ {
+ static_cast<Uint8>((data >> 56) & 0xFF),
+ static_cast<Uint8>((data >> 48) & 0xFF),
+ static_cast<Uint8>((data >> 40) & 0xFF),
+ static_cast<Uint8>((data >> 32) & 0xFF),
+ static_cast<Uint8>((data >> 24) & 0xFF),
+ static_cast<Uint8>((data >> 16) & 0xFF),
+ static_cast<Uint8>((data >> 8) & 0xFF),
+ static_cast<Uint8>((data ) & 0xFF)
+ };
+ append(&toWrite, sizeof(toWrite));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(float data)
+{
+ append(&data, sizeof(data));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(double data)
+{
+ append(&data, sizeof(data));
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(const char* data)
+{
+ // First insert string length
+ Uint32 length = static_cast<Uint32>(std::strlen(data));
+ *this << length;
+
+ // Then insert characters
+ append(data, length * sizeof(char));
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(const std::string& data)
+{
+ // First insert string length
+ Uint32 length = static_cast<Uint32>(data.size());
+ *this << length;
+
+ // Then insert characters
+ if (length > 0)
+ append(data.c_str(), length * sizeof(std::string::value_type));
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(const wchar_t* data)
+{
+ // First insert string length
+ Uint32 length = static_cast<Uint32>(std::wcslen(data));
+ *this << length;
+
+ // Then insert characters
+ for (const wchar_t* c = data; *c != L'\0'; ++c)
+ *this << static_cast<Uint32>(*c);
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(const std::wstring& data)
+{
+ // First insert string length
+ Uint32 length = static_cast<Uint32>(data.size());
+ *this << length;
+
+ // Then insert characters
+ if (length > 0)
+ {
+ for (std::wstring::const_iterator c = data.begin(); c != data.end(); ++c)
+ *this << static_cast<Uint32>(*c);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(const String& data)
+{
+ // First insert the string length
+ Uint32 length = static_cast<Uint32>(data.getSize());
+ *this << length;
+
+ // Then insert characters
+ if (length > 0)
+ {
+ for (String::ConstIterator c = data.begin(); c != data.end(); ++c)
+ *this << *c;
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Packet::checkSize(std::size_t size)
+{
+ m_isValid = m_isValid && (m_readPos + size <= m_data.size());
+
+ return m_isValid;
+}
+
+
+////////////////////////////////////////////////////////////
+const void* Packet::onSend(std::size_t& size)
+{
+ size = getDataSize();
+ return getData();
+}
+
+
+////////////////////////////////////////////////////////////
+void Packet::onReceive(const void* data, std::size_t size)
+{
+ append(data, size);
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Socket.cpp b/src/SFML/Network/Socket.cpp
new file mode 100644
index 0000000..d100421
--- /dev/null
+++ b/src/SFML/Network/Socket.cpp
@@ -0,0 +1,151 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Socket.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Socket::Socket(Type type) :
+m_type (type),
+m_socket (priv::SocketImpl::invalidSocket()),
+m_isBlocking(true)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::~Socket()
+{
+ // Close the socket before it gets destructed
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+void Socket::setBlocking(bool blocking)
+{
+ // Apply if the socket is already created
+ if (m_socket != priv::SocketImpl::invalidSocket())
+ priv::SocketImpl::setBlocking(m_socket, blocking);
+
+ m_isBlocking = blocking;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Socket::isBlocking() const
+{
+ return m_isBlocking;
+}
+
+
+////////////////////////////////////////////////////////////
+SocketHandle Socket::getHandle() const
+{
+ return m_socket;
+}
+
+
+////////////////////////////////////////////////////////////
+void Socket::create()
+{
+ // Don't create the socket if it already exists
+ if (m_socket == priv::SocketImpl::invalidSocket())
+ {
+ SocketHandle handle = socket(PF_INET, m_type == Tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (handle == priv::SocketImpl::invalidSocket())
+ {
+ err() << "Failed to create socket" << std::endl;
+ return;
+ }
+
+ create(handle);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Socket::create(SocketHandle handle)
+{
+ // Don't create the socket if it already exists
+ if (m_socket == priv::SocketImpl::invalidSocket())
+ {
+ // Assign the new handle
+ m_socket = handle;
+
+ // Set the current blocking state
+ setBlocking(m_isBlocking);
+
+ if (m_type == Tcp)
+ {
+ // Disable the Nagle algorithm (i.e. removes buffering of TCP packets)
+ int yes = 1;
+ if (setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
+ {
+ err() << "Failed to set socket option \"TCP_NODELAY\" ; "
+ << "all your TCP packets will be buffered" << std::endl;
+ }
+
+ // On Mac OS X, disable the SIGPIPE signal on disconnection
+ #ifdef SFML_SYSTEM_MACOS
+ if (setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
+ {
+ err() << "Failed to set socket option \"SO_NOSIGPIPE\"" << std::endl;
+ }
+ #endif
+ }
+ else
+ {
+ // Enable broadcast by default for UDP sockets
+ int yes = 1;
+ if (setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
+ {
+ err() << "Failed to enable broadcast on UDP socket" << std::endl;
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Socket::close()
+{
+ // Close the socket
+ if (m_socket != priv::SocketImpl::invalidSocket())
+ {
+ priv::SocketImpl::close(m_socket);
+ m_socket = priv::SocketImpl::invalidSocket();
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/SocketImpl.hpp b/src/SFML/Network/SocketImpl.hpp
new file mode 100644
index 0000000..d1ffebe
--- /dev/null
+++ b/src/SFML/Network/SocketImpl.hpp
@@ -0,0 +1,39 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Network/Win32/SocketImpl.hpp>
+
+#else
+
+ #include <SFML/Network/Unix/SocketImpl.hpp>
+
+#endif
diff --git a/src/SFML/Network/SocketSelector.cpp b/src/SFML/Network/SocketSelector.cpp
new file mode 100644
index 0000000..fa00c63
--- /dev/null
+++ b/src/SFML/Network/SocketSelector.cpp
@@ -0,0 +1,205 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SocketSelector.hpp>
+#include <SFML/Network/Socket.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <utility>
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4127) // "conditional expression is constant" generated by the FD_SET macro
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+struct SocketSelector::SocketSelectorImpl
+{
+ fd_set allSockets; ///< Set containing all the sockets handles
+ fd_set socketsReady; ///< Set containing handles of the sockets that are ready
+ int maxSocket; ///< Maximum socket handle
+ int socketCount; ///< Number of socket handles
+};
+
+
+////////////////////////////////////////////////////////////
+SocketSelector::SocketSelector() :
+m_impl(new SocketSelectorImpl)
+{
+ clear();
+}
+
+
+////////////////////////////////////////////////////////////
+SocketSelector::SocketSelector(const SocketSelector& copy) :
+m_impl(new SocketSelectorImpl(*copy.m_impl))
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+SocketSelector::~SocketSelector()
+{
+ delete m_impl;
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketSelector::add(Socket& socket)
+{
+ SocketHandle handle = socket.getHandle();
+ if (handle != priv::SocketImpl::invalidSocket())
+ {
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ if (m_impl->socketCount >= FD_SETSIZE)
+ {
+ err() << "The socket can't be added to the selector because the "
+ << "selector is full. This is a limitation of your operating "
+ << "system's FD_SETSIZE setting.";
+ return;
+ }
+
+ if (FD_ISSET(handle, &m_impl->allSockets))
+ return;
+
+ m_impl->socketCount++;
+
+#else
+
+ if (handle >= FD_SETSIZE)
+ {
+ err() << "The socket can't be added to the selector because its "
+ << "ID is too high. This is a limitation of your operating "
+ << "system's FD_SETSIZE setting.";
+ return;
+ }
+
+ // SocketHandle is an int in POSIX
+ m_impl->maxSocket = std::max(m_impl->maxSocket, handle);
+
+#endif
+
+ FD_SET(handle, &m_impl->allSockets);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketSelector::remove(Socket& socket)
+{
+ SocketHandle handle = socket.getHandle();
+ if (handle != priv::SocketImpl::invalidSocket())
+ {
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ if (!FD_ISSET(handle, &m_impl->allSockets))
+ return;
+
+ m_impl->socketCount--;
+
+#else
+
+ if (handle >= FD_SETSIZE)
+ return;
+
+#endif
+
+ FD_CLR(handle, &m_impl->allSockets);
+ FD_CLR(handle, &m_impl->socketsReady);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketSelector::clear()
+{
+ FD_ZERO(&m_impl->allSockets);
+ FD_ZERO(&m_impl->socketsReady);
+
+ m_impl->maxSocket = 0;
+ m_impl->socketCount = 0;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SocketSelector::wait(Time timeout)
+{
+ // Setup the timeout
+ timeval time;
+ time.tv_sec = static_cast<long>(timeout.asMicroseconds() / 1000000);
+ time.tv_usec = static_cast<long>(timeout.asMicroseconds() % 1000000);
+
+ // Initialize the set that will contain the sockets that are ready
+ m_impl->socketsReady = m_impl->allSockets;
+
+ // Wait until one of the sockets is ready for reading, or timeout is reached
+ // The first parameter is ignored on Windows
+ int count = select(m_impl->maxSocket + 1, &m_impl->socketsReady, NULL, NULL, timeout != Time::Zero ? &time : NULL);
+
+ return count > 0;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SocketSelector::isReady(Socket& socket) const
+{
+ SocketHandle handle = socket.getHandle();
+ if (handle != priv::SocketImpl::invalidSocket())
+ {
+
+#if !defined(SFML_SYSTEM_WINDOWS)
+
+ if (handle >= FD_SETSIZE)
+ return false;
+
+#endif
+
+ return FD_ISSET(handle, &m_impl->socketsReady) != 0;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+SocketSelector& SocketSelector::operator =(const SocketSelector& right)
+{
+ SocketSelector temp(right);
+
+ std::swap(m_impl, temp.m_impl);
+
+ return *this;
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/TcpListener.cpp b/src/SFML/Network/TcpListener.cpp
new file mode 100644
index 0000000..399f87d
--- /dev/null
+++ b/src/SFML/Network/TcpListener.cpp
@@ -0,0 +1,131 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/TcpListener.hpp>
+#include <SFML/Network/TcpSocket.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+TcpListener::TcpListener() :
+Socket(Tcp)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned short TcpListener::getLocalPort() const
+{
+ if (getHandle() != priv::SocketImpl::invalidSocket())
+ {
+ // Retrieve informations about the local end of the socket
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
+ {
+ return ntohs(address.sin_port);
+ }
+ }
+
+ // We failed to retrieve the port
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpListener::listen(unsigned short port, const IpAddress& address)
+{
+ // Close the socket if it is already bound
+ close();
+
+ // Create the internal socket if it doesn't exist
+ create();
+
+ // Check if the address is valid
+ if ((address == IpAddress::None) || (address == IpAddress::Broadcast))
+ return Error;
+
+ // Bind the socket to the specified port
+ sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port);
+ if (bind(getHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
+ {
+ // Not likely to happen, but...
+ err() << "Failed to bind listener socket to port " << port << std::endl;
+ return Error;
+ }
+
+ // Listen to the bound port
+ if (::listen(getHandle(), SOMAXCONN) == -1)
+ {
+ // Oops, socket is deaf
+ err() << "Failed to listen to port " << port << std::endl;
+ return Error;
+ }
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+void TcpListener::close()
+{
+ // Simply close the socket
+ Socket::close();
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpListener::accept(TcpSocket& socket)
+{
+ // Make sure that we're listening
+ if (getHandle() == priv::SocketImpl::invalidSocket())
+ {
+ err() << "Failed to accept a new connection, the socket is not listening" << std::endl;
+ return Error;
+ }
+
+ // Accept a new connection
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength length = sizeof(address);
+ SocketHandle remote = ::accept(getHandle(), reinterpret_cast<sockaddr*>(&address), &length);
+
+ // Check for errors
+ if (remote == priv::SocketImpl::invalidSocket())
+ return priv::SocketImpl::getErrorStatus();
+
+ // Initialize the new connected socket
+ socket.close();
+ socket.create(remote);
+
+ return Done;
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp
new file mode 100644
index 0000000..d8effa1
--- /dev/null
+++ b/src/SFML/Network/TcpSocket.cpp
@@ -0,0 +1,416 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/TcpSocket.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+#include <cstring>
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4127) // "conditional expression is constant" generated by the FD_SET macro
+#endif
+
+
+namespace
+{
+ // Define the low-level send/receive flags, which depend on the OS
+ #ifdef SFML_SYSTEM_LINUX
+ const int flags = MSG_NOSIGNAL;
+ #else
+ const int flags = 0;
+ #endif
+}
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+TcpSocket::TcpSocket() :
+Socket(Tcp)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned short TcpSocket::getLocalPort() const
+{
+ if (getHandle() != priv::SocketImpl::invalidSocket())
+ {
+ // Retrieve informations about the local end of the socket
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
+ {
+ return ntohs(address.sin_port);
+ }
+ }
+
+ // We failed to retrieve the port
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+IpAddress TcpSocket::getRemoteAddress() const
+{
+ if (getHandle() != priv::SocketImpl::invalidSocket())
+ {
+ // Retrieve informations about the remote end of the socket
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getpeername(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
+ {
+ return IpAddress(ntohl(address.sin_addr.s_addr));
+ }
+ }
+
+ // We failed to retrieve the address
+ return IpAddress::None;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned short TcpSocket::getRemotePort() const
+{
+ if (getHandle() != priv::SocketImpl::invalidSocket())
+ {
+ // Retrieve informations about the remote end of the socket
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getpeername(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
+ {
+ return ntohs(address.sin_port);
+ }
+ }
+
+ // We failed to retrieve the port
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::connect(const IpAddress& remoteAddress, unsigned short remotePort, Time timeout)
+{
+ // Disconnect the socket if it is already connected
+ disconnect();
+
+ // Create the internal socket if it doesn't exist
+ create();
+
+ // Create the remote address
+ sockaddr_in address = priv::SocketImpl::createAddress(remoteAddress.toInteger(), remotePort);
+
+ if (timeout <= Time::Zero)
+ {
+ // ----- We're not using a timeout: just try to connect -----
+
+ // Connect the socket
+ if (::connect(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
+ return priv::SocketImpl::getErrorStatus();
+
+ // Connection succeeded
+ return Done;
+ }
+ else
+ {
+ // ----- We're using a timeout: we'll need a few tricks to make it work -----
+
+ // Save the previous blocking state
+ bool blocking = isBlocking();
+
+ // Switch to non-blocking to enable our connection timeout
+ if (blocking)
+ setBlocking(false);
+
+ // Try to connect to the remote address
+ if (::connect(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) >= 0)
+ {
+ // We got instantly connected! (it may no happen a lot...)
+ setBlocking(blocking);
+ return Done;
+ }
+
+ // Get the error status
+ Status status = priv::SocketImpl::getErrorStatus();
+
+ // If we were in non-blocking mode, return immediately
+ if (!blocking)
+ return status;
+
+ // Otherwise, wait until something happens to our socket (success, timeout or error)
+ if (status == Socket::NotReady)
+ {
+ // Setup the selector
+ fd_set selector;
+ FD_ZERO(&selector);
+ FD_SET(getHandle(), &selector);
+
+ // Setup the timeout
+ timeval time;
+ time.tv_sec = static_cast<long>(timeout.asMicroseconds() / 1000000);
+ time.tv_usec = static_cast<long>(timeout.asMicroseconds() % 1000000);
+
+ // Wait for something to write on our socket (which means that the connection request has returned)
+ if (select(static_cast<int>(getHandle() + 1), NULL, &selector, NULL, &time) > 0)
+ {
+ // At this point the connection may have been either accepted or refused.
+ // To know whether it's a success or a failure, we must check the address of the connected peer
+ if (getRemoteAddress() != IpAddress::None)
+ {
+ // Connection accepted
+ status = Done;
+ }
+ else
+ {
+ // Connection refused
+ status = priv::SocketImpl::getErrorStatus();
+ }
+ }
+ else
+ {
+ // Failed to connect before timeout is over
+ status = priv::SocketImpl::getErrorStatus();
+ }
+ }
+
+ // Switch back to blocking mode
+ setBlocking(true);
+
+ return status;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void TcpSocket::disconnect()
+{
+ // Close the socket
+ close();
+
+ // Reset the pending packet data
+ m_pendingPacket = PendingPacket();
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::send(const void* data, std::size_t size)
+{
+ if (!isBlocking())
+ err() << "Warning: Partial sends might not be handled properly." << std::endl;
+
+ std::size_t sent;
+
+ return send(data, size, sent);
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::send(const void* data, std::size_t size, std::size_t& sent)
+{
+ // Check the parameters
+ if (!data || (size == 0))
+ {
+ err() << "Cannot send data over the network (no data to send)" << std::endl;
+ return Error;
+ }
+
+ // Loop until every byte has been sent
+ int result = 0;
+ for (sent = 0; sent < size; sent += result)
+ {
+ // Send a chunk of data
+ result = ::send(getHandle(), static_cast<const char*>(data) + sent, static_cast<int>(size - sent), flags);
+
+ // Check for errors
+ if (result < 0)
+ {
+ Status status = priv::SocketImpl::getErrorStatus();
+
+ if ((status == NotReady) && sent)
+ return Partial;
+
+ return status;
+ }
+ }
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::receive(void* data, std::size_t size, std::size_t& received)
+{
+ // First clear the variables to fill
+ received = 0;
+
+ // Check the destination buffer
+ if (!data)
+ {
+ err() << "Cannot receive data from the network (the destination buffer is invalid)" << std::endl;
+ return Error;
+ }
+
+ // Receive a chunk of bytes
+ int sizeReceived = recv(getHandle(), static_cast<char*>(data), static_cast<int>(size), flags);
+
+ // Check the number of bytes received
+ if (sizeReceived > 0)
+ {
+ received = static_cast<std::size_t>(sizeReceived);
+ return Done;
+ }
+ else if (sizeReceived == 0)
+ {
+ return Socket::Disconnected;
+ }
+ else
+ {
+ return priv::SocketImpl::getErrorStatus();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::send(Packet& packet)
+{
+ // TCP is a stream protocol, it doesn't preserve messages boundaries.
+ // This means that we have to send the packet size first, so that the
+ // receiver knows the actual end of the packet in the data stream.
+
+ // We allocate an extra memory block so that the size can be sent
+ // together with the data in a single call. This may seem inefficient,
+ // but it is actually required to avoid partial send, which could cause
+ // data corruption on the receiving end.
+
+ // Get the data to send from the packet
+ std::size_t size = 0;
+ const void* data = packet.onSend(size);
+
+ // First convert the packet size to network byte order
+ Uint32 packetSize = htonl(static_cast<Uint32>(size));
+
+ // Allocate memory for the data block to send
+ std::vector<char> blockToSend(sizeof(packetSize) + size);
+
+ // Copy the packet size and data into the block to send
+ std::memcpy(&blockToSend[0], &packetSize, sizeof(packetSize));
+ if (size > 0)
+ std::memcpy(&blockToSend[0] + sizeof(packetSize), data, size);
+
+ // Send the data block
+ std::size_t sent;
+ Status status = send(&blockToSend[0] + packet.m_sendPos, blockToSend.size() - packet.m_sendPos, sent);
+
+ // In the case of a partial send, record the location to resume from
+ if (status == Partial)
+ {
+ packet.m_sendPos += sent;
+ }
+ else if (status == Done)
+ {
+ packet.m_sendPos = 0;
+ }
+
+ return status;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status TcpSocket::receive(Packet& packet)
+{
+ // First clear the variables to fill
+ packet.clear();
+
+ // We start by getting the size of the incoming packet
+ Uint32 packetSize = 0;
+ std::size_t received = 0;
+ if (m_pendingPacket.SizeReceived < sizeof(m_pendingPacket.Size))
+ {
+ // Loop until we've received the entire size of the packet
+ // (even a 4 byte variable may be received in more than one call)
+ while (m_pendingPacket.SizeReceived < sizeof(m_pendingPacket.Size))
+ {
+ char* data = reinterpret_cast<char*>(&m_pendingPacket.Size) + m_pendingPacket.SizeReceived;
+ Status status = receive(data, sizeof(m_pendingPacket.Size) - m_pendingPacket.SizeReceived, received);
+ m_pendingPacket.SizeReceived += received;
+
+ if (status != Done)
+ return status;
+ }
+
+ // The packet size has been fully received
+ packetSize = ntohl(m_pendingPacket.Size);
+ }
+ else
+ {
+ // The packet size has already been received in a previous call
+ packetSize = ntohl(m_pendingPacket.Size);
+ }
+
+ // Loop until we receive all the packet data
+ char buffer[1024];
+ while (m_pendingPacket.Data.size() < packetSize)
+ {
+ // Receive a chunk of data
+ std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - m_pendingPacket.Data.size()), sizeof(buffer));
+ Status status = receive(buffer, sizeToGet, received);
+ if (status != Done)
+ return status;
+
+ // Append it into the packet
+ if (received > 0)
+ {
+ m_pendingPacket.Data.resize(m_pendingPacket.Data.size() + received);
+ char* begin = &m_pendingPacket.Data[0] + m_pendingPacket.Data.size() - received;
+ std::memcpy(begin, buffer, received);
+ }
+ }
+
+ // We have received all the packet data: we can copy it to the user packet
+ if (!m_pendingPacket.Data.empty())
+ packet.onReceive(&m_pendingPacket.Data[0], m_pendingPacket.Data.size());
+
+ // Clear the pending packet data
+ m_pendingPacket = PendingPacket();
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+TcpSocket::PendingPacket::PendingPacket() :
+Size (0),
+SizeReceived(0),
+Data ()
+{
+
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/UdpSocket.cpp b/src/SFML/Network/UdpSocket.cpp
new file mode 100644
index 0000000..0ff03b0
--- /dev/null
+++ b/src/SFML/Network/UdpSocket.cpp
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/UdpSocket.hpp>
+#include <SFML/Network/IpAddress.hpp>
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+UdpSocket::UdpSocket() :
+Socket (Udp),
+m_buffer(MaxDatagramSize)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned short UdpSocket::getLocalPort() const
+{
+ if (getHandle() != priv::SocketImpl::invalidSocket())
+ {
+ // Retrieve informations about the local end of the socket
+ sockaddr_in address;
+ priv::SocketImpl::AddrLength size = sizeof(address);
+ if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
+ {
+ return ntohs(address.sin_port);
+ }
+ }
+
+ // We failed to retrieve the port
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status UdpSocket::bind(unsigned short port, const IpAddress& address)
+{
+ // Close the socket if it is already bound
+ close();
+
+ // Create the internal socket if it doesn't exist
+ create();
+
+ // Check if the address is valid
+ if ((address == IpAddress::None) || (address == IpAddress::Broadcast))
+ return Error;
+
+ // Bind the socket
+ sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port);
+ if (::bind(getHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
+ {
+ err() << "Failed to bind socket to port " << port << std::endl;
+ return Error;
+ }
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+void UdpSocket::unbind()
+{
+ // Simply close the socket
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status UdpSocket::send(const void* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort)
+{
+ // Create the internal socket if it doesn't exist
+ create();
+
+ // Make sure that all the data will fit in one datagram
+ if (size > MaxDatagramSize)
+ {
+ err() << "Cannot send data over the network "
+ << "(the number of bytes to send is greater than sf::UdpSocket::MaxDatagramSize)" << std::endl;
+ return Error;
+ }
+
+ // Build the target address
+ sockaddr_in address = priv::SocketImpl::createAddress(remoteAddress.toInteger(), remotePort);
+
+ // Send the data (unlike TCP, all the data is always sent in one call)
+ int sent = sendto(getHandle(), static_cast<const char*>(data), static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), sizeof(address));
+
+ // Check for errors
+ if (sent < 0)
+ return priv::SocketImpl::getErrorStatus();
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status UdpSocket::receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort)
+{
+ // First clear the variables to fill
+ received = 0;
+ remoteAddress = IpAddress();
+ remotePort = 0;
+
+ // Check the destination buffer
+ if (!data)
+ {
+ err() << "Cannot receive data from the network (the destination buffer is invalid)" << std::endl;
+ return Error;
+ }
+
+ // Data that will be filled with the other computer's address
+ sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, 0);
+
+ // Receive a chunk of bytes
+ priv::SocketImpl::AddrLength addressSize = sizeof(address);
+ int sizeReceived = recvfrom(getHandle(), static_cast<char*>(data), static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), &addressSize);
+
+ // Check for errors
+ if (sizeReceived < 0)
+ return priv::SocketImpl::getErrorStatus();
+
+ // Fill the sender informations
+ received = static_cast<std::size_t>(sizeReceived);
+ remoteAddress = IpAddress(ntohl(address.sin_addr.s_addr));
+ remotePort = ntohs(address.sin_port);
+
+ return Done;
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status UdpSocket::send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort)
+{
+ // UDP is a datagram-oriented protocol (as opposed to TCP which is a stream protocol).
+ // Sending one datagram is almost safe: it may be lost but if it's received, then its data
+ // is guaranteed to be ok. However, splitting a packet into multiple datagrams would be highly
+ // unreliable, since datagrams may be reordered, dropped or mixed between different sources.
+ // That's why SFML imposes a limit on packet size so that they can be sent in a single datagram.
+ // This also removes the overhead associated to packets -- there's no size to send in addition
+ // to the packet's data.
+
+ // Get the data to send from the packet
+ std::size_t size = 0;
+ const void* data = packet.onSend(size);
+
+ // Send it
+ return send(data, size, remoteAddress, remotePort);
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status UdpSocket::receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort)
+{
+ // See the detailed comment in send(Packet) above.
+
+ // Receive the datagram
+ std::size_t received = 0;
+ Status status = receive(&m_buffer[0], m_buffer.size(), received, remoteAddress, remotePort);
+
+ // If we received valid data, we can copy it to the user packet
+ packet.clear();
+ if ((status == Done) && (received > 0))
+ packet.onReceive(&m_buffer[0], received);
+
+ return status;
+}
+
+
+} // namespace sf
diff --git a/src/SFML/Network/Unix/SocketImpl.cpp b/src/SFML/Network/Unix/SocketImpl.cpp
new file mode 100644
index 0000000..4029480
--- /dev/null
+++ b/src/SFML/Network/Unix/SocketImpl.cpp
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Unix/SocketImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <errno.h>
+#include <fcntl.h>
+#include <cstring>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+sockaddr_in SocketImpl::createAddress(Uint32 address, unsigned short port)
+{
+ sockaddr_in addr;
+ std::memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(address);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+#if defined(SFML_SYSTEM_MACOS)
+ addr.sin_len = sizeof(addr);
+#endif
+
+ return addr;
+}
+
+
+////////////////////////////////////////////////////////////
+SocketHandle SocketImpl::invalidSocket()
+{
+ return -1;
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketImpl::close(SocketHandle sock)
+{
+ ::close(sock);
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketImpl::setBlocking(SocketHandle sock, bool block)
+{
+ int status = fcntl(sock, F_GETFL);
+ if (block)
+ {
+ if (fcntl(sock, F_SETFL, status & ~O_NONBLOCK) == -1)
+ err() << "Failed to set file status flags: " << errno << std::endl;
+ }
+ else
+ {
+ if (fcntl(sock, F_SETFL, status | O_NONBLOCK) == -1)
+ err() << "Failed to set file status flags: " << errno << std::endl;
+
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status SocketImpl::getErrorStatus()
+{
+ // The followings are sometimes equal to EWOULDBLOCK,
+ // so we have to make a special case for them in order
+ // to avoid having double values in the switch case
+ if ((errno == EAGAIN) || (errno == EINPROGRESS))
+ return Socket::NotReady;
+
+ switch (errno)
+ {
+ case EWOULDBLOCK: return Socket::NotReady;
+ case ECONNABORTED: return Socket::Disconnected;
+ case ECONNRESET: return Socket::Disconnected;
+ case ETIMEDOUT: return Socket::Disconnected;
+ case ENETRESET: return Socket::Disconnected;
+ case ENOTCONN: return Socket::Disconnected;
+ case EPIPE: return Socket::Disconnected;
+ default: return Socket::Error;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Network/Unix/SocketImpl.hpp b/src/SFML/Network/Unix/SocketImpl.hpp
new file mode 100644
index 0000000..b70c077
--- /dev/null
+++ b/src/SFML/Network/Unix/SocketImpl.hpp
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOCKETIMPL_HPP
+#define SFML_SOCKETIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Socket.hpp>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Helper class implementing all the non-portable
+/// socket stuff; this is the Unix version
+///
+////////////////////////////////////////////////////////////
+class SocketImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ // Types
+ ////////////////////////////////////////////////////////////
+ typedef socklen_t AddrLength;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create an internal sockaddr_in address
+ ///
+ /// \param address Target address
+ /// \param port Target port
+ ///
+ /// \return sockaddr_in ready to be used by socket functions
+ ///
+ ////////////////////////////////////////////////////////////
+ static sockaddr_in createAddress(Uint32 address, unsigned short port);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Return the value of the invalid socket
+ ///
+ /// \return Special value of the invalid socket
+ ///
+ ////////////////////////////////////////////////////////////
+ static SocketHandle invalidSocket();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close and destroy a socket
+ ///
+ /// \param sock Handle of the socket to close
+ ///
+ ////////////////////////////////////////////////////////////
+ static void close(SocketHandle sock);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set a socket as blocking or non-blocking
+ ///
+ /// \param sock Handle of the socket
+ /// \param block New blocking state of the socket
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setBlocking(SocketHandle sock, bool block);
+
+ ////////////////////////////////////////////////////////////
+ /// Get the last socket error status
+ ///
+ /// \return Status corresponding to the last socket error
+ ///
+ ////////////////////////////////////////////////////////////
+ static Socket::Status getErrorStatus();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOCKETIMPL_HPP
diff --git a/src/SFML/Network/Win32/SocketImpl.cpp b/src/SFML/Network/Win32/SocketImpl.cpp
new file mode 100644
index 0000000..bd53665
--- /dev/null
+++ b/src/SFML/Network/Win32/SocketImpl.cpp
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Win32/SocketImpl.hpp>
+#include <cstring>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+sockaddr_in SocketImpl::createAddress(Uint32 address, unsigned short port)
+{
+ sockaddr_in addr;
+ std::memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(address);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ return addr;
+}
+
+
+////////////////////////////////////////////////////////////
+SocketHandle SocketImpl::invalidSocket()
+{
+ return INVALID_SOCKET;
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketImpl::close(SocketHandle sock)
+{
+ closesocket(sock);
+}
+
+
+////////////////////////////////////////////////////////////
+void SocketImpl::setBlocking(SocketHandle sock, bool block)
+{
+ u_long blocking = block ? 0 : 1;
+ ioctlsocket(sock, FIONBIO, &blocking);
+}
+
+
+////////////////////////////////////////////////////////////
+Socket::Status SocketImpl::getErrorStatus()
+{
+ switch (WSAGetLastError())
+ {
+ case WSAEWOULDBLOCK: return Socket::NotReady;
+ case WSAEALREADY: return Socket::NotReady;
+ case WSAECONNABORTED: return Socket::Disconnected;
+ case WSAECONNRESET: return Socket::Disconnected;
+ case WSAETIMEDOUT: return Socket::Disconnected;
+ case WSAENETRESET: return Socket::Disconnected;
+ case WSAENOTCONN: return Socket::Disconnected;
+ case WSAEISCONN: return Socket::Done; // when connecting a non-blocking socket
+ default: return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// Windows needs some initialization and cleanup to get
+// sockets working properly... so let's create a class that will
+// do it automatically
+////////////////////////////////////////////////////////////
+struct SocketInitializer
+{
+ SocketInitializer()
+ {
+ WSADATA init;
+ WSAStartup(MAKEWORD(2, 2), &init);
+ }
+
+ ~SocketInitializer()
+ {
+ WSACleanup();
+ }
+};
+
+SocketInitializer globalInitializer;
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Network/Win32/SocketImpl.hpp b/src/SFML/Network/Win32/SocketImpl.hpp
new file mode 100644
index 0000000..978336f
--- /dev/null
+++ b/src/SFML/Network/Win32/SocketImpl.hpp
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SOCKETIMPL_HPP
+#define SFML_SOCKETIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#ifdef _WIN32_WINDOWS
+ #undef _WIN32_WINDOWS
+#endif
+#ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+#endif
+#define _WIN32_WINDOWS 0x0501
+#define _WIN32_WINNT 0x0501
+#include <SFML/Network/Socket.hpp>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Helper class implementing all the non-portable
+/// socket stuff; this is the Windows version
+///
+////////////////////////////////////////////////////////////
+class SocketImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ // Types
+ ////////////////////////////////////////////////////////////
+ typedef int AddrLength;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create an internal sockaddr_in address
+ ///
+ /// \param address Target address
+ /// \param port Target port
+ ///
+ /// \return sockaddr_in ready to be used by socket functions
+ ///
+ ////////////////////////////////////////////////////////////
+ static sockaddr_in createAddress(Uint32 address, unsigned short port);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Return the value of the invalid socket
+ ///
+ /// \return Special value of the invalid socket
+ ///
+ ////////////////////////////////////////////////////////////
+ static SocketHandle invalidSocket();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close and destroy a socket
+ ///
+ /// \param sock Handle of the socket to close
+ ///
+ ////////////////////////////////////////////////////////////
+ static void close(SocketHandle sock);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set a socket as blocking or non-blocking
+ ///
+ /// \param sock Handle of the socket
+ /// \param block New blocking state of the socket
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setBlocking(SocketHandle sock, bool block);
+
+ ////////////////////////////////////////////////////////////
+ /// Get the last socket error status
+ ///
+ /// \return Status corresponding to the last socket error
+ ///
+ ////////////////////////////////////////////////////////////
+ static Socket::Status getErrorStatus();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SOCKETIMPL_HPP
diff --git a/src/SFML/System/Android/Activity.cpp b/src/SFML/System/Android/Activity.cpp
new file mode 100644
index 0000000..5d14026
--- /dev/null
+++ b/src/SFML/System/Android/Activity.cpp
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Laurent Gomila (laurent@sfml-dev.org)
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Android/Activity.hpp>
+#include <android/log.h>
+
+#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "sfml-error", __VA_ARGS__))
+
+LogcatStream::LogcatStream() :
+std::streambuf()
+{
+ // Nothing to do
+}
+
+std::streambuf::int_type LogcatStream::overflow (std::streambuf::int_type c)
+{
+ if (c == "\n"[0])
+ {
+ m_message.push_back(c);
+ LOGE("%s", m_message.c_str());
+ m_message.clear();
+ }
+
+ m_message.push_back(c);
+
+ return traits_type::not_eof(c);
+}
+
+namespace sf
+{
+namespace priv
+{
+ActivityStates* getActivity(ActivityStates* initializedStates, bool reset)
+{
+ static ActivityStates* states = NULL;
+
+ if (!states || reset)
+ states = initializedStates;
+
+ return states;
+}
+}
+}
diff --git a/src/SFML/System/Android/Activity.hpp b/src/SFML/System/Android/Activity.hpp
new file mode 100644
index 0000000..bd6bbc9
--- /dev/null
+++ b/src/SFML/System/Android/Activity.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_ACTIVITY_HPP
+#define SFML_ACTIVITY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/EglContext.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <android/native_activity.h>
+#include <android/configuration.h>
+#include <EGL/egl.h>
+#include <vector>
+#include <map>
+#include <string>
+#include <fstream>
+
+class SFML_SYSTEM_API LogcatStream : public std::streambuf
+{
+public:
+ LogcatStream();
+
+ std::streambuf::int_type overflow (std::streambuf::int_type c);
+
+private:
+ std::string m_message;
+};
+
+namespace sf
+{
+namespace priv
+{
+struct ActivityStates
+{
+ ANativeActivity* activity;
+ ANativeWindow* window;
+
+ ALooper* looper;
+ AInputQueue* inputQueue;
+ AConfiguration* config;
+
+ EGLDisplay display;
+ EglContext* context;
+
+ void* savedState;
+ size_t savedStateSize;
+
+ Mutex mutex;
+
+ void (*forwardEvent)(const Event& event);
+ int (*processEvent)(int fd, int events, void* data);
+
+ std::map<int, Vector2i> touchEvents;
+ Vector2i mousePosition;
+ bool isButtonPressed[Mouse::ButtonCount];
+
+ bool mainOver;
+
+ Vector2i screenSize;
+
+ bool initialized;
+ bool terminated;
+
+ bool fullscreen;
+
+ bool updated;
+
+ LogcatStream logcat;
+};
+
+SFML_SYSTEM_API ActivityStates* getActivity(ActivityStates* initializedStates=NULL, bool reset=false);
+
+} // namespace priv
+} // namespace sf
+
+
+#endif // SFML_ACTIVITY_HPP
diff --git a/src/SFML/System/Android/NativeActivity.cpp b/src/SFML/System/Android/NativeActivity.cpp
new file mode 100644
index 0000000..ac489ae
--- /dev/null
+++ b/src/SFML/System/Android/NativeActivity.cpp
@@ -0,0 +1,39 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/NativeActivity.hpp>
+#include <SFML/System/Android/Activity.hpp>
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+ANativeActivity* getNativeActivity()
+{
+ return priv::getActivity()->activity;
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Android/ResourceStream.cpp b/src/SFML/System/Android/ResourceStream.cpp
new file mode 100644
index 0000000..93280aa
--- /dev/null
+++ b/src/SFML/System/Android/ResourceStream.cpp
@@ -0,0 +1,116 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Android/ResourceStream.hpp>
+#include <SFML/System/Android/Activity.hpp>
+#include <SFML/System/Lock.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+ResourceStream::ResourceStream(const std::string& filename) :
+m_file (NULL)
+{
+ ActivityStates* states = getActivity(NULL);
+ Lock(states->mutex);
+ m_file = AAssetManager_open(states->activity->assetManager, filename.c_str(), AASSET_MODE_UNKNOWN);
+}
+
+
+////////////////////////////////////////////////////////////
+ResourceStream::~ResourceStream()
+{
+ if (m_file)
+ {
+ AAsset_close(m_file);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 ResourceStream::read(void *data, Int64 size)
+{
+ if (m_file)
+ {
+ return AAsset_read(m_file, data, size);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 ResourceStream::seek(Int64 position)
+{
+ if (m_file)
+ {
+ return AAsset_seek(m_file, position, SEEK_SET);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 ResourceStream::tell()
+{
+ if (m_file)
+ {
+ return getSize() - AAsset_getRemainingLength(m_file);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 ResourceStream::getSize()
+{
+ if (m_file)
+ {
+ return AAsset_getLength(m_file);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+} // namespace priv
+} // namespace sf
diff --git a/src/SFML/System/Android/ResourceStream.hpp b/src/SFML/System/Android/ResourceStream.hpp
new file mode 100644
index 0000000..8f5829b
--- /dev/null
+++ b/src/SFML/System/Android/ResourceStream.hpp
@@ -0,0 +1,113 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_RESOURCESTREAM_HPP
+#define SFML_RESOURCESTREAM_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Export.hpp>
+#include <SFML/System/InputStream.hpp>
+#include <android/asset_manager.h>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Read from Android asset files
+///
+////////////////////////////////////////////////////////////
+class SFML_SYSTEM_API ResourceStream : public InputStream
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// \param filename Filename of the asset
+ ///
+ ////////////////////////////////////////////////////////////
+ ResourceStream(const std::string& filename);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ResourceStream();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Read data from the asset
+ ///
+ /// \param data Buffer where the asset data is copied
+ /// \param size Number of bytes read
+ ///
+ /// \return The number of bytes actually read, or -1 on error
+ ///
+ ////////////////////////////////////////////////////////////
+ Int64 read(void *data, Int64 size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the current reading position in the asset file
+ ///
+ /// \param position The position to seek to, from the beginning
+ ///
+ /// \return The position actually sought to, or -1 on error
+ ///
+ ////////////////////////////////////////////////////////////
+ Int64 seek(Int64 position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current reading position in the asset file
+ ///
+ /// \return The current position, or -1 on error.
+ ///
+ ////////////////////////////////////////////////////////////
+ Int64 tell();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Return the size of the asset file
+ ///
+ /// \return The total number of bytes available in the asset, or -1 on error
+ ///
+ ////////////////////////////////////////////////////////////
+ Int64 getSize();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ AAsset* m_file; ///< The asset file to read
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_RESOURCESTREAM_HPP
diff --git a/src/SFML/System/CMakeLists.txt b/src/SFML/System/CMakeLists.txt
new file mode 100644
index 0000000..d1b712d
--- /dev/null
+++ b/src/SFML/System/CMakeLists.txt
@@ -0,0 +1,102 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/System)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/System)
+
+# all source files
+set(SRC
+ ${SRCROOT}/Clock.cpp
+ ${INCROOT}/Clock.hpp
+ ${SRCROOT}/Err.cpp
+ ${INCROOT}/Err.hpp
+ ${INCROOT}/Export.hpp
+ ${INCROOT}/InputStream.hpp
+ ${SRCROOT}/Lock.cpp
+ ${INCROOT}/Lock.hpp
+ ${SRCROOT}/Mutex.cpp
+ ${INCROOT}/Mutex.hpp
+ ${INCROOT}/NativeActivity.hpp
+ ${INCROOT}/NonCopyable.hpp
+ ${SRCROOT}/Sleep.cpp
+ ${INCROOT}/Sleep.hpp
+ ${SRCROOT}/String.cpp
+ ${INCROOT}/String.hpp
+ ${INCROOT}/String.inl
+ ${SRCROOT}/Thread.cpp
+ ${INCROOT}/Thread.hpp
+ ${INCROOT}/Thread.inl
+ ${SRCROOT}/ThreadLocal.cpp
+ ${INCROOT}/ThreadLocal.hpp
+ ${INCROOT}/ThreadLocalPtr.hpp
+ ${INCROOT}/ThreadLocalPtr.inl
+ ${SRCROOT}/Time.cpp
+ ${INCROOT}/Time.hpp
+ ${INCROOT}/Utf.hpp
+ ${INCROOT}/Utf.inl
+ ${INCROOT}/Vector2.hpp
+ ${INCROOT}/Vector2.inl
+ ${INCROOT}/Vector3.hpp
+ ${INCROOT}/Vector3.inl
+ ${SRCROOT}/FileInputStream.cpp
+ ${INCROOT}/FileInputStream.hpp
+ ${SRCROOT}/MemoryInputStream.cpp
+ ${INCROOT}/MemoryInputStream.hpp
+)
+source_group("" FILES ${SRC})
+
+# add platform specific sources
+if(SFML_OS_WINDOWS)
+ set(PLATFORM_SRC
+ ${SRCROOT}/Win32/ClockImpl.cpp
+ ${SRCROOT}/Win32/ClockImpl.hpp
+ ${SRCROOT}/Win32/MutexImpl.cpp
+ ${SRCROOT}/Win32/MutexImpl.hpp
+ ${SRCROOT}/Win32/SleepImpl.cpp
+ ${SRCROOT}/Win32/SleepImpl.hpp
+ ${SRCROOT}/Win32/ThreadImpl.cpp
+ ${SRCROOT}/Win32/ThreadImpl.hpp
+ ${SRCROOT}/Win32/ThreadLocalImpl.cpp
+ ${SRCROOT}/Win32/ThreadLocalImpl.hpp
+ )
+ source_group("windows" FILES ${PLATFORM_SRC})
+else()
+ set(PLATFORM_SRC
+ ${SRCROOT}/Unix/ClockImpl.cpp
+ ${SRCROOT}/Unix/ClockImpl.hpp
+ ${SRCROOT}/Unix/MutexImpl.cpp
+ ${SRCROOT}/Unix/MutexImpl.hpp
+ ${SRCROOT}/Unix/SleepImpl.cpp
+ ${SRCROOT}/Unix/SleepImpl.hpp
+ ${SRCROOT}/Unix/ThreadImpl.cpp
+ ${SRCROOT}/Unix/ThreadImpl.hpp
+ ${SRCROOT}/Unix/ThreadLocalImpl.cpp
+ ${SRCROOT}/Unix/ThreadLocalImpl.hpp
+ )
+
+ if(SFML_OS_ANDROID)
+ set(PLATFORM_SRC ${PLATFORM_SRC}
+ ${SRCROOT}/Android/Activity.hpp
+ ${SRCROOT}/Android/Activity.cpp
+ ${SRCROOT}/Android/NativeActivity.cpp
+ ${SRCROOT}/Android/ResourceStream.cpp
+ ${SRCROOT}/Android/ResourceStream.cpp
+ )
+ endif()
+
+ source_group("unix" FILES ${PLATFORM_SRC})
+endif()
+
+# define the sfml-system target
+sfml_add_library(sfml-system
+ SOURCES ${SRC} ${PLATFORM_SRC})
+
+# setup dependencies
+if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_MACOSX)
+ target_link_libraries(sfml-system PRIVATE pthread)
+endif()
+if(SFML_OS_LINUX)
+ target_link_libraries(sfml-system PRIVATE rt)
+elseif(SFML_OS_WINDOWS)
+ target_link_libraries(sfml-system PRIVATE winmm)
+elseif(SFML_OS_ANDROID)
+ target_link_libraries(sfml-system PRIVATE android log)
+endif()
diff --git a/src/SFML/System/Clock.cpp b/src/SFML/System/Clock.cpp
new file mode 100644
index 0000000..9f09533
--- /dev/null
+++ b/src/SFML/System/Clock.cpp
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Clock.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/System/Win32/ClockImpl.hpp>
+#else
+ #include <SFML/System/Unix/ClockImpl.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Clock::Clock() :
+m_startTime(priv::ClockImpl::getCurrentTime())
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Time Clock::getElapsedTime() const
+{
+ return priv::ClockImpl::getCurrentTime() - m_startTime;
+}
+
+
+////////////////////////////////////////////////////////////
+Time Clock::restart()
+{
+ Time now = priv::ClockImpl::getCurrentTime();
+ Time elapsed = now - m_startTime;
+ m_startTime = now;
+
+ return elapsed;
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Err.cpp b/src/SFML/System/Err.cpp
new file mode 100644
index 0000000..d186931
--- /dev/null
+++ b/src/SFML/System/Err.cpp
@@ -0,0 +1,110 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Err.hpp>
+#include <streambuf>
+#include <cstdio>
+
+
+namespace
+{
+// This class will be used as the default streambuf of sf::Err,
+// it outputs to stderr by default (to keep the default behavior)
+class DefaultErrStreamBuf : public std::streambuf
+{
+public:
+
+ DefaultErrStreamBuf()
+ {
+ // Allocate the write buffer
+ static const int size = 64;
+ char* buffer = new char[size];
+ setp(buffer, buffer + size);
+ }
+
+ ~DefaultErrStreamBuf()
+ {
+ // Synchronize
+ sync();
+
+ // Delete the write buffer
+ delete[] pbase();
+ }
+
+private:
+
+ virtual int overflow(int character)
+ {
+ if ((character != EOF) && (pptr() != epptr()))
+ {
+ // Valid character
+ return sputc(static_cast<char>(character));
+ }
+ else if (character != EOF)
+ {
+ // Not enough space in the buffer: synchronize output and try again
+ sync();
+ return overflow(character);
+ }
+ else
+ {
+ // Invalid character: synchronize output
+ return sync();
+ }
+ }
+
+ virtual int sync()
+ {
+ // Check if there is something into the write buffer
+ if (pbase() != pptr())
+ {
+ // Print the contents of the write buffer into the standard error output
+ std::size_t size = static_cast<int>(pptr() - pbase());
+ fwrite(pbase(), 1, size, stderr);
+
+ // Reset the pointer position to the beginning of the write buffer
+ setp(pbase(), epptr());
+ }
+
+ return 0;
+ }
+};
+}
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+std::ostream& err()
+{
+ static DefaultErrStreamBuf buffer;
+ static std::ostream stream(&buffer);
+
+ return stream;
+}
+
+
+} // namespace sf
diff --git a/src/SFML/System/FileInputStream.cpp b/src/SFML/System/FileInputStream.cpp
new file mode 100644
index 0000000..89e77c4
--- /dev/null
+++ b/src/SFML/System/FileInputStream.cpp
@@ -0,0 +1,146 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/FileInputStream.hpp>
+#ifdef SFML_SYSTEM_ANDROID
+#include <SFML/System/Android/ResourceStream.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+FileInputStream::FileInputStream()
+: m_file(NULL)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+FileInputStream::~FileInputStream()
+{
+#ifdef SFML_SYSTEM_ANDROID
+ if (m_file)
+ delete m_file;
+#else
+ if (m_file)
+ std::fclose(m_file);
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+bool FileInputStream::open(const std::string& filename)
+{
+#ifdef SFML_SYSTEM_ANDROID
+ if (m_file)
+ delete m_file;
+ m_file = new priv::ResourceStream(filename);
+ return m_file->tell() != -1;
+#else
+ if (m_file)
+ std::fclose(m_file);
+
+ m_file = std::fopen(filename.c_str(), "rb");
+
+ return m_file != NULL;
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 FileInputStream::read(void* data, Int64 size)
+{
+#ifdef SFML_SYSTEM_ANDROID
+ return m_file->read(data, size);
+#else
+ if (m_file)
+ return std::fread(data, 1, static_cast<std::size_t>(size), m_file);
+ else
+ return -1;
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 FileInputStream::seek(Int64 position)
+{
+#ifdef SFML_SYSTEM_ANDROID
+ return m_file->seek(position);
+#else
+ if (m_file)
+ {
+ if (std::fseek(m_file, static_cast<long>(position), SEEK_SET))
+ return -1;
+
+ return tell();
+ }
+ else
+ {
+ return -1;
+ }
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 FileInputStream::tell()
+{
+#ifdef SFML_SYSTEM_ANDROID
+ return m_file->tell();
+#else
+ if (m_file)
+ return std::ftell(m_file);
+ else
+ return -1;
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 FileInputStream::getSize()
+{
+#ifdef SFML_SYSTEM_ANDROID
+ return m_file->getSize();
+#else
+ if (m_file)
+ {
+ Int64 position = tell();
+ std::fseek(m_file, 0, SEEK_END);
+ Int64 size = tell();
+ seek(position);
+ return size;
+ }
+ else
+ {
+ return -1;
+ }
+#endif
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Lock.cpp b/src/SFML/System/Lock.cpp
new file mode 100644
index 0000000..ada1ca1
--- /dev/null
+++ b/src/SFML/System/Lock.cpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Mutex.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Lock::Lock(Mutex& mutex) :
+m_mutex(mutex)
+{
+ m_mutex.lock();
+}
+
+
+////////////////////////////////////////////////////////////
+Lock::~Lock()
+{
+ m_mutex.unlock();
+}
+
+} // namespace sf
diff --git a/src/SFML/System/MemoryInputStream.cpp b/src/SFML/System/MemoryInputStream.cpp
new file mode 100644
index 0000000..3bd02b4
--- /dev/null
+++ b/src/SFML/System/MemoryInputStream.cpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/MemoryInputStream.hpp>
+#include <cstring>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+MemoryInputStream::MemoryInputStream() :
+m_data (NULL),
+m_size (0),
+m_offset(0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void MemoryInputStream::open(const void* data, std::size_t sizeInBytes)
+{
+ m_data = static_cast<const char*>(data);
+ m_size = sizeInBytes;
+ m_offset = 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 MemoryInputStream::read(void* data, Int64 size)
+{
+ if (!m_data)
+ return -1;
+
+ Int64 endPosition = m_offset + size;
+ Int64 count = endPosition <= m_size ? size : m_size - m_offset;
+
+ if (count > 0)
+ {
+ std::memcpy(data, m_data + m_offset, static_cast<std::size_t>(count));
+ m_offset += count;
+ }
+
+ return count;
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 MemoryInputStream::seek(Int64 position)
+{
+ if (!m_data)
+ return -1;
+
+ m_offset = position < m_size ? position : m_size;
+ return m_offset;
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 MemoryInputStream::tell()
+{
+ if (!m_data)
+ return -1;
+
+ return m_offset;
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 MemoryInputStream::getSize()
+{
+ if (!m_data)
+ return -1;
+
+ return m_size;
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Mutex.cpp b/src/SFML/System/Mutex.cpp
new file mode 100644
index 0000000..139bf56
--- /dev/null
+++ b/src/SFML/System/Mutex.cpp
@@ -0,0 +1,66 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Mutex.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/System/Win32/MutexImpl.hpp>
+#else
+ #include <SFML/System/Unix/MutexImpl.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Mutex::Mutex()
+{
+ m_mutexImpl = new priv::MutexImpl;
+}
+
+
+////////////////////////////////////////////////////////////
+Mutex::~Mutex()
+{
+ delete m_mutexImpl;
+}
+
+
+////////////////////////////////////////////////////////////
+void Mutex::lock()
+{
+ m_mutexImpl->lock();
+}
+
+
+////////////////////////////////////////////////////////////
+void Mutex::unlock()
+{
+ m_mutexImpl->unlock();
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Sleep.cpp b/src/SFML/System/Sleep.cpp
new file mode 100644
index 0000000..35db5e8
--- /dev/null
+++ b/src/SFML/System/Sleep.cpp
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Sleep.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/System/Win32/SleepImpl.hpp>
+#else
+ #include <SFML/System/Unix/SleepImpl.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+void sleep(Time duration)
+{
+ if (duration >= Time::Zero)
+ priv::sleepImpl(duration);
+}
+
+} // namespace sf
diff --git a/src/SFML/System/String.cpp b/src/SFML/System/String.cpp
new file mode 100644
index 0000000..d8831f9
--- /dev/null
+++ b/src/SFML/System/String.cpp
@@ -0,0 +1,400 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+#include <SFML/System/Utf.hpp>
+#include <iterator>
+#include <cstring>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+const std::size_t String::InvalidPos = std::basic_string<Uint32>::npos;
+
+
+////////////////////////////////////////////////////////////
+String::String()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(char ansiChar, const std::locale& locale)
+{
+ m_string += Utf32::decodeAnsi(ansiChar, locale);
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(wchar_t wideChar)
+{
+ m_string += Utf32::decodeWide(wideChar);
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(Uint32 utf32Char)
+{
+ m_string += utf32Char;
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const char* ansiString, const std::locale& locale)
+{
+ if (ansiString)
+ {
+ std::size_t length = strlen(ansiString);
+ if (length > 0)
+ {
+ m_string.reserve(length + 1);
+ Utf32::fromAnsi(ansiString, ansiString + length, std::back_inserter(m_string), locale);
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const std::string& ansiString, const std::locale& locale)
+{
+ m_string.reserve(ansiString.length() + 1);
+ Utf32::fromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(m_string), locale);
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const wchar_t* wideString)
+{
+ if (wideString)
+ {
+ std::size_t length = std::wcslen(wideString);
+ if (length > 0)
+ {
+ m_string.reserve(length + 1);
+ Utf32::fromWide(wideString, wideString + length, std::back_inserter(m_string));
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const std::wstring& wideString)
+{
+ m_string.reserve(wideString.length() + 1);
+ Utf32::fromWide(wideString.begin(), wideString.end(), std::back_inserter(m_string));
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const Uint32* utf32String)
+{
+ if (utf32String)
+ m_string = utf32String;
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const std::basic_string<Uint32>& utf32String) :
+m_string(utf32String)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+String::String(const String& copy) :
+m_string(copy.m_string)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+String::operator std::string() const
+{
+ return toAnsiString();
+}
+
+
+////////////////////////////////////////////////////////////
+String::operator std::wstring() const
+{
+ return toWideString();
+}
+
+
+////////////////////////////////////////////////////////////
+std::string String::toAnsiString(const std::locale& locale) const
+{
+ // Prepare the output string
+ std::string output;
+ output.reserve(m_string.length() + 1);
+
+ // Convert
+ Utf32::toAnsi(m_string.begin(), m_string.end(), std::back_inserter(output), 0, locale);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+std::wstring String::toWideString() const
+{
+ // Prepare the output string
+ std::wstring output;
+ output.reserve(m_string.length() + 1);
+
+ // Convert
+ Utf32::toWide(m_string.begin(), m_string.end(), std::back_inserter(output), 0);
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+std::basic_string<Uint8> String::toUtf8() const
+{
+ // Prepare the output string
+ std::basic_string<Uint8> output;
+ output.reserve(m_string.length());
+
+ // Convert
+ Utf32::toUtf8(m_string.begin(), m_string.end(), std::back_inserter(output));
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+std::basic_string<Uint16> String::toUtf16() const
+{
+ // Prepare the output string
+ std::basic_string<Uint16> output;
+ output.reserve(m_string.length());
+
+ // Convert
+ Utf32::toUtf16(m_string.begin(), m_string.end(), std::back_inserter(output));
+
+ return output;
+}
+
+
+////////////////////////////////////////////////////////////
+std::basic_string<Uint32> String::toUtf32() const
+{
+ return m_string;
+}
+
+
+////////////////////////////////////////////////////////////
+String& String::operator =(const String& right)
+{
+ m_string = right.m_string;
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+String& String::operator +=(const String& right)
+{
+ m_string += right.m_string;
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+Uint32 String::operator [](std::size_t index) const
+{
+ return m_string[index];
+}
+
+
+////////////////////////////////////////////////////////////
+Uint32& String::operator [](std::size_t index)
+{
+ return m_string[index];
+}
+
+
+////////////////////////////////////////////////////////////
+void String::clear()
+{
+ m_string.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t String::getSize() const
+{
+ return m_string.size();
+}
+
+
+////////////////////////////////////////////////////////////
+bool String::isEmpty() const
+{
+ return m_string.empty();
+}
+
+
+////////////////////////////////////////////////////////////
+void String::erase(std::size_t position, std::size_t count)
+{
+ m_string.erase(position, count);
+}
+
+
+////////////////////////////////////////////////////////////
+void String::insert(std::size_t position, const String& str)
+{
+ m_string.insert(position, str.m_string);
+}
+
+
+////////////////////////////////////////////////////////////
+std::size_t String::find(const String& str, std::size_t start) const
+{
+ return m_string.find(str.m_string, start);
+}
+
+
+////////////////////////////////////////////////////////////
+void String::replace(std::size_t position, std::size_t length, const String& replaceWith)
+{
+ m_string.replace(position, length, replaceWith.m_string);
+}
+
+
+////////////////////////////////////////////////////////////
+void String::replace(const String& searchFor, const String& replaceWith)
+{
+ std::size_t step = replaceWith.getSize();
+ std::size_t len = searchFor.getSize();
+ std::size_t pos = find(searchFor);
+
+ // Replace each occurrence of search
+ while (pos != InvalidPos)
+ {
+ replace(pos, len, replaceWith);
+ pos = find(searchFor, pos + step);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+String String::substring(std::size_t position, std::size_t length) const
+{
+ return m_string.substr(position, length);
+}
+
+
+////////////////////////////////////////////////////////////
+const Uint32* String::getData() const
+{
+ return m_string.c_str();
+}
+
+
+////////////////////////////////////////////////////////////
+String::Iterator String::begin()
+{
+ return m_string.begin();
+}
+
+
+////////////////////////////////////////////////////////////
+String::ConstIterator String::begin() const
+{
+ return m_string.begin();
+}
+
+
+////////////////////////////////////////////////////////////
+String::Iterator String::end()
+{
+ return m_string.end();
+}
+
+
+////////////////////////////////////////////////////////////
+String::ConstIterator String::end() const
+{
+ return m_string.end();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const String& left, const String& right)
+{
+ return left.m_string == right.m_string;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const String& left, const String& right)
+{
+ return !(left == right);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <(const String& left, const String& right)
+{
+ return left.m_string < right.m_string;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >(const String& left, const String& right)
+{
+ return right < left;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <=(const String& left, const String& right)
+{
+ return !(right < left);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >=(const String& left, const String& right)
+{
+ return !(left < right);
+}
+
+
+////////////////////////////////////////////////////////////
+String operator +(const String& left, const String& right)
+{
+ String string = left;
+ string += right;
+
+ return string;
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Thread.cpp b/src/SFML/System/Thread.cpp
new file mode 100644
index 0000000..098018a
--- /dev/null
+++ b/src/SFML/System/Thread.cpp
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Thread.hpp>
+
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/System/Win32/ThreadImpl.hpp>
+#else
+ #include <SFML/System/Unix/ThreadImpl.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Thread::~Thread()
+{
+ wait();
+ delete m_entryPoint;
+}
+
+
+////////////////////////////////////////////////////////////
+void Thread::launch()
+{
+ wait();
+ m_impl = new priv::ThreadImpl(this);
+}
+
+
+////////////////////////////////////////////////////////////
+void Thread::wait()
+{
+ if (m_impl)
+ {
+ m_impl->wait();
+ delete m_impl;
+ m_impl = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Thread::terminate()
+{
+ if (m_impl)
+ {
+ m_impl->terminate();
+ delete m_impl;
+ m_impl = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Thread::run()
+{
+ m_entryPoint->run();
+}
+
+} // namespace sf
diff --git a/src/SFML/System/ThreadLocal.cpp b/src/SFML/System/ThreadLocal.cpp
new file mode 100644
index 0000000..62d8117
--- /dev/null
+++ b/src/SFML/System/ThreadLocal.cpp
@@ -0,0 +1,67 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/ThreadLocal.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/System/Win32/ThreadLocalImpl.hpp>
+#else
+ #include <SFML/System/Unix/ThreadLocalImpl.hpp>
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+ThreadLocal::ThreadLocal(void* value)
+{
+ m_impl = new priv::ThreadLocalImpl;
+ setValue(value);
+}
+
+
+////////////////////////////////////////////////////////////
+ThreadLocal::~ThreadLocal()
+{
+ delete m_impl;
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadLocal::setValue(void* value)
+{
+ m_impl->setValue(value);
+}
+
+
+////////////////////////////////////////////////////////////
+void* ThreadLocal::getValue() const
+{
+ return m_impl->getValue();
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Time.cpp b/src/SFML/System/Time.cpp
new file mode 100644
index 0000000..681c9a9
--- /dev/null
+++ b/src/SFML/System/Time.cpp
@@ -0,0 +1,260 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Time.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+const Time Time::Zero;
+
+
+////////////////////////////////////////////////////////////
+Time::Time() :
+m_microseconds(0)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+float Time::asSeconds() const
+{
+ return m_microseconds / 1000000.f;
+}
+
+
+////////////////////////////////////////////////////////////
+Int32 Time::asMilliseconds() const
+{
+ return static_cast<Int32>(m_microseconds / 1000);
+}
+
+
+////////////////////////////////////////////////////////////
+Int64 Time::asMicroseconds() const
+{
+ return m_microseconds;
+}
+
+
+////////////////////////////////////////////////////////////
+Time::Time(Int64 microseconds) :
+m_microseconds(microseconds)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Time seconds(float amount)
+{
+ return Time(static_cast<Int64>(amount * 1000000));
+}
+
+
+////////////////////////////////////////////////////////////
+Time milliseconds(Int32 amount)
+{
+ return Time(static_cast<Int64>(amount) * 1000);
+}
+
+
+////////////////////////////////////////////////////////////
+Time microseconds(Int64 amount)
+{
+ return Time(amount);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(Time left, Time right)
+{
+ return left.asMicroseconds() == right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(Time left, Time right)
+{
+ return left.asMicroseconds() != right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <(Time left, Time right)
+{
+ return left.asMicroseconds() < right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >(Time left, Time right)
+{
+ return left.asMicroseconds() > right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <=(Time left, Time right)
+{
+ return left.asMicroseconds() <= right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >=(Time left, Time right)
+{
+ return left.asMicroseconds() >= right.asMicroseconds();
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator -(Time right)
+{
+ return microseconds(-right.asMicroseconds());
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator +(Time left, Time right)
+{
+ return microseconds(left.asMicroseconds() + right.asMicroseconds());
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator +=(Time& left, Time right)
+{
+ return left = left + right;
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator -(Time left, Time right)
+{
+ return microseconds(left.asMicroseconds() - right.asMicroseconds());
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator -=(Time& left, Time right)
+{
+ return left = left - right;
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator *(Time left, float right)
+{
+ return seconds(left.asSeconds() * right);
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator *(Time left, Int64 right)
+{
+ return microseconds(left.asMicroseconds() * right);
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator *(float left, Time right)
+{
+ return right * left;
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator *(Int64 left, Time right)
+{
+ return right * left;
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator *=(Time& left, float right)
+{
+ return left = left * right;
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator *=(Time& left, Int64 right)
+{
+ return left = left * right;
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator /(Time left, float right)
+{
+ return seconds(left.asSeconds() / right);
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator /(Time left, Int64 right)
+{
+ return microseconds(left.asMicroseconds() / right);
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator /=(Time& left, float right)
+{
+ return left = left / right;
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator /=(Time& left, Int64 right)
+{
+ return left = left / right;
+}
+
+
+////////////////////////////////////////////////////////////
+float operator /(Time left, Time right)
+{
+ return left.asSeconds() / right.asSeconds();
+}
+
+
+////////////////////////////////////////////////////////////
+Time operator %(Time left, Time right)
+{
+ return microseconds(left.asMicroseconds() % right.asMicroseconds());
+}
+
+
+////////////////////////////////////////////////////////////
+Time& operator %=(Time& left, Time right)
+{
+ return left = left % right;
+}
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/ClockImpl.cpp b/src/SFML/System/Unix/ClockImpl.cpp
new file mode 100644
index 0000000..0d4f2bd
--- /dev/null
+++ b/src/SFML/System/Unix/ClockImpl.cpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Unix/ClockImpl.hpp>
+#if defined(SFML_SYSTEM_MACOS) || defined(SFML_SYSTEM_IOS)
+ #include <mach/mach_time.h>
+#else
+ #include <time.h>
+#endif
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+Time ClockImpl::getCurrentTime()
+{
+#if defined(SFML_SYSTEM_MACOS) || defined(SFML_SYSTEM_IOS)
+
+ // Mac OS X specific implementation (it doesn't support clock_gettime)
+ static mach_timebase_info_data_t frequency = {0, 0};
+ if (frequency.denom == 0)
+ mach_timebase_info(&frequency);
+ Uint64 nanoseconds = mach_absolute_time() * frequency.numer / frequency.denom;
+ return sf::microseconds(nanoseconds / 1000);
+
+#else
+
+ // POSIX implementation
+ timespec time;
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ return sf::microseconds(static_cast<Uint64>(time.tv_sec) * 1000000 + time.tv_nsec / 1000);
+
+#endif
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/ClockImpl.hpp b/src/SFML/System/Unix/ClockImpl.hpp
new file mode 100644
index 0000000..56f550c
--- /dev/null
+++ b/src/SFML/System/Unix/ClockImpl.hpp
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLOCKIMPLUNIX_HPP
+#define SFML_CLOCKIMPLUNIX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/Time.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of sf::Clock
+///
+////////////////////////////////////////////////////////////
+class ClockImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current time
+ ///
+ /// \return Current time
+ ///
+ ////////////////////////////////////////////////////////////
+ static Time getCurrentTime();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLOCKIMPLUNIX_HPP
diff --git a/src/SFML/System/Unix/MutexImpl.cpp b/src/SFML/System/Unix/MutexImpl.cpp
new file mode 100644
index 0000000..cc4e38e
--- /dev/null
+++ b/src/SFML/System/Unix/MutexImpl.cpp
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Unix/MutexImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+MutexImpl::MutexImpl()
+{
+ // Make it recursive to follow the expected behavior
+ pthread_mutexattr_t attributes;
+ pthread_mutexattr_init(&attributes);
+ pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
+
+ pthread_mutex_init(&m_mutex, &attributes);
+}
+
+
+////////////////////////////////////////////////////////////
+MutexImpl::~MutexImpl()
+{
+ pthread_mutex_destroy(&m_mutex);
+}
+
+
+////////////////////////////////////////////////////////////
+void MutexImpl::lock()
+{
+ pthread_mutex_lock(&m_mutex);
+}
+
+
+////////////////////////////////////////////////////////////
+void MutexImpl::unlock()
+{
+ pthread_mutex_unlock(&m_mutex);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/MutexImpl.hpp b/src/SFML/System/Unix/MutexImpl.hpp
new file mode 100644
index 0000000..cf0c0dd
--- /dev/null
+++ b/src/SFML/System/Unix/MutexImpl.hpp
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_MUTEXIMPL_HPP
+#define SFML_MUTEXIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <pthread.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of mutexes
+////////////////////////////////////////////////////////////
+class MutexImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ MutexImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~MutexImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Lock the mutex
+ ///
+ ////////////////////////////////////////////////////////////
+ void lock();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unlock the mutex
+ ///
+ ////////////////////////////////////////////////////////////
+ void unlock();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ pthread_mutex_t m_mutex; ///< pthread handle of the mutex
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_MUTEXIMPL_HPP
diff --git a/src/SFML/System/Unix/SleepImpl.cpp b/src/SFML/System/Unix/SleepImpl.cpp
new file mode 100644
index 0000000..f6fb608
--- /dev/null
+++ b/src/SFML/System/Unix/SleepImpl.cpp
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Unix/SleepImpl.hpp>
+#include <errno.h>
+#include <time.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void sleepImpl(Time time)
+{
+ Uint64 usecs = time.asMicroseconds();
+
+ // Construct the time to wait
+ timespec ti;
+ ti.tv_nsec = (usecs % 1000000) * 1000;
+ ti.tv_sec = usecs / 1000000;
+
+ // Wait...
+ // If nanosleep returns -1, we check errno. If it is EINTR
+ // nanosleep was interrupted and has set ti to the remaining
+ // duration. We continue sleeping until the complete duration
+ // has passed. We stop sleeping if it was due to an error.
+ while ((nanosleep(&ti, &ti) == -1) && (errno == EINTR))
+ {
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/SleepImpl.hpp b/src/SFML/System/Unix/SleepImpl.hpp
new file mode 100644
index 0000000..8d146d4
--- /dev/null
+++ b/src/SFML/System/Unix/SleepImpl.hpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SLEEPIMPLUNIX_HPP
+#define SFML_SLEEPIMPLUNIX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/Time.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of sf::Sleep
+///
+/// \param time Time to sleep
+///
+////////////////////////////////////////////////////////////
+void sleepImpl(Time time);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SLEEPIMPLUNIX_HPP
diff --git a/src/SFML/System/Unix/ThreadImpl.cpp b/src/SFML/System/Unix/ThreadImpl.cpp
new file mode 100644
index 0000000..e80213f
--- /dev/null
+++ b/src/SFML/System/Unix/ThreadImpl.cpp
@@ -0,0 +1,94 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Unix/ThreadImpl.hpp>
+#include <SFML/System/Thread.hpp>
+#include <iostream>
+#include <cassert>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+ThreadImpl::ThreadImpl(Thread* owner) :
+m_isActive(true)
+{
+ m_isActive = pthread_create(&m_thread, NULL, &ThreadImpl::entryPoint, owner) == 0;
+
+ if (!m_isActive)
+ std::cerr << "Failed to create thread" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadImpl::wait()
+{
+ if (m_isActive)
+ {
+ assert(pthread_equal(pthread_self(), m_thread) == 0); // A thread cannot wait for itself!
+ pthread_join(m_thread, NULL);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadImpl::terminate()
+{
+ if (m_isActive)
+ {
+ #ifndef SFML_SYSTEM_ANDROID
+ pthread_cancel(m_thread);
+ #else
+ // See https://stackoverflow.com/questions/4610086/pthread-cancel-al
+ pthread_kill(m_thread, SIGUSR1);
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void* ThreadImpl::entryPoint(void* userData)
+{
+ // The Thread instance is stored in the user data
+ Thread* owner = static_cast<Thread*>(userData);
+
+ #ifndef SFML_SYSTEM_ANDROID
+ // Tell the thread to handle cancel requests immediately
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ #endif
+
+ // Forward to the owner
+ owner->run();
+
+ return NULL;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/ThreadImpl.hpp b/src/SFML/System/Unix/ThreadImpl.hpp
new file mode 100644
index 0000000..2cd13d0
--- /dev/null
+++ b/src/SFML/System/Unix/ThreadImpl.hpp
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_THREADIMPL_HPP
+#define SFML_THREADIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <pthread.h>
+
+
+namespace sf
+{
+class Thread;
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of threads
+////////////////////////////////////////////////////////////
+class ThreadImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor, launch the thread
+ ///
+ /// \param owner The Thread instance to run
+ ///
+ ////////////////////////////////////////////////////////////
+ ThreadImpl(Thread* owner);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Wait until the thread finishes
+ ///
+ ////////////////////////////////////////////////////////////
+ void wait();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Terminate the thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void terminate();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Global entry point for all threads
+ ///
+ /// \param userData User-defined data (contains the Thread instance)
+ ///
+ /// \return Os specific error code
+ ///
+ ////////////////////////////////////////////////////////////
+ static void* entryPoint(void* userData);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ pthread_t m_thread; ///< pthread thread instance
+ bool m_isActive; ///< Thread state (active or inactive)
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_THREADIMPL_HPP
diff --git a/src/SFML/System/Unix/ThreadLocalImpl.cpp b/src/SFML/System/Unix/ThreadLocalImpl.cpp
new file mode 100644
index 0000000..1fea0c9
--- /dev/null
+++ b/src/SFML/System/Unix/ThreadLocalImpl.cpp
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Unix/ThreadLocalImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+ThreadLocalImpl::ThreadLocalImpl() :
+m_key(0)
+{
+ pthread_key_create(&m_key, NULL);
+}
+
+
+////////////////////////////////////////////////////////////
+ThreadLocalImpl::~ThreadLocalImpl()
+{
+ pthread_key_delete(m_key);
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadLocalImpl::setValue(void* value)
+{
+ pthread_setspecific(m_key, value);
+}
+
+
+////////////////////////////////////////////////////////////
+void* ThreadLocalImpl::getValue() const
+{
+ return pthread_getspecific(m_key);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Unix/ThreadLocalImpl.hpp b/src/SFML/System/Unix/ThreadLocalImpl.hpp
new file mode 100644
index 0000000..919dcd5
--- /dev/null
+++ b/src/SFML/System/Unix/ThreadLocalImpl.hpp
@@ -0,0 +1,87 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_THREADLOCALIMPL_HPP
+#define SFML_THREADLOCALIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <pthread.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of thread-local storage
+////////////////////////////////////////////////////////////
+class ThreadLocalImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor -- allocate the storage
+ ///
+ ////////////////////////////////////////////////////////////
+ ThreadLocalImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor -- free the storage
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ThreadLocalImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the thread-specific value of the variable
+ ///
+ /// \param value Value of the variable for this thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void setValue(void* value);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Retrieve the thread-specific value of the variable
+ ///
+ /// \return Value of the variable for this thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getValue() const;
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ pthread_key_t m_key; ///< Index of our thread-local storage slot
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_THREADLOCALIMPL_HPP
diff --git a/src/SFML/System/Win32/ClockImpl.cpp b/src/SFML/System/Win32/ClockImpl.cpp
new file mode 100644
index 0000000..f69da4b
--- /dev/null
+++ b/src/SFML/System/Win32/ClockImpl.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Win32/ClockImpl.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <windows.h>
+
+
+namespace
+{
+ LARGE_INTEGER getFrequency()
+ {
+ LARGE_INTEGER frequency;
+ QueryPerformanceFrequency(&frequency);
+ return frequency;
+ }
+
+ bool isWindowsXpOrOlder()
+ {
+ // Windows XP was the last 5.x version of Windows
+ return static_cast<DWORD>(LOBYTE(LOWORD(GetVersion()))) < 6;
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+Time ClockImpl::getCurrentTime()
+{
+ // Get the frequency of the performance counter
+ // (it is constant across the program lifetime)
+ static LARGE_INTEGER frequency = getFrequency();
+
+ // Detect if we are on Windows XP or older
+ static bool oldWindows = isWindowsXpOrOlder();
+
+ LARGE_INTEGER time;
+
+ if (oldWindows)
+ {
+ static sf::Mutex oldWindowsMutex;
+
+ // Acquire a lock (CRITICAL_SECTION) to prevent travelling back in time
+ Lock lock(oldWindowsMutex);
+
+ // Get the current time
+ QueryPerformanceCounter(&time);
+ }
+ else
+ {
+ // Get the current time
+ QueryPerformanceCounter(&time);
+ }
+
+ // Return the current time as microseconds
+ return sf::microseconds(1000000 * time.QuadPart / frequency.QuadPart);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Win32/ClockImpl.hpp b/src/SFML/System/Win32/ClockImpl.hpp
new file mode 100644
index 0000000..d40ec6f
--- /dev/null
+++ b/src/SFML/System/Win32/ClockImpl.hpp
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLOCKIMPLWIN32_HPP
+#define SFML_CLOCKIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/Time.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of sf::Clock
+///
+////////////////////////////////////////////////////////////
+class ClockImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current time
+ ///
+ /// \return Current time
+ ///
+ ////////////////////////////////////////////////////////////
+ static Time getCurrentTime();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLOCKIMPLWIN32_HPP
diff --git a/src/SFML/System/Win32/MutexImpl.cpp b/src/SFML/System/Win32/MutexImpl.cpp
new file mode 100644
index 0000000..8fdd388
--- /dev/null
+++ b/src/SFML/System/Win32/MutexImpl.cpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Win32/MutexImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+MutexImpl::MutexImpl()
+{
+ InitializeCriticalSection(&m_mutex);
+}
+
+
+////////////////////////////////////////////////////////////
+MutexImpl::~MutexImpl()
+{
+ DeleteCriticalSection(&m_mutex);
+}
+
+
+////////////////////////////////////////////////////////////
+void MutexImpl::lock()
+{
+ EnterCriticalSection(&m_mutex);
+}
+
+
+////////////////////////////////////////////////////////////
+void MutexImpl::unlock()
+{
+ LeaveCriticalSection(&m_mutex);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Win32/MutexImpl.hpp b/src/SFML/System/Win32/MutexImpl.hpp
new file mode 100644
index 0000000..9572114
--- /dev/null
+++ b/src/SFML/System/Win32/MutexImpl.hpp
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_MUTEXIMPL_HPP
+#define SFML_MUTEXIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of mutexes
+////////////////////////////////////////////////////////////
+class MutexImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ MutexImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~MutexImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Lock the mutex
+ ///
+ ////////////////////////////////////////////////////////////
+ void lock();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unlock the mutex
+ ///
+ ////////////////////////////////////////////////////////////
+ void unlock();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ CRITICAL_SECTION m_mutex; ///< Win32 handle of the mutex
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_MUTEXIMPL_HPP
diff --git a/src/SFML/System/Win32/SleepImpl.cpp b/src/SFML/System/Win32/SleepImpl.cpp
new file mode 100644
index 0000000..41c1018
--- /dev/null
+++ b/src/SFML/System/Win32/SleepImpl.cpp
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Win32/SleepImpl.hpp>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void sleepImpl(Time time)
+{
+ // Get the supported timer resolutions on this system
+ TIMECAPS tc;
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+
+ // Set the timer resolution to the minimum for the Sleep call
+ timeBeginPeriod(tc.wPeriodMin);
+
+ // Wait...
+ ::Sleep(time.asMilliseconds());
+
+ // Reset the timer resolution back to the system default
+ timeEndPeriod(tc.wPeriodMin);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Win32/SleepImpl.hpp b/src/SFML/System/Win32/SleepImpl.hpp
new file mode 100644
index 0000000..ad0138d
--- /dev/null
+++ b/src/SFML/System/Win32/SleepImpl.hpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SLEEPIMPLWIN32_HPP
+#define SFML_SLEEPIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/Time.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of sf::Sleep
+///
+/// \param time Time to sleep
+///
+////////////////////////////////////////////////////////////
+void sleepImpl(Time time);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SLEEPIMPLWIN32_HPP
diff --git a/src/SFML/System/Win32/ThreadImpl.cpp b/src/SFML/System/Win32/ThreadImpl.cpp
new file mode 100644
index 0000000..f5d2e2e
--- /dev/null
+++ b/src/SFML/System/Win32/ThreadImpl.cpp
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Win32/ThreadImpl.hpp>
+#include <SFML/System/Thread.hpp>
+#include <SFML/System/Err.hpp>
+#include <cassert>
+#include <process.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+ThreadImpl::ThreadImpl(Thread* owner)
+{
+ m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &ThreadImpl::entryPoint, owner, 0, &m_threadId));
+
+ if (!m_thread)
+ err() << "Failed to create thread" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+ThreadImpl::~ThreadImpl()
+{
+ if (m_thread)
+ CloseHandle(m_thread);
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadImpl::wait()
+{
+ if (m_thread)
+ {
+ assert(m_threadId != GetCurrentThreadId()); // A thread cannot wait for itself!
+ WaitForSingleObject(m_thread, INFINITE);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadImpl::terminate()
+{
+ if (m_thread)
+ TerminateThread(m_thread, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int __stdcall ThreadImpl::entryPoint(void* userData)
+{
+ // The Thread instance is stored in the user data
+ Thread* owner = static_cast<Thread*>(userData);
+
+ // Forward to the owner
+ owner->run();
+
+ // Optional, but it is cleaner
+ _endthreadex(0);
+
+ return 0;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Win32/ThreadImpl.hpp b/src/SFML/System/Win32/ThreadImpl.hpp
new file mode 100644
index 0000000..913585f
--- /dev/null
+++ b/src/SFML/System/Win32/ThreadImpl.hpp
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_THREADIMPL_HPP
+#define SFML_THREADIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <windows.h>
+
+// Fix for unaligned stack with clang and GCC on Windows XP 32-bit
+#if defined(SFML_SYSTEM_WINDOWS) && (defined(__clang__) || defined(__GNUC__))
+
+ #define ALIGN_STACK __attribute__((__force_align_arg_pointer__))
+
+#else
+
+ #define ALIGN_STACK
+
+#endif
+
+
+namespace sf
+{
+class Thread;
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of threads
+////////////////////////////////////////////////////////////
+class ThreadImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor, launch the thread
+ ///
+ /// \param owner The Thread instance to run
+ ///
+ ////////////////////////////////////////////////////////////
+ ThreadImpl(Thread* owner);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ThreadImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Wait until the thread finishes
+ ///
+ ////////////////////////////////////////////////////////////
+ void wait();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Terminate the thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void terminate();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Global entry point for all threads
+ ///
+ /// \param userData User-defined data (contains the Thread instance)
+ ///
+ /// \return OS specific error code
+ ///
+ ////////////////////////////////////////////////////////////
+ ALIGN_STACK static unsigned int __stdcall entryPoint(void* userData);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ HANDLE m_thread; ///< Win32 thread handle
+ unsigned int m_threadId; ///< Win32 thread identifier
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_THREADIMPL_HPP
diff --git a/src/SFML/System/Win32/ThreadLocalImpl.cpp b/src/SFML/System/Win32/ThreadLocalImpl.cpp
new file mode 100644
index 0000000..bd28da3
--- /dev/null
+++ b/src/SFML/System/Win32/ThreadLocalImpl.cpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Win32/ThreadLocalImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+ThreadLocalImpl::ThreadLocalImpl()
+{
+ m_index = TlsAlloc();
+}
+
+
+////////////////////////////////////////////////////////////
+ThreadLocalImpl::~ThreadLocalImpl()
+{
+ TlsFree(m_index);
+}
+
+
+////////////////////////////////////////////////////////////
+void ThreadLocalImpl::setValue(void* value)
+{
+ TlsSetValue(m_index, value);
+}
+
+
+////////////////////////////////////////////////////////////
+void* ThreadLocalImpl::getValue() const
+{
+ return TlsGetValue(m_index);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/System/Win32/ThreadLocalImpl.hpp b/src/SFML/System/Win32/ThreadLocalImpl.hpp
new file mode 100644
index 0000000..e617dfe
--- /dev/null
+++ b/src/SFML/System/Win32/ThreadLocalImpl.hpp
@@ -0,0 +1,87 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_THREADLOCALIMPL_HPP
+#define SFML_THREADLOCALIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of thread-local storage
+////////////////////////////////////////////////////////////
+class ThreadLocalImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor -- allocate the storage
+ ///
+ ////////////////////////////////////////////////////////////
+ ThreadLocalImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor -- free the storage
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ThreadLocalImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the thread-specific value of the variable
+ ///
+ /// \param value Value of the variable for this thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void setValue(void* value);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Retrieve the thread-specific value of the variable
+ ///
+ /// \return Value of the variable for this thread
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getValue() const;
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ DWORD m_index; ///< Index of our thread-local storage slot
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_THREADLOCALIMPL_HPP
diff --git a/src/SFML/Window/Android/ClipboardImpl.cpp b/src/SFML/Window/Android/ClipboardImpl.cpp
new file mode 100644
index 0000000..a5d3a19
--- /dev/null
+++ b/src/SFML/Window/Android/ClipboardImpl.cpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Android/ClipboardImpl.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getString()
+{
+ sf::err() << "Clipboard API not implemented for Android.\n";
+ return String();
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setString(const String& text)
+{
+ sf::err() << "Clipboard API not implemented for Android.\n";
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Android/ClipboardImpl.hpp b/src/SFML/Window/Android/ClipboardImpl.hpp
new file mode 100644
index 0000000..8d33dc6
--- /dev/null
+++ b/src/SFML/Window/Android/ClipboardImpl.hpp
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPLANDROID_HPP
+#define SFML_CLIPBOARDIMPLANDROID_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class ClipboardImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \param text sf::String object containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARDIMPLANDROID_HPP
diff --git a/src/SFML/Window/Android/CursorImpl.cpp b/src/SFML/Window/Android/CursorImpl.cpp
new file mode 100644
index 0000000..da5fff5
--- /dev/null
+++ b/src/SFML/Window/Android/CursorImpl.cpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Android/CursorImpl.hpp>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+CursorImpl::CursorImpl()
+{
+ // Nothing.
+}
+
+
+////////////////////////////////////////////////////////////
+CursorImpl::~CursorImpl()
+{
+ // Nothing.
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ // Not supported
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromSystem(Cursor::Type type)
+{
+ // Not supported
+ return false;
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/Android/CursorImpl.hpp b/src/SFML/Window/Android/CursorImpl.hpp
new file mode 100644
index 0000000..fe5f948
--- /dev/null
+++ b/src/SFML/Window/Android/CursorImpl.hpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSORIMPLANDROID_HPP
+#define SFML_CURSORIMPLANDROID_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+namespace sf
+{
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Android implementation of Cursor
+///
+/// This is a typical "not supported" implementation.
+///
+////////////////////////////////////////////////////////////
+class CursorImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Refer to sf::Cursor::Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// Refer to sf::Cursor::~Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ ~CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// Returns false.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Returns false.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Cursor::Type type);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_CURSORIMPLANDROID_HPP
diff --git a/src/SFML/Window/Android/InputImpl.cpp b/src/SFML/Window/Android/InputImpl.cpp
new file mode 100644
index 0000000..9da3a13
--- /dev/null
+++ b/src/SFML/Window/Android/InputImpl.cpp
@@ -0,0 +1,213 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Android/InputImpl.hpp>
+#include <SFML/System/Android/Activity.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <jni.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ // Not applicable
+ return false;
+}
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool visible)
+{
+ // todo: Check if the window is active
+
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ // Initializes JNI
+ jint lResult;
+ jint lFlags = 0;
+
+ JavaVM* lJavaVM = states->activity->vm;
+ JNIEnv* lJNIEnv = states->activity->env;
+
+ JavaVMAttachArgs lJavaVMAttachArgs;
+ lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+ lJavaVMAttachArgs.name = "NativeThread";
+ lJavaVMAttachArgs.group = NULL;
+
+ lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+
+ if (lResult == JNI_ERR)
+ err() << "Failed to initialize JNI, couldn't switch the keyboard visibility" << std::endl;
+
+ // Retrieves NativeActivity
+ jobject lNativeActivity = states->activity->clazz;
+ jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+ // Retrieves Context.INPUT_METHOD_SERVICE
+ jclass ClassContext = lJNIEnv->FindClass("android/content/Context");
+ jfieldID FieldINPUT_METHOD_SERVICE = lJNIEnv->GetStaticFieldID(ClassContext,
+ "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
+ jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext,
+ FieldINPUT_METHOD_SERVICE);
+ lJNIEnv->DeleteLocalRef(ClassContext);
+
+ // Runs getSystemService(Context.INPUT_METHOD_SERVICE)
+ jclass ClassInputMethodManager =
+ lJNIEnv->FindClass("android/view/inputmethod/InputMethodManager");
+ jmethodID MethodGetSystemService = lJNIEnv->GetMethodID(ClassNativeActivity,
+ "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+ jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity,
+ MethodGetSystemService, INPUT_METHOD_SERVICE);
+ lJNIEnv->DeleteLocalRef(INPUT_METHOD_SERVICE);
+
+ // Runs getWindow().getDecorView()
+ jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity,
+ "getWindow", "()Landroid/view/Window;");
+ jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity, MethodGetWindow);
+ jclass ClassWindow = lJNIEnv->FindClass("android/view/Window");
+ jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow,
+ "getDecorView", "()Landroid/view/View;");
+ jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView);
+ lJNIEnv->DeleteLocalRef(lWindow);
+ lJNIEnv->DeleteLocalRef(ClassWindow);
+
+ if (visible)
+ {
+ // Runs lInputMethodManager.showSoftInput(...)
+ jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager,
+ "showSoftInput", "(Landroid/view/View;I)Z");
+ jboolean lResult = lJNIEnv->CallBooleanMethod(lInputMethodManager,
+ MethodShowSoftInput, lDecorView, lFlags);
+ }
+ else
+ {
+ // Runs lWindow.getViewToken()
+ jclass ClassView = lJNIEnv->FindClass("android/view/View");
+ jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID(ClassView,
+ "getWindowToken", "()Landroid/os/IBinder;");
+ jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
+ MethodGetWindowToken);
+ lJNIEnv->DeleteLocalRef(ClassView);
+
+ // lInputMethodManager.hideSoftInput(...)
+ jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager,
+ "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
+ jboolean lRes = lJNIEnv->CallBooleanMethod(lInputMethodManager,
+ MethodHideSoftInput, lBinder, lFlags);
+ lJNIEnv->DeleteLocalRef(lBinder);
+ }
+ lJNIEnv->DeleteLocalRef(ClassNativeActivity);
+ lJNIEnv->DeleteLocalRef(ClassInputMethodManager);
+ lJNIEnv->DeleteLocalRef(lDecorView);
+
+ // Finished with the JVM
+ lJavaVM->DetachCurrentThread();
+}
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ priv::ActivityStates* states = priv::getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return states->isButtonPressed[button];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ priv::ActivityStates* states = priv::getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return states->mousePosition;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ return getMousePosition();
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ // Injecting events is impossible on Android
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ setMousePosition(position);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int finger)
+{
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ priv::ActivityStates* states = priv::getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return states->touchEvents.find(finger) != states->touchEvents.end();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger)
+{
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ priv::ActivityStates* states = priv::getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return states->touchEvents.find(finger)->second;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger, const Window& relativeTo)
+{
+ return getTouchPosition(finger);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Android/InputImpl.hpp b/src/SFML/Window/Android/InputImpl.hpp
new file mode 100644
index 0000000..37167b5
--- /dev/null
+++ b/src/SFML/Window/Android/InputImpl.hpp
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_INPUTIMPLANDROID_HPP
+#define SFML_INPUTIMPLANDROID_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(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.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 isTouchDown(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 getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLANDROID_HPP
diff --git a/src/SFML/Window/Android/JoystickImpl.cpp b/src/SFML/Window/Android/JoystickImpl.cpp
new file mode 100644
index 0000000..58dfc82
--- /dev/null
+++ b/src/SFML/Window/Android/JoystickImpl.cpp
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // To implement
+}
+
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // To implement
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ // To implement
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ // To implement
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ // To implement
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ // To implement
+ return JoystickCaps();
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::update()
+{
+ // To implement
+ return JoystickState();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Android/JoystickImpl.hpp b/src/SFML/Window/Android/JoystickImpl.hpp
new file mode 100644
index 0000000..2fb8cd3
--- /dev/null
+++ b/src/SFML/Window/Android/JoystickImpl.hpp
@@ -0,0 +1,117 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_JOYSTICKIMPLANDROID_HPP
+#define SFML_JOYSTICKIMPLANDROID_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Android implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ int m_index; ///< Index of the joystick
+ Joystick::Identification m_identification; ///< Joystick identification
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLANDROID_HPP
diff --git a/src/SFML/Window/Android/SensorImpl.cpp b/src/SFML/Window/Android/SensorImpl.cpp
new file mode 100644
index 0000000..3a018b5
--- /dev/null
+++ b/src/SFML/Window/Android/SensorImpl.cpp
@@ -0,0 +1,214 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+#include <SFML/System/Time.hpp>
+#include <android/looper.h>
+
+// Define missing constants
+#define ASENSOR_TYPE_GRAVITY 0x00000009
+#define ASENSOR_TYPE_LINEAR_ACCELERATION 0x0000000a
+#define ASENSOR_TYPE_ORIENTATION 0x00000003
+
+namespace
+{
+ ALooper* looper;
+ ASensorManager* sensorManager;
+ ASensorEventQueue* sensorEventQueue;
+ sf::Vector3f sensorData[sf::Sensor::Count];
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // Get the looper associated with this thread
+ looper = ALooper_forThread();
+
+ // Get the unique sensor manager
+ sensorManager = ASensorManager_getInstance();
+
+ // Create the sensor events queue and attach it to the looper
+ sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper,
+ 1, &processSensorEvents, NULL);
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // Detach the sensor events queue from the looper and destroy it
+ ASensorManager_destroyEventQueue(sensorManager, sensorEventQueue);
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type sensor)
+{
+ const ASensor* available = getDefaultSensor(sensor);
+
+ return available? true : false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type sensor)
+{
+ // Get the default sensor matching the type
+ m_sensor = getDefaultSensor(sensor);
+
+ // Sensor not available, stop here
+ if (!m_sensor)
+ return false;
+
+ // Get the minimum delay allowed between events
+ Time minimumDelay = microseconds(ASensor_getMinDelay(m_sensor));
+
+ // Set the event rate (not to consume too much battery)
+ ASensorEventQueue_setEventRate(sensorEventQueue, m_sensor, minimumDelay.asMicroseconds());
+
+ // Save the index of the sensor
+ m_index = static_cast<unsigned int>(sensor);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ // Update our sensor data list
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ return sensorData[m_index];
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool enabled)
+{
+ if (enabled)
+ ASensorEventQueue_enableSensor(sensorEventQueue, m_sensor);
+ else
+ ASensorEventQueue_disableSensor(sensorEventQueue, m_sensor);
+}
+
+
+////////////////////////////////////////////////////////////
+ASensor const* SensorImpl::getDefaultSensor(Sensor::Type sensor)
+{
+ // Find the Android sensor type
+ static int types[] = {ASENSOR_TYPE_ACCELEROMETER, ASENSOR_TYPE_GYROSCOPE,
+ ASENSOR_TYPE_MAGNETIC_FIELD, ASENSOR_TYPE_GRAVITY, ASENSOR_TYPE_LINEAR_ACCELERATION,
+ ASENSOR_TYPE_ORIENTATION};
+
+ int type = types[sensor];
+
+ // Retrieve the default sensor matching this type
+ return ASensorManager_getDefaultSensor(sensorManager, type);
+}
+
+
+////////////////////////////////////////////////////////////
+int SensorImpl::processSensorEvents(int fd, int events, void* data)
+{
+ ASensorEvent event;
+
+ while (ASensorEventQueue_getEvents(sensorEventQueue, &event, 1) > 0)
+ {
+ unsigned int type = Sensor::Count;
+ Vector3f data;
+
+ switch (event.type)
+ {
+ case ASENSOR_TYPE_ACCELEROMETER:
+ type = Sensor::Accelerometer;
+ data.x = event.acceleration.x;
+ data.y = event.acceleration.y;
+ data.z = event.acceleration.z;
+ break;
+
+ case ASENSOR_TYPE_GYROSCOPE:
+ type = Sensor::Gyroscope;
+ data.x = event.vector.x;
+ data.y = event.vector.y;
+ data.z = event.vector.z;
+ break;
+
+ case ASENSOR_TYPE_MAGNETIC_FIELD:
+ type = Sensor::Magnetometer;
+ data.x = event.magnetic.x;
+ data.y = event.magnetic.y;
+ data.z = event.magnetic.z;
+ break;
+
+ case ASENSOR_TYPE_GRAVITY:
+ type = Sensor::Gravity;
+ data.x = event.vector.x;
+ data.y = event.vector.y;
+ data.z = event.vector.z;
+ break;
+
+ case ASENSOR_TYPE_LINEAR_ACCELERATION:
+ type = Sensor::UserAcceleration;
+ data.x = event.acceleration.x;
+ data.y = event.acceleration.y;
+ data.z = event.acceleration.z;
+ break;
+
+ case ASENSOR_TYPE_ORIENTATION:
+ type = Sensor::Orientation;
+ data.x = event.vector.x;
+ data.y = event.vector.y;
+ data.z = event.vector.z;
+ break;
+ }
+
+ // An unknown sensor event has been detected, we don't know how to process it
+ if (type == Sensor::Count)
+ continue;
+
+ sensorData[type] = data;
+ }
+
+ return 1;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Android/SensorImpl.hpp b/src/SFML/Window/Android/SensorImpl.hpp
new file mode 100644
index 0000000..4ce19a4
--- /dev/null
+++ b/src/SFML/Window/Android/SensorImpl.hpp
@@ -0,0 +1,137 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPLANDROID_HPP
+#define SFML_SENSORIMPLANDROID_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Vector3.hpp>
+#include <android/sensor.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Android implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the default Android sensor matching the sensor type
+ ///
+ /// \param type Type of the sensor
+ ///
+ /// \return The default Android sensor, NULL otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static ASensor const* getDefaultSensor(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process the pending sensor data available and add them to our lists
+ ///
+ /// \param fd File descriptor
+ /// \param events Bitmask of the poll events that were triggered
+ /// \param data Data pointer supplied
+ ///
+ /// \return Whether it should continue (1) or unregister the callback (0)
+ ///
+ ////////////////////////////////////////////////////////////
+ static int processSensorEvents(int fd, int events, void* data);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ const ASensor* m_sensor; ///< Android sensor structure
+ unsigned int m_index; ///< Index of the sensor
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLANDROID_HPP
diff --git a/src/SFML/Window/Android/VideoModeImpl.cpp b/src/SFML/Window/Android/VideoModeImpl.cpp
new file mode 100644
index 0000000..d9c171c
--- /dev/null
+++ b/src/SFML/Window/Android/VideoModeImpl.cpp
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <SFML/System/Android/Activity.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Lock.hpp>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ VideoMode desktop = getDesktopMode();
+
+ // Return both portrait and landscape resolutions
+ std::vector<VideoMode> modes;
+ modes.push_back(desktop);
+ modes.push_back(VideoMode(desktop.height, desktop.width, desktop.bitsPerPixel));
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ // Get the activity states
+ priv::ActivityStates* states = priv::getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return VideoMode(states->screenSize.x, states->screenSize.y);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp
new file mode 100644
index 0000000..40992a0
--- /dev/null
+++ b/src/SFML/Window/Android/WindowImplAndroid.cpp
@@ -0,0 +1,727 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
+#include <SFML/Window/Android/WindowImplAndroid.hpp>
+#include <SFML/Window/Event.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <android/looper.h>
+
+// Define missing constants for older API levels
+#if __ANDROID_API__ < 13
+ #define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
+ #define AMOTION_EVENT_ACTION_SCROLL 0x00000008
+#endif
+
+////////////////////////////////////////////////////////////
+// Private data
+////////////////////////////////////////////////////////////
+namespace sf
+{
+namespace priv
+{
+WindowImplAndroid* WindowImplAndroid::singleInstance = NULL;
+
+////////////////////////////////////////////////////////////
+WindowImplAndroid::WindowImplAndroid(WindowHandle handle)
+: m_size(0, 0)
+, m_windowBeingCreated(false)
+, m_windowBeingDestroyed(false)
+, m_hasFocus(false)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplAndroid::WindowImplAndroid(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings)
+: m_size(mode.width, mode.height)
+, m_windowBeingCreated(false)
+, m_windowBeingDestroyed(false)
+, m_hasFocus(false)
+{
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ if (style& Style::Fullscreen)
+ states->fullscreen = true;
+
+ WindowImplAndroid::singleInstance = this;
+ states->forwardEvent = forwardEvent;
+
+ // Register process event callback
+ states->processEvent = processEvent;
+
+ states->initialized = true;
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplAndroid::~WindowImplAndroid()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplAndroid::getSystemHandle() const
+{
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ return states->window;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::processEvents()
+{
+ // Process incoming OS events
+ ALooper_pollAll(0, NULL, NULL, NULL);
+
+ ActivityStates* states = getActivity(NULL);
+ sf::Lock lock(states->mutex);
+
+ if (m_windowBeingCreated)
+ {
+ states->context->createSurface(states->window);
+ m_windowBeingCreated = false;
+ }
+
+ if (m_windowBeingDestroyed)
+ {
+ states->context->destroySurface();
+ m_windowBeingDestroyed = false;
+ }
+
+ states->updated = true;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplAndroid::getPosition() const
+{
+ // Not applicable
+ return Vector2i(0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setPosition(const Vector2i& position)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplAndroid::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setSize(const Vector2u& size)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setTitle(const String& title)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setMouseCursorVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setMouseCursorGrabbed(bool grabbed)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setMouseCursor(const CursorImpl& cursor)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::setKeyRepeatEnabled(bool enabled)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::requestFocus()
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplAndroid::hasFocus() const
+{
+ return m_hasFocus;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplAndroid::forwardEvent(const Event& event)
+{
+ ActivityStates* states = getActivity(NULL);
+
+ if (event.type == Event::GainedFocus)
+ {
+ WindowImplAndroid::singleInstance->m_size.x = ANativeWindow_getWidth(states->window);
+ WindowImplAndroid::singleInstance->m_size.y = ANativeWindow_getHeight(states->window);
+ WindowImplAndroid::singleInstance->m_windowBeingCreated = true;
+ WindowImplAndroid::singleInstance->m_hasFocus = true;
+ }
+ else if (event.type == Event::LostFocus)
+ {
+ WindowImplAndroid::singleInstance->m_windowBeingDestroyed = true;
+ WindowImplAndroid::singleInstance->m_hasFocus = false;
+ }
+
+ WindowImplAndroid::singleInstance->pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::processEvent(int fd, int events, void* data)
+{
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ AInputEvent* _event = NULL;
+
+ if (AInputQueue_getEvent(states->inputQueue, &_event) >= 0)
+ {
+ if (AInputQueue_preDispatchEvent(states->inputQueue, _event))
+ return 1;
+
+ int handled = 0;
+
+ int32_t type = AInputEvent_getType(_event);
+
+ if (type == AINPUT_EVENT_TYPE_KEY)
+ {
+ int32_t action = AKeyEvent_getAction(_event);
+ int32_t key = AKeyEvent_getKeyCode(_event);
+
+ if ((action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_UP || action == AKEY_EVENT_ACTION_MULTIPLE) &&
+ key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN)
+ {
+ handled = processKeyEvent(_event, states);
+ }
+ }
+ else if (type == AINPUT_EVENT_TYPE_MOTION)
+ {
+ int32_t action = AMotionEvent_getAction(_event);
+
+ switch (action & AMOTION_EVENT_ACTION_MASK)
+ {
+ case AMOTION_EVENT_ACTION_SCROLL:
+ {
+ handled = processScrollEvent(_event, states);
+ break;
+ }
+
+ // todo: should hover_move indeed trigger the event?
+ // case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_MOVE:
+ {
+ handled = processMotionEvent(_event, states);
+ break;
+ }
+
+ // todo: investigate AMOTION_EVENT_OUTSIDE
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_DOWN:
+ {
+ handled = processPointerEvent(true, _event, states);
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_CANCEL:
+ {
+ handled = processPointerEvent(false, _event, states);
+ break;
+ }
+ }
+
+ }
+
+ AInputQueue_finishEvent(states->inputQueue, _event, handled);
+ }
+
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states)
+{
+ // Prepare the Java virtual machine
+ jint lResult;
+ jint lFlags = 0;
+
+ JavaVM* lJavaVM = states->activity->vm;
+ JNIEnv* lJNIEnv = states->activity->env;
+
+ JavaVMAttachArgs lJavaVMAttachArgs;
+ lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+ lJavaVMAttachArgs.name = "NativeThread";
+ lJavaVMAttachArgs.group = NULL;
+
+ lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+
+ if (lResult == JNI_ERR) {
+ err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl;
+ return 0;
+ }
+
+ // Retrieve everything we need to create this MotionEvent in Java
+ jlong downTime = AMotionEvent_getDownTime(_event);
+ jlong eventTime = AMotionEvent_getEventTime(_event);
+ jint action = AMotionEvent_getAction(_event);
+ jfloat x = AMotionEvent_getX(_event, 0);
+ jfloat y = AMotionEvent_getY(_event, 0);
+ jfloat pressure = AMotionEvent_getPressure(_event, 0);
+ jfloat size = AMotionEvent_getSize(_event, 0);
+ jint metaState = AMotionEvent_getMetaState(_event);
+ jfloat xPrecision = AMotionEvent_getXPrecision(_event);
+ jfloat yPrecision = AMotionEvent_getYPrecision(_event);
+ jint deviceId = AInputEvent_getDeviceId(_event);
+ jint edgeFlags = AMotionEvent_getEdgeFlags(_event);
+
+ // Create the MotionEvent object in Java trough its static constructor obtain()
+ jclass ClassMotionEvent = lJNIEnv->FindClass("android/view/MotionEvent");
+ jmethodID StaticMethodObtain = lJNIEnv->GetStaticMethodID(ClassMotionEvent, "obtain", "(JJIFFFFIFFII)Landroid/view/MotionEvent;");
+ jobject ObjectMotionEvent = lJNIEnv->CallStaticObjectMethod(ClassMotionEvent, StaticMethodObtain, downTime, eventTime, action, x, y, pressure, size, metaState, xPrecision, yPrecision, deviceId, edgeFlags);
+
+ // Call its getAxisValue() method to get the delta value of our wheel move event
+ jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F");
+ jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001);
+
+ lJNIEnv->DeleteLocalRef(ClassMotionEvent);
+ lJNIEnv->DeleteLocalRef(ObjectMotionEvent);
+
+ // Create and send our mouse wheel event
+ Event event;
+ event.type = Event::MouseWheelMoved;
+ event.mouseWheel.delta = static_cast<double>(delta);
+ event.mouseWheel.x = AMotionEvent_getX(_event, 0);
+ event.mouseWheel.y = AMotionEvent_getY(_event, 0);
+
+ forwardEvent(event);
+
+ // Detach this thread from the JVM
+ lJavaVM->DetachCurrentThread();
+
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states)
+{
+ int32_t device = AInputEvent_getSource(_event);
+ int32_t action = AKeyEvent_getAction(_event);
+
+ int32_t key = AKeyEvent_getKeyCode(_event);
+ int32_t metakey = AKeyEvent_getMetaState(_event);
+
+ Event event;
+ event.key.code = androidKeyToSF(key);
+ event.key.alt = metakey & AMETA_ALT_ON;
+ event.key.control = false;
+ event.key.shift = metakey & AMETA_SHIFT_ON;
+
+ switch (action)
+ {
+ case AKEY_EVENT_ACTION_DOWN:
+ event.type = Event::KeyPressed;
+ forwardEvent(event);
+ return 1;
+ case AKEY_EVENT_ACTION_UP:
+ event.type = Event::KeyReleased;
+ forwardEvent(event);
+
+ if (int unicode = getUnicode(_event))
+ {
+ event.type = Event::TextEntered;
+ event.text.unicode = unicode;
+ forwardEvent(event);
+ }
+ return 1;
+ case AKEY_EVENT_ACTION_MULTIPLE:
+ // Since complex inputs don't get separate key down/up events
+ // both have to be faked at once
+ event.type = Event::KeyPressed;
+ forwardEvent(event);
+ event.type = Event::KeyReleased;
+ forwardEvent(event);
+
+ // This requires some special treatment, since this might represent
+ // a repetition of key presses or a complete sequence
+ if (key == AKEYCODE_UNKNOWN)
+ {
+ // This is a unique sequence, which is not yet exposed in the NDK
+ // https://code.google.com/p/android/issues/detail?id=33998
+ return 0;
+ }
+ else if (int unicode = getUnicode(_event)) // This is a repeated sequence
+ {
+ event.type = Event::TextEntered;
+ event.text.unicode = unicode;
+
+ int32_t repeats = AKeyEvent_getRepeatCount(_event);
+ for (int32_t i = 0; i < repeats; ++i)
+ forwardEvent(event);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states)
+{
+ int32_t device = AInputEvent_getSource(_event);
+ int32_t action = AMotionEvent_getAction(_event);
+
+ Event event;
+
+ if (device == AINPUT_SOURCE_MOUSE)
+ event.type = Event::MouseMoved;
+ else if (device & AINPUT_SOURCE_TOUCHSCREEN)
+ event.type = Event::TouchMoved;
+
+ int pointerCount = AMotionEvent_getPointerCount(_event);
+
+ for (int p = 0; p < pointerCount; p++)
+ {
+ int id = AMotionEvent_getPointerId(_event, p);
+
+ float x = AMotionEvent_getX(_event, p);
+ float y = AMotionEvent_getY(_event, p);
+
+ if (device == AINPUT_SOURCE_MOUSE)
+ {
+ event.mouseMove.x = x;
+ event.mouseMove.y = y;
+
+ states->mousePosition = Vector2i(event.mouseMove.x, event.mouseMove.y);
+ }
+ else if (device & AINPUT_SOURCE_TOUCHSCREEN)
+ {
+ if (states->touchEvents[id].x == x && states->touchEvents[id].y == y)
+ continue;
+
+ event.touch.finger = id;
+ event.touch.x = x;
+ event.touch.y = y;
+
+ states->touchEvents[id] = Vector2i(event.touch.x, event.touch.y);
+ }
+
+ forwardEvent(event);
+ }
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states)
+{
+ int32_t device = AInputEvent_getSource(_event);
+ int32_t action = AMotionEvent_getAction(_event);
+
+ int index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ int id = AMotionEvent_getPointerId(_event, index);
+
+ float x = AMotionEvent_getX(_event, index);
+ float y = AMotionEvent_getY(_event, index);
+
+ Event event;
+
+ if (isDown)
+ {
+ if (device == AINPUT_SOURCE_MOUSE)
+ {
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = static_cast<Mouse::Button>(id);
+ event.mouseButton.x = x;
+ event.mouseButton.y = y;
+
+ if (id >= 0 && id < Mouse::ButtonCount)
+ states->isButtonPressed[id] = true;
+ }
+ else if (device & AINPUT_SOURCE_TOUCHSCREEN)
+ {
+ event.type = Event::TouchBegan;
+ event.touch.finger = id;
+ event.touch.x = x;
+ event.touch.y = y;
+
+ states->touchEvents[id] = Vector2i(event.touch.x, event.touch.y);
+ }
+ }
+ else
+ {
+ if (device == AINPUT_SOURCE_MOUSE)
+ {
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = static_cast<Mouse::Button>(id);
+ event.mouseButton.x = x;
+ event.mouseButton.y = y;
+
+ if (id >= 0 && id < Mouse::ButtonCount)
+ states->isButtonPressed[id] = false;
+ }
+ else if (device & AINPUT_SOURCE_TOUCHSCREEN)
+ {
+ event.type = Event::TouchEnded;
+ event.touch.finger = id;
+ event.touch.x = x;
+ event.touch.y = y;
+
+ states->touchEvents.erase(id);
+ }
+ }
+
+ forwardEvent(event);
+ return 1;
+}
+
+
+////////////////////////////////////////////////////////////
+Keyboard::Key WindowImplAndroid::androidKeyToSF(int32_t key)
+{
+ switch (key)
+ {
+ case AKEYCODE_UNKNOWN:
+ case AKEYCODE_SOFT_LEFT:
+ case AKEYCODE_SOFT_RIGHT:
+ case AKEYCODE_HOME: return Keyboard::Unknown;
+ case AKEYCODE_BACK: return Keyboard::Escape;
+ case AKEYCODE_CALL:
+ case AKEYCODE_ENDCALL: return Keyboard::Unknown;
+ case AKEYCODE_0: return Keyboard::Num0;
+ case AKEYCODE_1: return Keyboard::Num1;
+ case AKEYCODE_2: return Keyboard::Num2;
+ case AKEYCODE_3: return Keyboard::Num3;
+ case AKEYCODE_4: return Keyboard::Num4;
+ case AKEYCODE_5: return Keyboard::Num5;
+ case AKEYCODE_6: return Keyboard::Num6;
+ case AKEYCODE_7: return Keyboard::Num7;
+ case AKEYCODE_8: return Keyboard::Num8;
+ case AKEYCODE_9: return Keyboard::Num9;
+ case AKEYCODE_STAR:
+ case AKEYCODE_POUND:
+ case AKEYCODE_DPAD_UP:
+ case AKEYCODE_DPAD_DOWN:
+ case AKEYCODE_DPAD_LEFT:
+ case AKEYCODE_DPAD_RIGHT:
+ case AKEYCODE_DPAD_CENTER:
+ case AKEYCODE_VOLUME_UP:
+ case AKEYCODE_VOLUME_DOWN:
+ case AKEYCODE_POWER:
+ case AKEYCODE_CAMERA:
+ case AKEYCODE_CLEAR: return Keyboard::Unknown;
+ case AKEYCODE_A: return Keyboard::A;
+ case AKEYCODE_B: return Keyboard::B;
+ case AKEYCODE_C: return Keyboard::C;
+ case AKEYCODE_D: return Keyboard::D;
+ case AKEYCODE_E: return Keyboard::E;
+ case AKEYCODE_F: return Keyboard::F;
+ case AKEYCODE_G: return Keyboard::G;
+ case AKEYCODE_H: return Keyboard::H;
+ case AKEYCODE_I: return Keyboard::I;
+ case AKEYCODE_J: return Keyboard::J;
+ case AKEYCODE_K: return Keyboard::K;
+ case AKEYCODE_L: return Keyboard::L;
+ case AKEYCODE_M: return Keyboard::M;
+ case AKEYCODE_N: return Keyboard::N;
+ case AKEYCODE_O: return Keyboard::O;
+ case AKEYCODE_P: return Keyboard::P;
+ case AKEYCODE_Q: return Keyboard::Q;
+ case AKEYCODE_R: return Keyboard::R;
+ case AKEYCODE_S: return Keyboard::S;
+ case AKEYCODE_T: return Keyboard::T;
+ case AKEYCODE_U: return Keyboard::U;
+ case AKEYCODE_V: return Keyboard::V;
+ case AKEYCODE_W: return Keyboard::W;
+ case AKEYCODE_X: return Keyboard::X;
+ case AKEYCODE_Y: return Keyboard::Y;
+ case AKEYCODE_Z: return Keyboard::Z;
+ case AKEYCODE_COMMA: return Keyboard::Comma;
+ case AKEYCODE_PERIOD: return Keyboard::Period;
+ case AKEYCODE_ALT_LEFT: return Keyboard::LAlt;
+ case AKEYCODE_ALT_RIGHT: return Keyboard::RAlt;
+ case AKEYCODE_SHIFT_LEFT: return Keyboard::LShift;
+ case AKEYCODE_SHIFT_RIGHT: return Keyboard::RShift;
+ case AKEYCODE_TAB: return Keyboard::Tab;
+ case AKEYCODE_SPACE: return Keyboard::Space;
+ case AKEYCODE_SYM:
+ case AKEYCODE_EXPLORER:
+ case AKEYCODE_ENVELOPE: return Keyboard::Unknown;
+ case AKEYCODE_ENTER: return Keyboard::Enter;
+ case AKEYCODE_DEL: return Keyboard::Backspace;
+ case AKEYCODE_FORWARD_DEL: return Keyboard::Delete;
+ case AKEYCODE_GRAVE: return Keyboard::Tilde;
+ case AKEYCODE_MINUS: return Keyboard::Subtract;
+ case AKEYCODE_EQUALS: return Keyboard::Equal;
+ case AKEYCODE_LEFT_BRACKET: return Keyboard::LBracket;
+ case AKEYCODE_RIGHT_BRACKET: return Keyboard::RBracket;
+ case AKEYCODE_BACKSLASH: return Keyboard::Backslash;
+ case AKEYCODE_SEMICOLON: return Keyboard::Semicolon;
+ case AKEYCODE_APOSTROPHE: return Keyboard::Quote;
+ case AKEYCODE_SLASH: return Keyboard::Slash;
+ case AKEYCODE_AT:
+ case AKEYCODE_NUM:
+ case AKEYCODE_HEADSETHOOK:
+ case AKEYCODE_FOCUS: // *Camera* focus
+ case AKEYCODE_PLUS:
+ case AKEYCODE_MENU:
+ case AKEYCODE_NOTIFICATION:
+ case AKEYCODE_SEARCH:
+ case AKEYCODE_MEDIA_PLAY_PAUSE:
+ case AKEYCODE_MEDIA_STOP:
+ case AKEYCODE_MEDIA_NEXT:
+ case AKEYCODE_MEDIA_PREVIOUS:
+ case AKEYCODE_MEDIA_REWIND:
+ case AKEYCODE_MEDIA_FAST_FORWARD:
+ case AKEYCODE_MUTE: return Keyboard::Unknown;
+ case AKEYCODE_PAGE_UP: return Keyboard::PageUp;
+ case AKEYCODE_PAGE_DOWN: return Keyboard::PageDown;
+ case AKEYCODE_PICTSYMBOLS:
+ case AKEYCODE_SWITCH_CHARSET:
+ case AKEYCODE_BUTTON_A:
+ case AKEYCODE_BUTTON_B:
+ case AKEYCODE_BUTTON_C:
+ case AKEYCODE_BUTTON_X:
+ case AKEYCODE_BUTTON_Y:
+ case AKEYCODE_BUTTON_Z:
+ case AKEYCODE_BUTTON_L1:
+ case AKEYCODE_BUTTON_R1:
+ case AKEYCODE_BUTTON_L2:
+ case AKEYCODE_BUTTON_R2:
+ case AKEYCODE_BUTTON_THUMBL:
+ case AKEYCODE_BUTTON_THUMBR:
+ case AKEYCODE_BUTTON_START:
+ case AKEYCODE_BUTTON_SELECT:
+ case AKEYCODE_BUTTON_MODE: return Keyboard::Unknown;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+int WindowImplAndroid::getUnicode(AInputEvent* event)
+{
+ // Retrieve activity states
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ // Initializes JNI
+ jint lResult;
+ jint lFlags = 0;
+
+ JavaVM* lJavaVM = states->activity->vm;
+ JNIEnv* lJNIEnv = states->activity->env;
+
+ JavaVMAttachArgs lJavaVMAttachArgs;
+ lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+ lJavaVMAttachArgs.name = "NativeThread";
+ lJavaVMAttachArgs.group = NULL;
+
+ lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+
+ if (lResult == JNI_ERR)
+ err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl;
+
+ // Retrieve key data from the input event
+ jlong downTime = AKeyEvent_getDownTime(event);
+ jlong eventTime = AKeyEvent_getEventTime(event);
+ jint action = AKeyEvent_getAction(event);
+ jint code = AKeyEvent_getKeyCode(event);
+ jint repeat = AKeyEvent_getRepeatCount(event); // not sure!
+ jint metaState = AKeyEvent_getMetaState(event);
+ jint deviceId = AInputEvent_getDeviceId(event);
+ jint scancode = AKeyEvent_getScanCode(event);
+ jint flags = AKeyEvent_getFlags(event);
+ jint source = AInputEvent_getSource(event);
+
+ // Construct a KeyEvent object from the event data
+ jclass ClassKeyEvent = lJNIEnv->FindClass("android/view/KeyEvent");
+ jmethodID KeyEventConstructor = lJNIEnv->GetMethodID(ClassKeyEvent, "<init>", "(JJIIIIIIII)V");
+ jobject ObjectKeyEvent = lJNIEnv->NewObject(ClassKeyEvent, KeyEventConstructor, downTime, eventTime, action, code, repeat, metaState, deviceId, scancode, flags, source);
+
+ // Call its getUnicodeChar() method to get the Unicode value
+ jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I");
+ int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState);
+
+ lJNIEnv->DeleteLocalRef(ClassKeyEvent);
+ lJNIEnv->DeleteLocalRef(ObjectKeyEvent);
+
+ // Detach this thread from the JVM
+ lJavaVM->DetachCurrentThread();
+
+ return unicode;
+}
+
+} // namespace priv
+} // namespace sf
diff --git a/src/SFML/Window/Android/WindowImplAndroid.hpp b/src/SFML/Window/Android/WindowImplAndroid.hpp
new file mode 100644
index 0000000..7636144
--- /dev/null
+++ b/src/SFML/Window/Android/WindowImplAndroid.hpp
@@ -0,0 +1,249 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_WINDOWIMPLANDROID_HPP
+#define SFML_WINDOWIMPLANDROID_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/Window/EglContext.hpp>
+#include <SFML/System/Android/Activity.hpp>
+#include <android/input.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Android implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplAndroid : public WindowImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplAndroid(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style (resizable, fixed, or fullscren)
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplAndroid(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplAndroid();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clips or releases the mouse cursor
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+ static void forwardEvent(const Event& event);
+ static WindowImplAndroid* singleInstance;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process messages from the looper associated with the main thread
+ ///
+ /// \param fd File descriptor
+ /// \param events Bitmask of the poll events that were triggered
+ /// \param data Data pointer supplied
+ ///
+ /// \return Whether it should continue (1) or unregister the callback (0)
+ ///
+ ////////////////////////////////////////////////////////////
+ static int processEvent(int fd, int events, void* data);
+
+ static int processScrollEvent(AInputEvent* _event, ActivityStates* states);
+ static int processKeyEvent(AInputEvent* _event, ActivityStates* states);
+ static int processMotionEvent(AInputEvent* _event, ActivityStates* states);
+ static int processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a Android key to SFML key code
+ ///
+ /// \param symbol Android key to convert
+ ///
+ /// \return Corresponding SFML key code
+ ///
+ ////////////////////////////////////////////////////////////
+ static Keyboard::Key androidKeyToSF(int32_t key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get Unicode decoded from the input event
+ ///
+ /// \param Event Input event
+ ///
+ /// \return The Unicode value
+ ///
+ ////////////////////////////////////////////////////////////
+ static int getUnicode(AInputEvent* event);
+
+ Vector2u m_size;
+ bool m_windowBeingCreated;
+ bool m_windowBeingDestroyed;
+ bool m_hasFocus;
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPLANDROID_HPP
diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt
new file mode 100644
index 0000000..98ea439
--- /dev/null
+++ b/src/SFML/Window/CMakeLists.txt
@@ -0,0 +1,288 @@
+
+set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Window)
+set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Window)
+
+# all source files
+set(SRC
+ ${INCROOT}/Clipboard.hpp
+ ${SRCROOT}/Clipboard.cpp
+ ${SRCROOT}/ClipboardImpl.hpp
+ ${SRCROOT}/Context.cpp
+ ${INCROOT}/Context.hpp
+ ${SRCROOT}/Cursor.cpp
+ ${INCROOT}/Cursor.hpp
+ ${SRCROOT}/CursorImpl.hpp
+ ${INCROOT}/Export.hpp
+ ${SRCROOT}/GlContext.cpp
+ ${SRCROOT}/GlContext.hpp
+ ${SRCROOT}/GlResource.cpp
+ ${INCROOT}/GlResource.hpp
+ ${INCROOT}/ContextSettings.hpp
+ ${INCROOT}/Event.hpp
+ ${SRCROOT}/InputImpl.hpp
+ ${INCROOT}/Joystick.hpp
+ ${SRCROOT}/Joystick.cpp
+ ${SRCROOT}/JoystickImpl.hpp
+ ${SRCROOT}/JoystickManager.cpp
+ ${SRCROOT}/JoystickManager.hpp
+ ${INCROOT}/Keyboard.hpp
+ ${SRCROOT}/Keyboard.cpp
+ ${INCROOT}/Mouse.hpp
+ ${SRCROOT}/Mouse.cpp
+ ${INCROOT}/Touch.hpp
+ ${SRCROOT}/Touch.cpp
+ ${INCROOT}/Sensor.hpp
+ ${SRCROOT}/Sensor.cpp
+ ${SRCROOT}/SensorImpl.hpp
+ ${SRCROOT}/SensorManager.cpp
+ ${SRCROOT}/SensorManager.hpp
+ ${SRCROOT}/VideoMode.cpp
+ ${INCROOT}/VideoMode.hpp
+ ${SRCROOT}/VideoModeImpl.hpp
+ ${SRCROOT}/Window.cpp
+ ${INCROOT}/Window.hpp
+ ${INCROOT}/WindowHandle.hpp
+ ${SRCROOT}/WindowImpl.cpp
+ ${SRCROOT}/WindowImpl.hpp
+ ${INCROOT}/WindowStyle.hpp
+)
+if(SFML_OPENGL_ES AND NOT SFML_OS_IOS)
+ list(APPEND SRC ${SRCROOT}/EGLCheck.cpp)
+ list(APPEND SRC ${SRCROOT}/EGLCheck.hpp)
+ list(APPEND SRC ${SRCROOT}/EglContext.cpp)
+ list(APPEND SRC ${SRCROOT}/EglContext.hpp)
+endif()
+source_group("" FILES ${SRC})
+
+# add platform specific sources
+if(SFML_OS_WINDOWS)
+ set(PLATFORM_SRC
+ ${SRCROOT}/Win32/CursorImpl.hpp
+ ${SRCROOT}/Win32/CursorImpl.cpp
+ ${SRCROOT}/Win32/ClipboardImpl.hpp
+ ${SRCROOT}/Win32/ClipboardImpl.cpp
+ ${SRCROOT}/Win32/WglContext.cpp
+ ${SRCROOT}/Win32/WglContext.hpp
+ ${SRCROOT}/Win32/WglExtensions.cpp
+ ${SRCROOT}/Win32/WglExtensions.hpp
+ ${SRCROOT}/Win32/InputImpl.cpp
+ ${SRCROOT}/Win32/InputImpl.hpp
+ ${SRCROOT}/Win32/JoystickImpl.cpp
+ ${SRCROOT}/Win32/JoystickImpl.hpp
+ ${SRCROOT}/Win32/SensorImpl.hpp
+ ${SRCROOT}/Win32/SensorImpl.cpp
+ ${SRCROOT}/Win32/VideoModeImpl.cpp
+ ${SRCROOT}/Win32/WindowImplWin32.cpp
+ ${SRCROOT}/Win32/WindowImplWin32.hpp
+ )
+ source_group("windows" FILES ${PLATFORM_SRC})
+
+ # make sure that we use the Unicode version of the Win API functions
+ add_definitions(-DUNICODE -D_UNICODE)
+elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD)
+ set(PLATFORM_SRC
+ ${SRCROOT}/Unix/CursorImpl.hpp
+ ${SRCROOT}/Unix/CursorImpl.cpp
+ ${SRCROOT}/Unix/ClipboardImpl.hpp
+ ${SRCROOT}/Unix/ClipboardImpl.cpp
+ ${SRCROOT}/Unix/Display.cpp
+ ${SRCROOT}/Unix/Display.hpp
+ ${SRCROOT}/Unix/InputImpl.cpp
+ ${SRCROOT}/Unix/InputImpl.hpp
+ ${SRCROOT}/Unix/SensorImpl.cpp
+ ${SRCROOT}/Unix/SensorImpl.hpp
+ ${SRCROOT}/Unix/VideoModeImpl.cpp
+ ${SRCROOT}/Unix/WindowImplX11.cpp
+ ${SRCROOT}/Unix/WindowImplX11.hpp
+ )
+ if(NOT SFML_OPENGL_ES)
+ set(PLATFORM_SRC
+ ${PLATFORM_SRC}
+ ${SRCROOT}/Unix/GlxContext.cpp
+ ${SRCROOT}/Unix/GlxContext.hpp
+ ${SRCROOT}/Unix/GlxExtensions.cpp
+ ${SRCROOT}/Unix/GlxExtensions.hpp
+ )
+ endif()
+ if(SFML_OS_LINUX)
+ set(PLATFORM_SRC
+ ${PLATFORM_SRC}
+ ${SRCROOT}/Unix/JoystickImpl.cpp
+ ${SRCROOT}/Unix/JoystickImpl.hpp
+ )
+ elseif(SFML_OS_FREEBSD)
+ set(PLATFORM_SRC
+ ${PLATFORM_SRC}
+ ${SRCROOT}/FreeBSD/JoystickImpl.cpp
+ ${SRCROOT}/FreeBSD/JoystickImpl.hpp
+ )
+ elseif(SFML_OS_OPENBSD)
+ set(PLATFORM_SRC
+ ${PLATFORM_SRC}
+ ${SRCROOT}/OpenBSD/JoystickImpl.cpp
+ ${SRCROOT}/OpenBSD/JoystickImpl.hpp
+ )
+ endif()
+ source_group("unix" FILES ${PLATFORM_SRC})
+elseif(SFML_OS_MACOSX)
+ set(PLATFORM_SRC
+ ${SRCROOT}/OSX/cpp_objc_conversion.h
+ ${SRCROOT}/OSX/cpp_objc_conversion.mm
+ ${SRCROOT}/OSX/cg_sf_conversion.hpp
+ ${SRCROOT}/OSX/cg_sf_conversion.mm
+ ${SRCROOT}/OSX/CursorImpl.hpp
+ ${SRCROOT}/OSX/CursorImpl.mm
+ ${SRCROOT}/OSX/ClipboardImpl.hpp
+ ${SRCROOT}/OSX/ClipboardImpl.mm
+ ${SRCROOT}/OSX/InputImpl.mm
+ ${SRCROOT}/OSX/InputImpl.hpp
+ ${SRCROOT}/OSX/HIDInputManager.hpp
+ ${SRCROOT}/OSX/HIDInputManager.mm
+ ${SRCROOT}/OSX/HIDJoystickManager.hpp
+ ${SRCROOT}/OSX/HIDJoystickManager.cpp
+ ${SRCROOT}/OSX/JoystickImpl.cpp
+ ${SRCROOT}/OSX/JoystickImpl.hpp
+ ${SRCROOT}/OSX/NSImage+raw.h
+ ${SRCROOT}/OSX/NSImage+raw.mm
+ ${SRCROOT}/OSX/Scaling.h
+ ${SRCROOT}/OSX/SensorImpl.cpp
+ ${SRCROOT}/OSX/SensorImpl.hpp
+ ${SRCROOT}/OSX/SFApplication.h
+ ${SRCROOT}/OSX/SFApplication.m
+ ${SRCROOT}/OSX/SFApplicationDelegate.h
+ ${SRCROOT}/OSX/SFApplicationDelegate.m
+ ${SRCROOT}/OSX/SFContext.hpp
+ ${SRCROOT}/OSX/SFContext.mm
+ ${SRCROOT}/OSX/SFKeyboardModifiersHelper.h
+ ${SRCROOT}/OSX/SFKeyboardModifiersHelper.mm
+ ${SRCROOT}/OSX/SFOpenGLView.h
+ ${SRCROOT}/OSX/SFOpenGLView.mm
+ ${SRCROOT}/OSX/SFOpenGLView+keyboard.mm
+ ${SRCROOT}/OSX/SFOpenGLView+keyboard_priv.h
+ ${SRCROOT}/OSX/SFOpenGLView+mouse.mm
+ ${SRCROOT}/OSX/SFOpenGLView+mouse_priv.h
+ ${SRCROOT}/OSX/SFSilentResponder.h
+ ${SRCROOT}/OSX/SFSilentResponder.m
+ ${SRCROOT}/OSX/SFWindow.h
+ ${SRCROOT}/OSX/SFWindow.m
+ ${SRCROOT}/OSX/SFWindowController.h
+ ${SRCROOT}/OSX/SFWindowController.mm
+ ${SRCROOT}/OSX/SFViewController.h
+ ${SRCROOT}/OSX/SFViewController.mm
+ ${SRCROOT}/OSX/VideoModeImpl.cpp
+ ${SRCROOT}/OSX/WindowImplCocoa.hpp
+ ${SRCROOT}/OSX/WindowImplCocoa.mm
+ ${SRCROOT}/OSX/WindowImplDelegateProtocol.h
+ ${SRCROOT}/OSX/AutoreleasePoolWrapper.h
+ ${SRCROOT}/OSX/AutoreleasePoolWrapper.mm
+ )
+ source_group("mac" FILES ${PLATFORM_SRC})
+elseif(SFML_OS_IOS)
+ set(PLATFORM_SRC
+ ${SRCROOT}/iOS/CursorImpl.hpp
+ ${SRCROOT}/iOS/CursorImpl.cpp
+ ${SRCROOT}/iOS/ClipboardImpl.mm
+ ${SRCROOT}/iOS/ClipboardImpl.hpp
+ ${SRCROOT}/iOS/EaglContext.mm
+ ${SRCROOT}/iOS/EaglContext.hpp
+ ${SRCROOT}/iOS/InputImpl.mm
+ ${SRCROOT}/iOS/InputImpl.hpp
+ ${SRCROOT}/iOS/JoystickImpl.mm
+ ${SRCROOT}/iOS/JoystickImpl.hpp
+ ${SRCROOT}/iOS/SensorImpl.mm
+ ${SRCROOT}/iOS/SensorImpl.hpp
+ ${SRCROOT}/iOS/VideoModeImpl.mm
+ ${SRCROOT}/iOS/WindowImplUIKit.hpp
+ ${SRCROOT}/iOS/WindowImplUIKit.mm
+ ${SRCROOT}/iOS/ObjCType.hpp
+ ${SRCROOT}/iOS/SFAppDelegate.hpp
+ ${SRCROOT}/iOS/SFAppDelegate.mm
+ ${SRCROOT}/iOS/SFView.hpp
+ ${SRCROOT}/iOS/SFView.mm
+ ${SRCROOT}/iOS/SFViewController.hpp
+ ${SRCROOT}/iOS/SFViewController.mm
+ ${SRCROOT}/iOS/SFMain.hpp
+ ${SRCROOT}/iOS/SFMain.mm
+ )
+ source_group("ios" FILES ${PLATFORM_SRC})
+elseif(SFML_OS_ANDROID)
+ set(PLATFORM_SRC
+ ${SRCROOT}/Android/CursorImpl.hpp
+ ${SRCROOT}/Android/CursorImpl.cpp
+ ${SRCROOT}/Android/ClipboardImpl.hpp
+ ${SRCROOT}/Android/ClipboardImpl.cpp
+ ${SRCROOT}/Android/WindowImplAndroid.hpp
+ ${SRCROOT}/Android/WindowImplAndroid.cpp
+ ${SRCROOT}/Android/VideoModeImpl.cpp
+ ${SRCROOT}/Android/InputImpl.hpp
+ ${SRCROOT}/Android/InputImpl.cpp
+ ${SRCROOT}/Android/JoystickImpl.hpp
+ ${SRCROOT}/Android/JoystickImpl.cpp
+ ${SRCROOT}/Android/SensorImpl.hpp
+ ${SRCROOT}/Android/SensorImpl.cpp
+ )
+ source_group("android" FILES ${PLATFORM_SRC})
+endif()
+
+# define the sfml-window target
+sfml_add_library(sfml-window
+ SOURCES ${SRC} ${PLATFORM_SRC})
+target_link_libraries(sfml-window PUBLIC sfml-system)
+
+# When static linking on macOS, we need to add this flag for objective C to work
+if ((NOT BUILD_SHARED_LIBS) AND SFML_OS_MACOSX)
+ target_link_libraries(sfml-window PRIVATE -ObjC)
+endif()
+
+# find and setup usage for external libraries
+if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OPENBSD)
+ sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB")
+ target_link_libraries(sfml-window PRIVATE X11)
+endif()
+
+# CMake 3.11 and later prefer to choose GLVND, but we choose legacy OpenGL for backward compability
+# (unless the OpenGL_GL_PREFERENCE was explicitly set)
+# See CMP0072 for more details (cmake --help-policy CMP0072)
+if ((NOT ${CMAKE_VERSION} VERSION_LESS 3.11) AND (NOT OpenGL_GL_PREFERENCE))
+ set(OpenGL_GL_PREFERENCE "LEGACY")
+endif()
+
+if(SFML_OPENGL_ES)
+ if(SFML_OS_IOS)
+ target_link_libraries(sfml-window PRIVATE "-framework OpenGLES")
+ elseif(SFML_OS_ANDROID)
+ target_link_libraries(sfml-window PRIVATE EGL GLESv1_CM)
+ endif()
+else()
+ sfml_find_package(OpenGL INCLUDE "OPENGL_INCLUDE_DIR" LINK "OPENGL_LIBRARIES")
+ target_link_libraries(sfml-window PRIVATE OpenGL)
+endif()
+
+if(SFML_OS_WINDOWS AND NOT SFML_COMPILER_MSVC)
+ include(CheckIncludeFile)
+ check_include_file(dinput.h DINPUT_H_FOUND)
+ if(NOT DINPUT_H_FOUND)
+ target_include_directories(sfml-window PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/mingw")
+ endif()
+endif()
+
+if(SFML_OPENGL_ES AND SFML_OS_LINUX)
+ sfml_find_package(EGL INCLUDE "EGL_INCLUDE_DIR" LINK "EGL_LIBRARY")
+ sfml_find_package(GLES INCLUDE "GLES_INCLUDE_DIR" LINK "GLES_LIBRARY")
+ target_link_libraries(sfml-window PRIVATE EGL GLES)
+endif()
+
+if(SFML_OS_LINUX)
+ sfml_find_package(UDev INCLUDE "UDEV_INCLUDE_DIR" LINK "UDEV_LIBRARIES")
+ target_link_libraries(sfml-window PRIVATE UDev)
+elseif(SFML_OS_WINDOWS)
+ target_link_libraries(sfml-window PRIVATE winmm gdi32)
+elseif(SFML_OS_FREEBSD)
+ target_link_libraries(sfml-window PRIVATE usbhid)
+elseif(SFML_OS_MACOSX)
+ target_link_libraries(sfml-window PRIVATE "-framework Foundation" "-framework AppKit" "-framework IOKit" "-framework Carbon")
+elseif(SFML_OS_IOS)
+ target_link_libraries(sfml-window PRIVATE "-framework Foundation" "-framework UIKit" "-framework CoreGraphics" "-framework QuartzCore" "-framework CoreMotion")
+elseif(SFML_OS_ANDROID)
+ target_link_libraries(sfml-window PRIVATE android)
+endif()
diff --git a/src/SFML/Window/Clipboard.cpp b/src/SFML/Window/Clipboard.cpp
new file mode 100644
index 0000000..9148c97
--- /dev/null
+++ b/src/SFML/Window/Clipboard.cpp
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Clipboard.hpp>
+#include <SFML/Window/ClipboardImpl.hpp>
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+String Clipboard::getString()
+{
+ return priv::ClipboardImpl::getString();
+}
+
+
+////////////////////////////////////////////////////////////
+void Clipboard::setString(const String& text)
+{
+ return priv::ClipboardImpl::setString(text);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/ClipboardImpl.hpp b/src/SFML/Window/ClipboardImpl.hpp
new file mode 100644
index 0000000..8e60d4e
--- /dev/null
+++ b/src/SFML/Window/ClipboardImpl.hpp
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPL_HPP
+#define SFML_CLIPBOARDIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/Window/Win32/ClipboardImpl.hpp>
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+ #include <SFML/Window/Unix/ClipboardImpl.hpp>
+#elif defined(SFML_SYSTEM_MACOS)
+ #include <SFML/Window/OSX/ClipboardImpl.hpp>
+#elif defined(SFML_SYSTEM_IOS)
+ #include <SFML/Window/iOS/ClipboardImpl.hpp>
+#elif defined(SFML_SYSTEM_ANDROID)
+ #include <SFML/Window/Android/ClipboardImpl.hpp>
+#endif
+
+#endif // SFML_CLIPBOARDIMPL_HPP
diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp
new file mode 100644
index 0000000..4e0a4b8
--- /dev/null
+++ b/src/SFML/Window/Context.cpp
@@ -0,0 +1,111 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Context.hpp>
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/System/ThreadLocalPtr.hpp>
+
+
+namespace
+{
+ // This per-thread variable holds the current context for each thread
+ sf::ThreadLocalPtr<sf::Context> currentContext(NULL);
+}
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Context::Context()
+{
+ m_context = priv::GlContext::create();
+ setActive(true);
+}
+
+
+////////////////////////////////////////////////////////////
+Context::~Context()
+{
+ setActive(false);
+ delete m_context;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Context::setActive(bool active)
+{
+ bool result = m_context->setActive(active);
+
+ if (result)
+ currentContext = (active ? this : NULL);
+
+ return result;
+}
+
+
+////////////////////////////////////////////////////////////
+const ContextSettings& Context::getSettings() const
+{
+ return m_context->getSettings();
+}
+
+
+////////////////////////////////////////////////////////////
+const Context* Context::getActiveContext()
+{
+ return currentContext;
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 Context::getActiveContextId()
+{
+ return priv::GlContext::getActiveContextId();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Context::isExtensionAvailable(const char* name)
+{
+ return priv::GlContext::isExtensionAvailable(name);
+}
+
+
+////////////////////////////////////////////////////////////
+GlFunctionPointer Context::getFunction(const char* name)
+{
+ return priv::GlContext::getFunction(name);
+}
+
+
+////////////////////////////////////////////////////////////
+Context::Context(const ContextSettings& settings, unsigned int width, unsigned int height)
+{
+ m_context = priv::GlContext::create(settings, width, height);
+ setActive(true);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/Cursor.cpp b/src/SFML/Window/Cursor.cpp
new file mode 100644
index 0000000..c71491f
--- /dev/null
+++ b/src/SFML/Window/Cursor.cpp
@@ -0,0 +1,73 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/Window/CursorImpl.hpp>
+
+namespace sf
+{
+
+////////////////////////////////////////////////////////////
+Cursor::Cursor() :
+m_impl(new priv::CursorImpl())
+{
+ // That's it
+}
+
+
+////////////////////////////////////////////////////////////
+Cursor::~Cursor()
+{
+ delete m_impl;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Cursor::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ if ((pixels == 0) || (size.x == 0) || (size.y == 0))
+ return false;
+ else
+ return m_impl->loadFromPixels(pixels, size, hotspot);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Cursor::loadFromSystem(Type type)
+{
+ return m_impl->loadFromSystem(type);
+}
+
+
+////////////////////////////////////////////////////////////
+const priv::CursorImpl& Cursor::getImpl() const
+{
+ return *m_impl;
+}
+
+} // namespace sf
+
diff --git a/src/SFML/Window/CursorImpl.hpp b/src/SFML/Window/CursorImpl.hpp
new file mode 100644
index 0000000..d48220c
--- /dev/null
+++ b/src/SFML/Window/CursorImpl.hpp
@@ -0,0 +1,56 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSORIMPL_HPP
+#define SFML_CURSORIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Window/Win32/CursorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+
+ #include <SFML/Window/Unix/CursorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_MACOS)
+
+ #include <SFML/Window/OSX/CursorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_IOS)
+
+ #include <SFML/Window/iOS/CursorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_ANDROID)
+
+ #include <SFML/Window/Android/CursorImpl.hpp>
+
+#endif
+
+
+#endif // SFML_CURSORIMPL_HPP
diff --git a/src/SFML/Window/EGLCheck.cpp b/src/SFML/Window/EGLCheck.cpp
new file mode 100644
index 0000000..dabf54e
--- /dev/null
+++ b/src/SFML/Window/EGLCheck.cpp
@@ -0,0 +1,161 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/EGLCheck.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void eglCheckError(const char* file, unsigned int line)
+{
+ // Obtain information about the success or failure of the most recent EGL
+ // function called in the current thread
+ EGLint errorCode = eglGetError();
+
+ if (errorCode != EGL_SUCCESS)
+ {
+ std::string fileString(file);
+ std::string error = "unknown error";
+ std::string description = "no description";
+
+ // Decode the error code returned
+ switch (errorCode)
+ {
+ case EGL_NOT_INITIALIZED:
+ {
+ error = "EGL_NOT_INITIALIZED";
+ description = "EGL is not initialized, or could not be initialized, for the specified display";
+ break;
+ }
+
+ case EGL_BAD_ACCESS:
+ {
+ error = "EGL_BAD_ACCESS";
+ description = "EGL cannot access a requested resource (for example, a context is bound in another thread)";
+ break;
+ }
+
+ case EGL_BAD_ALLOC:
+ {
+ error = "EGL_BAD_ALLOC";
+ description = "EGL failed to allocate resources for the requested operation";
+ break;
+ }
+ case EGL_BAD_ATTRIBUTE:
+ {
+ error = "EGL_BAD_ATTRIBUTE";
+ description = "an unrecognized attribute or attribute value was passed in an attribute list";
+ break;
+ }
+
+ case EGL_BAD_CONTEXT:
+ {
+ error = "EGL_BAD_CONTEXT";
+ description = "an EGLContext argument does not name a valid EGLContext";
+ break;
+ }
+
+ case EGL_BAD_CONFIG:
+ {
+ error = "EGL_BAD_CONFIG";
+ description = "an EGLConfig argument does not name a valid EGLConfig";
+ break;
+ }
+
+ case EGL_BAD_CURRENT_SURFACE:
+ {
+ error = "EGL_BAD_CURRENT_SURFACE";
+ description = "the current surface of the calling thread is a window, pbuffer, or pixmap that is no longer valid";
+ break;
+ }
+
+ case EGL_BAD_DISPLAY:
+ {
+ error = "EGL_BAD_DISPLAY";
+ description = "an EGLDisplay argument does not name a valid EGLDisplay; or, EGL is not initialized on the specified EGLDisplay";
+ break;
+ }
+
+
+ case EGL_BAD_SURFACE:
+ {
+ error = "EGL_BAD_SURFACE";
+ description = "an EGLSurface argument does not name a valid surface (window, pbuffer, or pixmap) configured for rendering";
+ break;
+ }
+
+ case EGL_BAD_MATCH:
+ {
+ error = "EGL_BAD_MATCH";
+ description = "arguments are inconsistent; for example, an otherwise valid context requires buffers (e.g. depth or stencil) not allocated by an otherwise valid surface";
+ break;
+ }
+
+ case EGL_BAD_PARAMETER:
+ {
+ error = "EGL_BAD_PARAMETER";
+ description = "one or more argument values are invalid";
+ break;
+ }
+
+ case EGL_BAD_NATIVE_PIXMAP:
+ {
+ error = "EGL_BAD_NATIVE_PIXMAP";
+ description = "an EGLNativePixmapType argument does not refer to a valid native pixmap";
+ break;
+ }
+
+ case EGL_BAD_NATIVE_WINDOW:
+ {
+ error = "EGL_BAD_NATIVE_WINDOW";
+ description = "an EGLNativeWindowType argument does not refer to a valid native window";
+ break;
+ }
+
+ case EGL_CONTEXT_LOST:
+ {
+ error = "EGL_CONTEXT_LOST";
+ description = "a power management event has occurred. The application must destroy all contexts and reinitialize client API state and objects to continue rendering";
+ break;
+ }
+ }
+
+ // Log the error
+ err() << "An internal EGL call failed in "
+ << fileString.substr(fileString.find_last_of("\\/") + 1) << " (" << line << ") : "
+ << error << ", " << description
+ << std::endl;
+ }
+}
+
+} // namespace priv
+} // namespace sf
diff --git a/src/SFML/Window/EGLCheck.hpp b/src/SFML/Window/EGLCheck.hpp
new file mode 100644
index 0000000..317d9a8
--- /dev/null
+++ b/src/SFML/Window/EGLCheck.hpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_EGLCHECK_HPP
+#define SFML_EGLCHECK_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <EGL/egl.h>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// Let's define a macro to quickly check every EGL API call
+////////////////////////////////////////////////////////////
+#ifdef SFML_DEBUG
+
+ //// In debug mode, perform a test on every EGL call
+ #define eglCheck(x) x; sf::priv::eglCheckError(__FILE__, __LINE__);
+
+#else
+
+ // Else, we don't add any overhead
+ #define eglCheck(x) (x)
+
+#endif
+
+////////////////////////////////////////////////////////////
+/// \brief Check the last EGL error
+///
+/// \param file Source file where the call is located
+/// \param line Line number of the source file where the call is located
+///
+////////////////////////////////////////////////////////////
+void eglCheckError(const char* file, unsigned int line);
+
+} // namespace priv
+} // namespace sf
+
+
+#endif // SFML_EGLCHECK_HPP
diff --git a/src/SFML/Window/EglContext.cpp b/src/SFML/Window/EglContext.cpp
new file mode 100644
index 0000000..fb91cda
--- /dev/null
+++ b/src/SFML/Window/EglContext.cpp
@@ -0,0 +1,341 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/EglContext.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/OpenGL.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#ifdef SFML_SYSTEM_ANDROID
+ #include <SFML/System/Android/Activity.hpp>
+#endif
+#ifdef SFML_SYSTEM_LINUX
+ #include <X11/Xlib.h>
+#endif
+
+namespace
+{
+ EGLDisplay getInitializedDisplay()
+ {
+#if defined(SFML_SYSTEM_LINUX)
+
+ static EGLDisplay display = EGL_NO_DISPLAY;
+
+ if (display == EGL_NO_DISPLAY)
+ {
+ display = eglCheck(eglGetDisplay(EGL_DEFAULT_DISPLAY));
+ eglCheck(eglInitialize(display, NULL, NULL));
+ }
+
+ return display;
+
+#elif defined(SFML_SYSTEM_ANDROID)
+
+ // On Android, its native activity handles this for us
+ sf::priv::ActivityStates* states = sf::priv::getActivity(NULL);
+ sf::Lock lock(states->mutex);
+
+ return states->display;
+
+#endif
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+EglContext::EglContext(EglContext* shared) :
+m_display (EGL_NO_DISPLAY),
+m_context (EGL_NO_CONTEXT),
+m_surface (EGL_NO_SURFACE),
+m_config (NULL)
+{
+ // Get the initialized EGL display
+ m_display = getInitializedDisplay();
+
+ // Get the best EGL config matching the default video settings
+ m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings());
+ updateSettings();
+
+ // Note: The EGL specs say that attrib_list can be NULL when passed to eglCreatePbufferSurface,
+ // but this is resulting in a segfault. Bug in Android?
+ EGLint attrib_list[] = {
+ EGL_WIDTH, 1,
+ EGL_HEIGHT,1,
+ EGL_NONE
+ };
+
+ m_surface = eglCheck(eglCreatePbufferSurface(m_display, m_config, attrib_list));
+
+ // Create EGL context
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+EglContext::EglContext(EglContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_display (EGL_NO_DISPLAY),
+m_context (EGL_NO_CONTEXT),
+m_surface (EGL_NO_SURFACE),
+m_config (NULL)
+{
+#ifdef SFML_SYSTEM_ANDROID
+
+ // On Android, we must save the created context
+ ActivityStates* states = getActivity(NULL);
+ Lock lock(states->mutex);
+
+ states->context = this;
+
+#endif
+
+ // Get the initialized EGL display
+ m_display = getInitializedDisplay();
+
+ // Get the best EGL config matching the requested video settings
+ m_config = getBestConfig(m_display, bitsPerPixel, settings);
+ updateSettings();
+
+ // Create EGL context
+ createContext(shared);
+
+#if !defined(SFML_SYSTEM_ANDROID)
+ // Create EGL surface (except on Android because the window is created
+ // asynchronously, its activity manager will call it for us)
+ createSurface((EGLNativeWindowType)owner->getSystemHandle());
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+EglContext::EglContext(EglContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
+m_display (EGL_NO_DISPLAY),
+m_context (EGL_NO_CONTEXT),
+m_surface (EGL_NO_SURFACE),
+m_config (NULL)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+EglContext::~EglContext()
+{
+ // Notify unshared OpenGL resources of context destruction
+ cleanupUnsharedResources();
+
+ // Deactivate the current context
+ EGLContext currentContext = eglCheck(eglGetCurrentContext());
+
+ if (currentContext == m_context)
+ {
+ eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+ }
+
+ // Destroy context
+ if (m_context != EGL_NO_CONTEXT)
+ {
+ eglCheck(eglDestroyContext(m_display, m_context));
+ }
+
+ // Destroy surface
+ if (m_surface != EGL_NO_SURFACE)
+ {
+ eglCheck(eglDestroySurface(m_display, m_surface));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool EglContext::makeCurrent(bool current)
+{
+ if (current)
+ return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context));
+
+ return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::display()
+{
+ if (m_surface != EGL_NO_SURFACE)
+ eglCheck(eglSwapBuffers(m_display, m_surface));
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::setVerticalSyncEnabled(bool enabled)
+{
+ eglCheck(eglSwapInterval(m_display, enabled ? 1 : 0));
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::createContext(EglContext* shared)
+{
+ const EGLint contextVersion[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 1,
+ EGL_NONE
+ };
+
+ EGLContext toShared;
+
+ if (shared)
+ toShared = shared->m_context;
+ else
+ toShared = EGL_NO_CONTEXT;
+
+ if (toShared != EGL_NO_CONTEXT)
+ eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ // Create EGL context
+ m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::createSurface(EGLNativeWindowType window)
+{
+ m_surface = eglCheck(eglCreateWindowSurface(m_display, m_config, window, NULL));
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::destroySurface()
+{
+ eglCheck(eglDestroySurface(m_display, m_surface));
+ m_surface = EGL_NO_SURFACE;
+
+ // Ensure that this context is no longer active since our surface is now destroyed
+ setActive(false);
+}
+
+
+////////////////////////////////////////////////////////////
+EGLConfig EglContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings)
+{
+ // Set our video settings constraint
+ const EGLint attributes[] = {
+ EGL_BUFFER_SIZE, static_cast<EGLint>(bitsPerPixel),
+ EGL_DEPTH_SIZE, static_cast<EGLint>(settings.depthBits),
+ EGL_STENCIL_SIZE, static_cast<EGLint>(settings.stencilBits),
+ EGL_SAMPLE_BUFFERS, static_cast<EGLint>(settings.antialiasingLevel),
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
+ EGL_NONE
+ };
+
+ EGLint configCount;
+ EGLConfig configs[1];
+
+ // Ask EGL for the best config matching our video settings
+ eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount));
+
+ // TODO: This should check EGL_CONFORMANT and pick the first conformant configuration.
+
+ return configs[0];
+}
+
+
+////////////////////////////////////////////////////////////
+void EglContext::updateSettings()
+{
+ EGLint tmp;
+
+ // Update the internal context settings with the current config
+ eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp));
+ m_settings.depthBits = tmp;
+
+ eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp));
+ m_settings.stencilBits = tmp;
+
+ eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp));
+ m_settings.antialiasingLevel = tmp;
+
+ m_settings.majorVersion = 1;
+ m_settings.minorVersion = 1;
+ m_settings.attributeFlags = ContextSettings::Default;
+}
+
+
+#ifdef SFML_SYSTEM_LINUX
+////////////////////////////////////////////////////////////
+XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsPerPixel, const ContextSettings& settings)
+{
+ // Get the initialized EGL display
+ EGLDisplay display = getInitializedDisplay();
+
+ // Get the best EGL config matching the default video settings
+ EGLConfig config = getBestConfig(display, bitsPerPixel, settings);
+
+ // Retrieve the visual id associated with this EGL config
+ EGLint nativeVisualId;
+
+ eglCheck(eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId));
+
+ if (nativeVisualId == 0)
+ {
+ // Should never happen...
+ err() << "No EGL visual found. You should check your graphics driver" << std::endl;
+
+ return XVisualInfo();
+ }
+
+ XVisualInfo vTemplate;
+ vTemplate.visualid = static_cast<VisualID>(nativeVisualId);
+
+ // Get X11 visuals compatible with this EGL config
+ XVisualInfo *availableVisuals, bestVisual;
+ int visualCount = 0;
+
+ availableVisuals = XGetVisualInfo(XDisplay, VisualIDMask, &vTemplate, &visualCount);
+
+ if (visualCount == 0)
+ {
+ // Can't happen...
+ err() << "No X11 visual found. Bug in your EGL implementation ?" << std::endl;
+
+ return XVisualInfo();
+ }
+
+ // Pick up the best one
+ bestVisual = availableVisuals[0];
+ XFree(availableVisuals);
+
+ return bestVisual;
+}
+#endif
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/EglContext.hpp b/src/SFML/Window/EglContext.hpp
new file mode 100644
index 0000000..a889c3a
--- /dev/null
+++ b/src/SFML/Window/EglContext.hpp
@@ -0,0 +1,190 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_EGLCONTEXT_HPP
+#define SFML_EGLCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+#include <SFML/Window/EGLCheck.hpp>
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/OpenGL.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+class EglContext : public GlContext
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context, not associated to a window
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ EglContext(EglContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ EglContext(EglContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ EglContext(EglContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~EglContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate the context as the current target
+ /// for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled: True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Creation parameters
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(EglContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the EGL surface
+ ///
+ /// This function must be called when the activity (re)start, or
+ /// when the orientation change.
+ ///
+ /// \param window: The native window type
+ ///
+ ////////////////////////////////////////////////////////////
+ void createSurface(EGLNativeWindowType window);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destroy the EGL surface
+ ///
+ /// This function must be called when the activity is stopped, or
+ /// when the orientation change.
+ ///
+ ////////////////////////////////////////////////////////////
+ void destroySurface();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the best EGL visual for a given set of video settings
+ ///
+ /// \param display EGL display
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Requested context settings
+ ///
+ /// \return The best EGL config
+ ///
+ ////////////////////////////////////////////////////////////
+ static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings);
+
+#ifdef SFML_SYSTEM_LINUX
+ ////////////////////////////////////////////////////////////
+ /// \brief Select the best EGL visual for a given set of settings
+ ///
+ /// \param display X display
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Requested context settings
+ ///
+ /// \return The best visual
+ ///
+ ////////////////////////////////////////////////////////////
+ static XVisualInfo selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings);
+#endif
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Helper to copy the picked EGL configuration
+ ////////////////////////////////////////////////////////////
+ void updateSettings();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ EGLDisplay m_display; ///< The internal EGL display
+ EGLContext m_context; ///< The internal EGL context
+ EGLSurface m_surface; ///< The internal EGL surface
+ EGLConfig m_config; ///< The internal EGL config
+
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_EGLCONTEXT_HPP
diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.cpp b/src/SFML/Window/FreeBSD/JoystickImpl.cpp
new file mode 100644
index 0000000..6bc646d
--- /dev/null
+++ b/src/SFML/Window/FreeBSD/JoystickImpl.cpp
@@ -0,0 +1,346 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Laurent Gomila (laurent@sfml-dev.org)
+// 2013-2013 David Demelier (demelier.david@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstring>
+#include <map>
+#include <string>
+#include <utility>
+
+////////////////////////////////////////////////////////////
+/// \brief This file implements FreeBSD driver joystick
+///
+/// It has been tested on a Saitek gamepad with 12 buttons,
+/// 2 analog axis and one hat.
+///
+/// Note: old joy(4) drivers are not supported and no one use that
+/// anymore.
+////////////////////////////////////////////////////////////
+
+
+namespace
+{
+ std::map<unsigned int, std::string> plugged;
+ std::map<int, std::pair<int, int> > hatValueMap;
+
+ bool isJoystick(const char *name)
+ {
+ int file = ::open(name, O_RDONLY | O_NONBLOCK);
+
+ if (file < 0)
+ return false;
+
+ report_desc_t desc = hid_get_report_desc(file);
+
+ if (!desc)
+ {
+ ::close(file);
+ return false;
+ }
+
+ int id = hid_get_report_id(file);
+ hid_data_t data = hid_start_parse(desc, 1 << hid_input, id);
+
+ if (!data)
+ {
+ hid_dispose_report_desc(desc);
+ ::close(file);
+ return false;
+ }
+
+ hid_item_t item;
+
+ // Assume it isn't
+ bool result = false;
+
+ while (hid_get_item(data, &item) > 0)
+ {
+ if ((item.kind == hid_collection) && (HID_PAGE(item.usage) == HUP_GENERIC_DESKTOP))
+ {
+ if ((HID_USAGE(item.usage) == HUG_JOYSTICK) || (HID_USAGE(item.usage) == HUG_GAME_PAD))
+ {
+ result = true;
+ }
+ }
+ }
+
+ hid_end_parse(data);
+ hid_dispose_report_desc(desc);
+ ::close(file);
+
+ return result;
+ }
+
+ void updatePluggedList()
+ {
+ /*
+ * Devices /dev/uhid<x> are shared between joystick and any other
+ * human interface device. We need to iterate over all found devices
+ * and check if they are joysticks. The index of JoystickImpl::open
+ * does not match the /dev/uhid<index> device!
+ */
+ DIR* directory = opendir("/dev");
+
+ if (directory)
+ {
+ int joystickCount = 0;
+ struct dirent* directoryEntry = readdir(directory);
+
+ while (directoryEntry && joystickCount < sf::Joystick::Count)
+ {
+ if (!std::strncmp(directoryEntry->d_name, "uhid", 4))
+ {
+ std::string name("/dev/");
+ name += directoryEntry->d_name;
+
+ if (isJoystick(name.c_str()))
+ plugged[joystickCount++] = name;
+ }
+
+ directoryEntry = readdir(directory);
+ }
+
+ closedir(directory);
+ }
+ }
+
+ int usageToAxis(int usage)
+ {
+ switch (usage)
+ {
+ case HUG_X: return sf::Joystick::X;
+ case HUG_Y: return sf::Joystick::Y;
+ case HUG_Z: return sf::Joystick::Z;
+ case HUG_RZ: return sf::Joystick::R;
+ case HUG_RX: return sf::Joystick::U;
+ case HUG_RY: return sf::Joystick::V;
+ default: return -1;
+ }
+ }
+
+ void hatValueToSfml(int value, sf::priv::JoystickState& state)
+ {
+ state.axes[sf::Joystick::PovX] = hatValueMap[value].first;
+ state.axes[sf::Joystick::PovY] = hatValueMap[value].second;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ hid_init(NULL);
+
+ // Do an initial scan
+ updatePluggedList();
+
+ // Map of hat values
+ hatValueMap[0] = std::make_pair( 0, 0); // center
+
+ hatValueMap[1] = std::make_pair( 0, -100); // top
+ hatValueMap[3] = std::make_pair( 100, 0); // right
+ hatValueMap[5] = std::make_pair( 0, 100); // bottom
+ hatValueMap[7] = std::make_pair(-100, 0); // left
+
+ hatValueMap[2] = std::make_pair( 100, -100); // top-right
+ hatValueMap[4] = std::make_pair( 100, 100); // bottom-right
+ hatValueMap[6] = std::make_pair(-100, 100); // bottom-left
+ hatValueMap[8] = std::make_pair(-100, -100); // top-left
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ return plugged.find(index) != plugged.end();
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ if (isConnected(index))
+ {
+ // Open the joystick's file descriptor (read-only and non-blocking)
+ m_file = ::open(plugged[index].c_str(), O_RDONLY | O_NONBLOCK);
+ if (m_file >= 0)
+ {
+ // Reset the joystick state
+ m_state = JoystickState();
+
+ // Get the report descriptor
+ m_desc = hid_get_report_desc(m_file);
+ if (!m_desc)
+ {
+ ::close(m_file);
+ return false;
+ }
+
+ // And the id
+ m_id = hid_get_report_id(m_file);
+
+ // Then allocate a buffer for data retrieval
+ m_length = hid_report_size(m_desc, hid_input, m_id);
+ m_buffer.resize(m_length);
+
+ m_state.connected = true;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ ::close(m_file);
+ hid_dispose_report_desc(m_desc);
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ JoystickCaps caps;
+ hid_item_t item;
+
+ hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id);
+
+ while (hid_get_item(data, &item))
+ {
+ if (item.kind == hid_input)
+ {
+ int usage = HID_USAGE(item.usage);
+
+ if (usage == HUP_BUTTON)
+ {
+ caps.buttonCount++;
+ break;
+ }
+ else if (usage == HUP_GENERIC_DESKTOP)
+ {
+ int axis = usageToAxis(usage);
+
+ if (usage == HUG_HAT_SWITCH)
+ {
+ caps.axes[Joystick::PovX] = true;
+ caps.axes[Joystick::PovY] = true;
+ }
+ else if (axis != -1)
+ {
+ caps.axes[axis] = true;
+ }
+ }
+ }
+ }
+
+ hid_end_parse(data);
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::JoystickImpl::update()
+{
+ while (read(m_file, &m_buffer[0], m_length) == m_length)
+ {
+ hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id);
+
+ // No memory?
+ if (!data)
+ continue;
+
+ int buttonIndex = 0;
+ hid_item_t item;
+
+ while (hid_get_item(data, &item))
+ {
+ if (item.kind == hid_input)
+ {
+ int usage = HID_USAGE(item.usage);
+
+ if (usage == HUP_BUTTON)
+ {
+ m_state.buttons[buttonIndex++] = hid_get_data(&m_buffer[0], &item);
+ }
+ else if (usage == HUP_GENERIC_DESKTOP)
+ {
+ int value = hid_get_data(&m_buffer[0], &item);
+ int axis = usageToAxis(usage);
+
+ if (usage == HUG_HAT_SWITCH)
+ {
+ hatValueToSfml(value, m_state);
+ }
+ else if (axis != -1)
+ {
+ int minimum = item.logical_minimum;
+ int maximum = item.logical_maximum;
+
+ value = (value - minimum) * 200 / (maximum - minimum) - 100;
+ m_state.axes[axis] = value;
+ }
+ }
+ }
+ }
+
+ hid_end_parse(data);
+ }
+
+ return m_state;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.hpp b/src/SFML/Window/FreeBSD/JoystickImpl.hpp
new file mode 100644
index 0000000..5b2c029
--- /dev/null
+++ b/src/SFML/Window/FreeBSD/JoystickImpl.hpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKIMPLFREEBSD_HPP
+#define SFML_JOYSTICKIMPLFREEBSD_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <dev/usb/usbhid.h>
+#include <usbhid.h>
+#include <vector>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief FreeBSD implementation of joysticks
+///
+/// This code has been tested on FreeBSD 9.1 only.
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ int m_file; ///< File descriptor of the joystick
+ report_desc_t m_desc; ///< USB report descriptor
+ int m_id; ///< USB id
+ std::vector<char> m_buffer; ///< USB HID buffer
+ int m_length; ///< Buffer length
+ Joystick::Identification m_identification; ///< Joystick identification
+ JoystickState m_state; ///< Current state of the joystick
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLFREEBSD_HPP
diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp
new file mode 100644
index 0000000..3cbb701
--- /dev/null
+++ b/src/SFML/Window/GlContext.cpp
@@ -0,0 +1,824 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/System/ThreadLocalPtr.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/OpenGL.hpp>
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <set>
+#include <utility>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+#include <cassert>
+
+#if !defined(SFML_OPENGL_ES)
+
+ #if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Window/Win32/WglContext.hpp>
+ typedef sf::priv::WglContext ContextType;
+
+ #elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+
+ #include <SFML/Window/Unix/GlxContext.hpp>
+ typedef sf::priv::GlxContext ContextType;
+
+ #elif defined(SFML_SYSTEM_MACOS)
+
+ #include <SFML/Window/OSX/SFContext.hpp>
+ typedef sf::priv::SFContext ContextType;
+
+ #endif
+
+#else
+
+ #if defined(SFML_SYSTEM_IOS)
+
+ #include <SFML/Window/iOS/EaglContext.hpp>
+ typedef sf::priv::EaglContext ContextType;
+
+ #else
+
+ #include <SFML/Window/EglContext.hpp>
+ typedef sf::priv::EglContext ContextType;
+
+ #endif
+
+#endif
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint);
+
+#else
+
+ typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint);
+
+#endif
+
+#if !defined(GL_MULTISAMPLE)
+ #define GL_MULTISAMPLE 0x809D
+#endif
+
+#if !defined(GL_MAJOR_VERSION)
+ #define GL_MAJOR_VERSION 0x821B
+#endif
+
+#if !defined(GL_MINOR_VERSION)
+ #define GL_MINOR_VERSION 0x821C
+#endif
+
+#if !defined(GL_NUM_EXTENSIONS)
+ #define GL_NUM_EXTENSIONS 0x821D
+#endif
+
+#if !defined(GL_CONTEXT_FLAGS)
+ #define GL_CONTEXT_FLAGS 0x821E
+#endif
+
+#if !defined(GL_FRAMEBUFFER_SRGB)
+ #define GL_FRAMEBUFFER_SRGB 0x8DB9
+#endif
+
+#if !defined(GL_CONTEXT_FLAG_DEBUG_BIT)
+ #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#endif
+
+#if !defined(GL_CONTEXT_PROFILE_MASK)
+ #define GL_CONTEXT_PROFILE_MASK 0x9126
+#endif
+
+#if !defined(GL_CONTEXT_CORE_PROFILE_BIT)
+ #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#endif
+
+#if !defined(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+ #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#endif
+
+
+namespace
+{
+ // AMD drivers have issues with internal synchronization
+ // We need to make sure that no operating system context
+ // or pixel format operations are performed simultaneously
+ // This mutex is also used to protect the shared context
+ // from being locked on multiple threads and for managing
+ // the resource count
+ sf::Mutex mutex;
+
+ // OpenGL resources counter
+ unsigned int resourceCount = 0;
+
+ // This per-thread variable holds the current context for each thread
+ sf::ThreadLocalPtr<sf::priv::GlContext> currentContext(NULL);
+
+ // The hidden, inactive context that will be shared with all other contexts
+ ContextType* sharedContext = NULL;
+
+ // Unique identifier, used for identifying contexts when managing unshareable OpenGL resources
+ sf::Uint64 id = 1; // start at 1, zero is "no context"
+
+ // Set containing callback functions to be called whenever a
+ // context is going to be destroyed
+ // Unshareable OpenGL resources rely on this to clean up properly
+ // whenever a context containing them is destroyed
+ typedef std::set<std::pair<sf::ContextDestroyCallback, void*> > ContextDestroyCallbacks;
+ ContextDestroyCallbacks contextDestroyCallbacks;
+
+ // This structure contains all the state necessary to
+ // track TransientContext usage
+ struct TransientContext : private sf::NonCopyable
+ {
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ TransientContext() :
+ referenceCount (0),
+ context (0),
+ sharedContextLock(0),
+ useSharedContext (false)
+ {
+ if (resourceCount == 0)
+ {
+ context = new sf::Context;
+ }
+ else if (!currentContext)
+ {
+ sharedContextLock = new sf::Lock(mutex);
+ useSharedContext = true;
+ sharedContext->setActive(true);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~TransientContext()
+ {
+ if (useSharedContext)
+ sharedContext->setActive(false);
+
+ delete sharedContextLock;
+ delete context;
+ }
+
+ ///////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ unsigned int referenceCount;
+ sf::Context* context;
+ sf::Lock* sharedContextLock;
+ bool useSharedContext;
+ };
+
+ // This per-thread variable tracks if and how a transient
+ // context is currently being used on the current thread
+ sf::ThreadLocalPtr<TransientContext> transientContext(NULL);
+
+ // Supported OpenGL extensions
+ std::vector<std::string> extensions;
+
+ // Helper to parse OpenGL version strings
+ bool parseVersionString(const char* version, const char* prefix, unsigned int &major, unsigned int &minor)
+ {
+ std::size_t prefixLength = std::strlen(prefix);
+
+ if ((std::strlen(version) >= (prefixLength + 3)) &&
+ (std::strncmp(version, prefix, prefixLength) == 0) &&
+ std::isdigit(version[prefixLength]) &&
+ (version[prefixLength + 1] == '.') &&
+ std::isdigit(version[prefixLength + 2]))
+ {
+ major = version[prefixLength] - '0';
+ minor = version[prefixLength + 2] - '0';
+
+ return true;
+ }
+
+ return false;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void GlContext::initResource()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // If this is the very first resource, trigger the global context initialization
+ if (resourceCount == 0)
+ {
+ if (sharedContext)
+ {
+ // Increment the resources counter
+ resourceCount++;
+
+ return;
+ }
+
+ // Create the shared context
+ sharedContext = new ContextType(NULL);
+ sharedContext->initialize(ContextSettings());
+
+ // Load our extensions vector
+ extensions.clear();
+
+ // Check whether a >= 3.0 context is available
+ int majorVersion = 0;
+ glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
+
+ if (glGetError() == GL_INVALID_ENUM)
+ {
+ // Try to load the < 3.0 way
+ const char* extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+
+ do
+ {
+ const char* extension = extensionString;
+
+ while(*extensionString && (*extensionString != ' '))
+ extensionString++;
+
+ extensions.push_back(std::string(extension, extensionString));
+ }
+ while (*extensionString++);
+ }
+ else
+ {
+ // Try to load the >= 3.0 way
+ glGetStringiFuncType glGetStringiFunc = NULL;
+ glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
+
+ if (glGetStringiFunc)
+ {
+ int numExtensions = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
+
+ if (numExtensions)
+ {
+ for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
+ {
+ const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
+
+ extensions.push_back(extensionString);
+ }
+ }
+ }
+ }
+
+ // Deactivate the shared context so that others can activate it when necessary
+ sharedContext->setActive(false);
+ }
+
+ // Increment the resources counter
+ resourceCount++;
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::cleanupResource()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // Decrement the resources counter
+ resourceCount--;
+
+ // If there's no more resource alive, we can trigger the global context cleanup
+ if (resourceCount == 0)
+ {
+ if (!sharedContext)
+ return;
+
+ // Destroy the shared context
+ delete sharedContext;
+ sharedContext = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::registerContextDestroyCallback(ContextDestroyCallback callback, void* arg)
+{
+ contextDestroyCallbacks.insert(std::make_pair(callback, arg));
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::acquireTransientContext()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // If this is the first TransientContextLock on this thread
+ // construct the state object
+ if (!transientContext)
+ transientContext = new TransientContext;
+
+ // Increase the reference count
+ transientContext->referenceCount++;
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::releaseTransientContext()
+{
+ // Protect from concurrent access
+ Lock lock(mutex);
+
+ // Make sure a matching acquireTransientContext() was called
+ assert(transientContext);
+
+ // Decrease the reference count
+ transientContext->referenceCount--;
+
+ // If this is the last TransientContextLock that is released
+ // destroy the state object
+ if (transientContext->referenceCount == 0)
+ {
+ delete transientContext;
+ transientContext = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+GlContext* GlContext::create()
+{
+ // Make sure that there's an active context (context creation may need extensions, and thus a valid context)
+ assert(sharedContext != NULL);
+
+ Lock lock(mutex);
+
+ GlContext* context = NULL;
+
+ // We don't use acquireTransientContext here since we have
+ // to ensure we have exclusive access to the shared context
+ // in order to make sure it is not active during context creation
+ {
+ sharedContext->setActive(true);
+
+ // Create the context
+ context = new ContextType(sharedContext);
+
+ sharedContext->setActive(false);
+ }
+
+ context->initialize(ContextSettings());
+
+ return context;
+}
+
+
+////////////////////////////////////////////////////////////
+GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel)
+{
+ // Make sure that there's an active context (context creation may need extensions, and thus a valid context)
+ assert(sharedContext != NULL);
+
+ Lock lock(mutex);
+
+ GlContext* context = NULL;
+
+ // We don't use acquireTransientContext here since we have
+ // to ensure we have exclusive access to the shared context
+ // in order to make sure it is not active during context creation
+ {
+ sharedContext->setActive(true);
+
+ // Create the context
+ context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
+
+ sharedContext->setActive(false);
+ }
+
+ context->initialize(settings);
+ context->checkSettings(settings);
+
+ return context;
+}
+
+
+////////////////////////////////////////////////////////////
+GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height)
+{
+ // Make sure that there's an active context (context creation may need extensions, and thus a valid context)
+ assert(sharedContext != NULL);
+
+ Lock lock(mutex);
+
+ GlContext* context = NULL;
+
+ // We don't use acquireTransientContext here since we have
+ // to ensure we have exclusive access to the shared context
+ // in order to make sure it is not active during context creation
+ {
+ sharedContext->setActive(true);
+
+ // Create the context
+ context = new ContextType(sharedContext, settings, width, height);
+
+ sharedContext->setActive(false);
+ }
+
+ context->initialize(settings);
+ context->checkSettings(settings);
+
+ return context;
+}
+
+
+////////////////////////////////////////////////////////////
+bool GlContext::isExtensionAvailable(const char* name)
+{
+ return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
+}
+
+
+////////////////////////////////////////////////////////////
+GlFunctionPointer GlContext::getFunction(const char* name)
+{
+#if !defined(SFML_OPENGL_ES)
+
+ Lock lock(mutex);
+
+ return ContextType::getFunction(name);
+
+#else
+
+ return 0;
+
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+Uint64 GlContext::getActiveContextId()
+{
+ return currentContext ? currentContext->m_id : 0;
+}
+
+
+////////////////////////////////////////////////////////////
+GlContext::~GlContext()
+{
+ // Deactivate the context before killing it, unless we're inside Cleanup()
+ if (sharedContext)
+ {
+ if (this == currentContext)
+ currentContext = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const ContextSettings& GlContext::getSettings() const
+{
+ return m_settings;
+}
+
+
+////////////////////////////////////////////////////////////
+bool GlContext::setActive(bool active)
+{
+ if (active)
+ {
+ if (this != currentContext)
+ {
+ Lock lock(mutex);
+
+ // Activate the context
+ if (makeCurrent(true))
+ {
+ // Set it as the new current context for this thread
+ currentContext = this;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // This context is already the active one on this thread, don't do anything
+ return true;
+ }
+ }
+ else
+ {
+ if (this == currentContext)
+ {
+ Lock lock(mutex);
+
+ // Deactivate the context
+ if (makeCurrent(false))
+ {
+ currentContext = NULL;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // This context is not the active one on this thread, don't do anything
+ return true;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+GlContext::GlContext() :
+m_id(id++)
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb)
+{
+ int colorDiff = static_cast<int>(bitsPerPixel) - colorBits;
+ int depthDiff = static_cast<int>(settings.depthBits) - depthBits;
+ int stencilDiff = static_cast<int>(settings.stencilBits) - stencilBits;
+ int antialiasingDiff = static_cast<int>(settings.antialiasingLevel) - antialiasing;
+
+ // Weight sub-scores so that better settings don't score equally as bad as worse settings
+ colorDiff *= ((colorDiff > 0) ? 100000 : 1);
+ depthDiff *= ((depthDiff > 0) ? 100000 : 1);
+ stencilDiff *= ((stencilDiff > 0) ? 100000 : 1);
+ antialiasingDiff *= ((antialiasingDiff > 0) ? 100000 : 1);
+
+ // Aggregate the scores
+ int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff);
+
+ // If the user wants an sRGB capable format, try really hard to get one
+ if (settings.sRgbCapable && !sRgb)
+ score += 10000000;
+
+ // Make sure we prefer hardware acceleration over features
+ if (!accelerated)
+ score += 100000000;
+
+ return score;
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::cleanupUnsharedResources()
+{
+ // Save the current context so we can restore it later
+ GlContext* contextToRestore = currentContext;
+
+ // If this context is already active there is no need to save it
+ if (contextToRestore == this)
+ contextToRestore = NULL;
+
+ // Make this context active so resources can be freed
+ setActive(true);
+
+ // Call the registered destruction callbacks
+ for (ContextDestroyCallbacks::iterator iter = contextDestroyCallbacks.begin(); iter != contextDestroyCallbacks.end(); ++iter)
+ iter->first(iter->second);
+
+ // Make the originally active context active again
+ if (contextToRestore)
+ contextToRestore->setActive(true);
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::initialize(const ContextSettings& requestedSettings)
+{
+ // Activate the context
+ setActive(true);
+
+ // Retrieve the context version number
+ int majorVersion = 0;
+ int minorVersion = 0;
+
+ // Try the new way first
+ glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
+ glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
+
+ if (glGetError() != GL_INVALID_ENUM)
+ {
+ m_settings.majorVersion = static_cast<unsigned int>(majorVersion);
+ m_settings.minorVersion = static_cast<unsigned int>(minorVersion);
+ }
+ else
+ {
+ // Try the old way
+
+ // If we can't get the version number, assume 1.1
+ m_settings.majorVersion = 1;
+ m_settings.minorVersion = 1;
+
+ const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ if (version)
+ {
+ // OpenGL ES Common Lite profile: The beginning of the returned string is "OpenGL ES-CL major.minor"
+ // OpenGL ES Common profile: The beginning of the returned string is "OpenGL ES-CM major.minor"
+ // OpenGL ES Full profile: The beginning of the returned string is "OpenGL ES major.minor"
+ // Desktop OpenGL: The beginning of the returned string is "major.minor"
+
+ if (!parseVersionString(version, "OpenGL ES-CL ", m_settings.majorVersion, m_settings.minorVersion) &&
+ !parseVersionString(version, "OpenGL ES-CM ", m_settings.majorVersion, m_settings.minorVersion) &&
+ !parseVersionString(version, "OpenGL ES ", m_settings.majorVersion, m_settings.minorVersion) &&
+ !parseVersionString(version, "", m_settings.majorVersion, m_settings.minorVersion))
+ {
+ err() << "Unable to parse OpenGL version string: \"" << version << "\", defaulting to 1.1" << std::endl;
+ }
+ }
+ else
+ {
+ err() << "Unable to retrieve OpenGL version string, defaulting to 1.1" << std::endl;
+ }
+ }
+
+ // 3.0 contexts only deprecate features, but do not remove them yet
+ // 3.1 contexts remove features if ARB_compatibility is not present
+ // 3.2+ contexts remove features only if a core profile is requested
+
+ // If the context was created with wglCreateContext, it is guaranteed to be compatibility.
+ // If a 3.0 context was created with wglCreateContextAttribsARB, it is guaranteed to be compatibility.
+ // If a 3.1 context was created with wglCreateContextAttribsARB, the compatibility flag
+ // is set only if ARB_compatibility is present
+ // If a 3.2+ context was created with wglCreateContextAttribsARB, the compatibility flag
+ // would have been set correctly already depending on whether ARB_create_context_profile is supported.
+
+ // If the user requests a 3.0 context, it will be a compatibility context regardless of the requested profile.
+ // If the user requests a 3.1 context and its creation was successful, the specification
+ // states that it will not be a compatibility profile context regardless of the requested
+ // profile unless ARB_compatibility is present.
+
+ m_settings.attributeFlags = ContextSettings::Default;
+
+ if (m_settings.majorVersion >= 3)
+ {
+ // Retrieve the context flags
+ int flags = 0;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
+
+ if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
+ m_settings.attributeFlags |= ContextSettings::Debug;
+
+ if ((m_settings.majorVersion == 3) && (m_settings.minorVersion == 1))
+ {
+ m_settings.attributeFlags |= ContextSettings::Core;
+
+ glGetStringiFuncType glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
+
+ if (glGetStringiFunc)
+ {
+ int numExtensions = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
+
+ for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
+ {
+ const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
+
+ if (std::strstr(extensionString, "GL_ARB_compatibility"))
+ {
+ m_settings.attributeFlags &= ~static_cast<Uint32>(ContextSettings::Core);
+ break;
+ }
+ }
+ }
+ }
+ else if ((m_settings.majorVersion > 3) || (m_settings.minorVersion >= 2))
+ {
+ // Retrieve the context profile
+ int profile = 0;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
+
+ if (profile & GL_CONTEXT_CORE_PROFILE_BIT)
+ m_settings.attributeFlags |= ContextSettings::Core;
+ }
+ }
+
+ // Enable anti-aliasing if requested by the user and supported
+ if ((requestedSettings.antialiasingLevel > 0) && (m_settings.antialiasingLevel > 0))
+ {
+ glEnable(GL_MULTISAMPLE);
+ }
+ else
+ {
+ m_settings.antialiasingLevel = 0;
+ }
+
+ // Enable sRGB if requested by the user and supported
+ if (requestedSettings.sRgbCapable && m_settings.sRgbCapable)
+ {
+ glEnable(GL_FRAMEBUFFER_SRGB);
+
+ // Check to see if the enable was successful
+ if (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_FALSE)
+ {
+ err() << "Warning: Failed to enable GL_FRAMEBUFFER_SRGB" << std::endl;
+ m_settings.sRgbCapable = false;
+ }
+ }
+ else
+ {
+ m_settings.sRgbCapable = false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void GlContext::checkSettings(const ContextSettings& requestedSettings)
+{
+ // Perform checks to inform the user if they are getting a context they might not have expected
+
+ // Detect any known non-accelerated implementations and warn
+ const char* vendorName = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ const char* rendererName = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+
+ if (vendorName && rendererName)
+ {
+ if ((std::strcmp(vendorName, "Microsoft Corporation") == 0) && (std::strcmp(rendererName, "GDI Generic") == 0))
+ {
+ err() << "Warning: Detected \"Microsoft Corporation GDI Generic\" OpenGL implementation" << std::endl
+ << "The current OpenGL implementation is not hardware-accelerated" << std::endl;
+ }
+ }
+
+ int version = m_settings.majorVersion * 10 + m_settings.minorVersion;
+ int requestedVersion = requestedSettings.majorVersion * 10 + requestedSettings.minorVersion;
+
+ if ((m_settings.attributeFlags != requestedSettings.attributeFlags) ||
+ (version < requestedVersion) ||
+ (m_settings.stencilBits < requestedSettings.stencilBits) ||
+ (m_settings.antialiasingLevel < requestedSettings.antialiasingLevel) ||
+ (m_settings.depthBits < requestedSettings.depthBits) ||
+ (!m_settings.sRgbCapable && requestedSettings.sRgbCapable))
+ {
+ err() << "Warning: The created OpenGL context does not fully meet the settings that were requested" << std::endl;
+ err() << "Requested: version = " << requestedSettings.majorVersion << "." << requestedSettings.minorVersion
+ << " ; depth bits = " << requestedSettings.depthBits
+ << " ; stencil bits = " << requestedSettings.stencilBits
+ << " ; AA level = " << requestedSettings.antialiasingLevel
+ << std::boolalpha
+ << " ; core = " << ((requestedSettings.attributeFlags & ContextSettings::Core) != 0)
+ << " ; debug = " << ((requestedSettings.attributeFlags & ContextSettings::Debug) != 0)
+ << " ; sRGB = " << requestedSettings.sRgbCapable
+ << std::noboolalpha << std::endl;
+ err() << "Created: version = " << m_settings.majorVersion << "." << m_settings.minorVersion
+ << " ; depth bits = " << m_settings.depthBits
+ << " ; stencil bits = " << m_settings.stencilBits
+ << " ; AA level = " << m_settings.antialiasingLevel
+ << std::boolalpha
+ << " ; core = " << ((m_settings.attributeFlags & ContextSettings::Core) != 0)
+ << " ; debug = " << ((m_settings.attributeFlags & ContextSettings::Debug) != 0)
+ << " ; sRGB = " << m_settings.sRgbCapable
+ << std::noboolalpha << std::endl;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp
new file mode 100644
index 0000000..0b66965
--- /dev/null
+++ b/src/SFML/Window/GlContext.hpp
@@ -0,0 +1,305 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GLCONTEXT_HPP
+#define SFML_GLCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/Window/Context.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+class WindowImpl;
+
+////////////////////////////////////////////////////////////
+/// \brief Abstract class representing an OpenGL context
+///
+////////////////////////////////////////////////////////////
+class GlContext : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform resource initialization
+ ///
+ /// This function is called every time an OpenGL resource is
+ /// created. When the first resource is initialized, it makes
+ /// sure that everything is ready for contexts to work properly.
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initResource();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform resource cleanup
+ ///
+ /// This function is called every time an OpenGL resource is
+ /// destroyed. When the last resource is destroyed, it makes
+ /// sure that everything that was created by initResource()
+ /// is properly released.
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanupResource();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a function to be called when a context is destroyed
+ ///
+ /// This is used for internal purposes in order to properly
+ /// clean up OpenGL resources that cannot be shared bwteen
+ /// contexts.
+ ///
+ /// \param callback Function to be called when a context is destroyed
+ /// \param arg Argument to pass when calling the function
+ ///
+ ////////////////////////////////////////////////////////////
+ static void registerContextDestroyCallback(ContextDestroyCallback callback, void* arg);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Acquires a context for short-term use on the current thread
+ ///
+ ////////////////////////////////////////////////////////////
+ static void acquireTransientContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Releases a context after short-term use on the current thread
+ ///
+ ////////////////////////////////////////////////////////////
+ static void releaseTransientContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context, not associated to a window
+ ///
+ /// This function automatically chooses the specialized class
+ /// to use according to the OS.
+ ///
+ /// \return Pointer to the created context (don't forget to delete it)
+ ///
+ ////////////////////////////////////////////////////////////
+ static GlContext* create();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// This function automatically chooses the specialized class
+ /// to use according to the OS.
+ ///
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth (in bits per pixel)
+ ///
+ /// \return Pointer to the created context
+ ///
+ ////////////////////////////////////////////////////////////
+ static GlContext* create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// This function automatically chooses the specialized class
+ /// to use according to the OS.
+ ///
+ /// \param settings Creation parameters
+ /// \param width Back buffer width
+ /// \param height Back buffer height
+ ///
+ /// \return Pointer to the created context
+ ///
+ ////////////////////////////////////////////////////////////
+ static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height);
+
+public:
+ ////////////////////////////////////////////////////////////
+ /// \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's ID
+ ///
+ /// The context ID is used to identify contexts when
+ /// managing unshareable OpenGL resources.
+ ///
+ /// \return The active context's ID or 0 if no context is currently active
+ ///
+ ////////////////////////////////////////////////////////////
+ static Uint64 getActiveContextId();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~GlContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \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 Activate or deactivate the context as the current target for rendering
+ ///
+ /// A context 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 context can be active on a thread at a time, thus
+ /// the context previously active (if any) automatically gets deactivated.
+ ///
+ /// \param active True to activate, false to deactivate
+ ///
+ /// \return True if operation was successful, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool setActive(bool active);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display() = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled) = 0;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// This constructor is meant for derived classes only.
+ ///
+ ////////////////////////////////////////////////////////////
+ GlContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate the context as the current target
+ /// for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Notify unshared GlResources of context destruction
+ ///
+ ////////////////////////////////////////////////////////////
+ void cleanupUnsharedResources();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Evaluate a pixel format configuration
+ ///
+ /// This functions can be used by implementations that have
+ /// several valid formats and want to get the best one.
+ /// A score is returned for the given configuration: the
+ /// lower the score is, the better the configuration is.
+ ///
+ /// \param bitsPerPixel Requested pixel depth (bits per pixel)
+ /// \param settings Requested additional settings
+ /// \param colorBits Color bits of the configuration to evaluate
+ /// \param depthBits Depth bits of the configuration to evaluate
+ /// \param stencilBits Stencil bits of the configuration to evaluate
+ /// \param antialiasing Antialiasing level of the configuration to evaluate
+ /// \param accelerated Whether the pixel format is hardware accelerated
+ /// \param sRgb Whether the pixel format is sRGB capable
+ ///
+ /// \return Score of the configuration
+ ///
+ ////////////////////////////////////////////////////////////
+ static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ContextSettings m_settings; ///< Creation settings of the context
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform various initializations after the context construction
+ /// \param requestedSettings Requested settings during context creation
+ ///
+ ////////////////////////////////////////////////////////////
+ void initialize(const ContextSettings& requestedSettings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the context is compatible with the requested settings
+ /// \param requestedSettings Requested settings during context creation
+ ///
+ ////////////////////////////////////////////////////////////
+ void checkSettings(const ContextSettings& requestedSettings);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ const Uint64 m_id; ///< Unique number that identifies the context
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_GLCONTEXT_HPP
diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp
new file mode 100644
index 0000000..64fc88c
--- /dev/null
+++ b/src/SFML/Window/GlResource.cpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlResource.hpp>
+#include <SFML/Window/GlContext.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+GlResource::GlResource()
+{
+ priv::GlContext::initResource();
+}
+
+
+////////////////////////////////////////////////////////////
+GlResource::~GlResource()
+{
+ priv::GlContext::cleanupResource();
+}
+
+
+////////////////////////////////////////////////////////////
+void GlResource::registerContextDestroyCallback(ContextDestroyCallback callback, void* arg)
+{
+ priv::GlContext::registerContextDestroyCallback(callback, arg);
+}
+
+
+////////////////////////////////////////////////////////////
+GlResource::TransientContextLock::TransientContextLock()
+{
+ priv::GlContext::acquireTransientContext();
+}
+
+
+////////////////////////////////////////////////////////////
+GlResource::TransientContextLock::~TransientContextLock()
+{
+ priv::GlContext::releaseTransientContext();
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/InputImpl.hpp b/src/SFML/Window/InputImpl.hpp
new file mode 100644
index 0000000..305fc09
--- /dev/null
+++ b/src/SFML/Window/InputImpl.hpp
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_INPUTIMPL_HPP
+#define SFML_INPUTIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+ #include <SFML/Window/Win32/InputImpl.hpp>
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+ #include <SFML/Window/Unix/InputImpl.hpp>
+#elif defined(SFML_SYSTEM_MACOS)
+ #include <SFML/Window/OSX/InputImpl.hpp>
+#elif defined(SFML_SYSTEM_IOS)
+ #include <SFML/Window/iOS/InputImpl.hpp>
+#elif defined(SFML_SYSTEM_ANDROID)
+ #include <SFML/Window/Android/InputImpl.hpp>
+#endif
+
+
+#endif // SFML_INPUTIMPL_HPP
diff --git a/src/SFML/Window/Joystick.cpp b/src/SFML/Window/Joystick.cpp
new file mode 100644
index 0000000..62793f1
--- /dev/null
+++ b/src/SFML/Window/Joystick.cpp
@@ -0,0 +1,92 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/JoystickManager.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+bool Joystick::isConnected(unsigned int joystick)
+{
+ return priv::JoystickManager::getInstance().getState(joystick).connected;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Joystick::getButtonCount(unsigned int joystick)
+{
+ return priv::JoystickManager::getInstance().getCapabilities(joystick).buttonCount;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Joystick::hasAxis(unsigned int joystick, Axis axis)
+{
+ return priv::JoystickManager::getInstance().getCapabilities(joystick).axes[axis];
+}
+
+
+////////////////////////////////////////////////////////////
+bool Joystick::isButtonPressed(unsigned int joystick, unsigned int button)
+{
+ return priv::JoystickManager::getInstance().getState(joystick).buttons[button];
+}
+
+
+////////////////////////////////////////////////////////////
+float Joystick::getAxisPosition(unsigned int joystick, Axis axis)
+{
+ return priv::JoystickManager::getInstance().getState(joystick).axes[axis];
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification Joystick::getIdentification(unsigned int joystick)
+{
+ return priv::JoystickManager::getInstance().getIdentification(joystick);
+}
+
+
+////////////////////////////////////////////////////////////
+void Joystick::update()
+{
+ return priv::JoystickManager::getInstance().update();
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification::Identification() :
+name ("No Joystick"),
+vendorId (0),
+productId(0)
+{
+
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/JoystickImpl.hpp b/src/SFML/Window/JoystickImpl.hpp
new file mode 100644
index 0000000..e4fd7e2
--- /dev/null
+++ b/src/SFML/Window/JoystickImpl.hpp
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKIMPL_HPP
+#define SFML_JOYSTICKIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/System/String.hpp>
+#include <algorithm>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Structure holding a joystick's information
+///
+////////////////////////////////////////////////////////////
+struct JoystickCaps
+{
+ JoystickCaps()
+ {
+ buttonCount = 0;
+ std::fill(axes, axes + Joystick::AxisCount, false);
+ }
+
+ unsigned int buttonCount; ///< Number of buttons supported by the joystick
+ bool axes[Joystick::AxisCount]; ///< Support for each axis
+};
+
+
+////////////////////////////////////////////////////////////
+/// \brief Structure holding a joystick's state
+///
+////////////////////////////////////////////////////////////
+struct JoystickState
+{
+ JoystickState()
+ {
+ connected = false;
+ std::fill(axes, axes + Joystick::AxisCount, 0.f);
+ std::fill(buttons, buttons + Joystick::ButtonCount, false);
+ }
+
+ bool connected; ///< Is the joystick currently connected?
+ float axes[Joystick::AxisCount]; ///< Position of each axis, in range [-100, 100]
+ bool buttons[Joystick::ButtonCount]; ///< Status of each button (true = pressed)
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Window/Win32/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_LINUX)
+
+ #include <SFML/Window/Unix/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_FREEBSD)
+
+ #include <SFML/Window/FreeBSD/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_OPENBSD)
+
+ #include <SFML/Window/OpenBSD/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_MACOS)
+
+ #include <SFML/Window/OSX/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_IOS)
+
+ #include <SFML/Window/iOS/JoystickImpl.hpp>
+
+#elif defined(SFML_SYSTEM_ANDROID)
+
+ #include <SFML/Window/Android/JoystickImpl.hpp>
+
+#endif
+
+
+#endif // SFML_JOYSTICKIMPL_HPP
diff --git a/src/SFML/Window/JoystickManager.cpp b/src/SFML/Window/JoystickManager.cpp
new file mode 100644
index 0000000..1574faa
--- /dev/null
+++ b/src/SFML/Window/JoystickManager.cpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickManager.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+JoystickManager& JoystickManager::getInstance()
+{
+ static JoystickManager instance;
+ return instance;
+}
+
+
+////////////////////////////////////////////////////////////
+const JoystickCaps& JoystickManager::getCapabilities(unsigned int joystick) const
+{
+ return m_joysticks[joystick].capabilities;
+}
+
+
+////////////////////////////////////////////////////////////
+const JoystickState& JoystickManager::getState(unsigned int joystick) const
+{
+ return m_joysticks[joystick].state;
+}
+
+
+////////////////////////////////////////////////////////////
+const Joystick::Identification& JoystickManager::getIdentification(unsigned int joystick) const
+{
+ return m_joysticks[joystick].identification;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickManager::update()
+{
+ for (int i = 0; i < Joystick::Count; ++i)
+ {
+ Item& item = m_joysticks[i];
+
+ if (item.state.connected)
+ {
+ // Get the current state of the joystick
+ item.state = item.joystick.update();
+
+ // Check if it's still connected
+ if (!item.state.connected)
+ {
+ item.joystick.close();
+ item.capabilities = JoystickCaps();
+ item.state = JoystickState();
+ item.identification = Joystick::Identification();
+ }
+ }
+ else
+ {
+ // Check if the joystick was connected since last update
+ if (JoystickImpl::isConnected(i))
+ {
+ if (item.joystick.open(i))
+ {
+ item.capabilities = item.joystick.getCapabilities();
+ item.state = item.joystick.update();
+ item.identification = item.joystick.getIdentification();
+ }
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickManager::JoystickManager()
+{
+ JoystickImpl::initialize();
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickManager::~JoystickManager()
+{
+ for (int i = 0; i < Joystick::Count; ++i)
+ {
+ if (m_joysticks[i].state.connected)
+ m_joysticks[i].joystick.close();
+ }
+
+ JoystickImpl::cleanup();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/JoystickManager.hpp b/src/SFML/Window/JoystickManager.hpp
new file mode 100644
index 0000000..08692cd
--- /dev/null
+++ b/src/SFML/Window/JoystickManager.hpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKMANAGER_HPP
+#define SFML_JOYSTICKMANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Global joystick manager
+///
+////////////////////////////////////////////////////////////
+class JoystickManager : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the global unique instance of the manager
+ ///
+ /// \return Unique instance of the joystick manager
+ ///
+ ////////////////////////////////////////////////////////////
+ static JoystickManager& getInstance();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the capabilities for an open joystick
+ ///
+ /// \param joystick Index of the joystick
+ ///
+ /// \return Capabilities of the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ const JoystickCaps& getCapabilities(unsigned int joystick) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current state of an open joystick
+ ///
+ /// \param joystick Index of the joystick
+ ///
+ /// \return Current state of the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ const JoystickState& getState(unsigned int joystick) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the identification for an open joystick
+ ///
+ /// \param joystick Index of the joystick
+ ///
+ /// \return Identification for the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ const Joystick::Identification& getIdentification(unsigned int joystick) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the state of all the joysticks
+ ///
+ ////////////////////////////////////////////////////////////
+ void update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~JoystickManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Joystick information and state
+ ///
+ ////////////////////////////////////////////////////////////
+ struct Item
+ {
+ JoystickImpl joystick; ///< Joystick implementation
+ JoystickState state; ///< The current joystick state
+ JoystickCaps capabilities; ///< The joystick capabilities
+ Joystick::Identification identification; ///< The joystick identification
+ };
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Item m_joysticks[Joystick::Count]; ///< Joysticks information and state
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKMANAGER_HPP
diff --git a/src/SFML/Window/Keyboard.cpp b/src/SFML/Window/Keyboard.cpp
new file mode 100644
index 0000000..14cda19
--- /dev/null
+++ b/src/SFML/Window/Keyboard.cpp
@@ -0,0 +1,47 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/InputImpl.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+bool Keyboard::isKeyPressed(Key key)
+{
+ return priv::InputImpl::isKeyPressed(key);
+}
+
+
+////////////////////////////////////////////////////////////
+void Keyboard::setVirtualKeyboardVisible(bool visible)
+{
+ priv::InputImpl::setVirtualKeyboardVisible(visible);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/Mouse.cpp b/src/SFML/Window/Mouse.cpp
new file mode 100644
index 0000000..862dc69
--- /dev/null
+++ b/src/SFML/Window/Mouse.cpp
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Mouse.hpp>
+#include <SFML/Window/InputImpl.hpp>
+#include <SFML/Window/Window.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+bool Mouse::isButtonPressed(Button button)
+{
+ return priv::InputImpl::isMouseButtonPressed(button);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i Mouse::getPosition()
+{
+ return priv::InputImpl::getMousePosition();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i Mouse::getPosition(const Window& relativeTo)
+{
+ return priv::InputImpl::getMousePosition(relativeTo);
+}
+
+
+////////////////////////////////////////////////////////////
+void Mouse::setPosition(const Vector2i& position)
+{
+ priv::InputImpl::setMousePosition(position);
+}
+
+
+////////////////////////////////////////////////////////////
+void Mouse::setPosition(const Vector2i& position, const Window& relativeTo)
+{
+ priv::InputImpl::setMousePosition(position, relativeTo);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h
new file mode 100644
index 0000000..020fa22
--- /dev/null
+++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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 Ensure one autorelease pool is available on this thread
+///
+////////////////////////////////////////////////////////////
+void ensureThreadHasPool(void);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Drain the thread's pool but keep it alive
+///
+////////////////////////////////////////////////////////////
+void drainThreadPool(void);
diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm
new file mode 100644
index 0000000..6b341b2
--- /dev/null
+++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm
@@ -0,0 +1,105 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <cassert>
+#include <pthread.h>
+
+#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
+#import <Foundation/Foundation.h>
+
+
+////////////////////////////////////////////////////////////
+/// Here we manage one and only one pool by thread. This prevents draining one
+/// pool and making other pools invalid which can lead to a crash on 10.5 and an
+/// annoying message on 10.6 (*** attempt to pop an unknown autorelease pool).
+///
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Private data
+////////////////////////////////////////////////////////////
+static pthread_key_t poolKey;
+static pthread_once_t initOnceToken = PTHREAD_ONCE_INIT;
+
+
+////////////////////////////////////////////////////////////
+/// \brief (local function) Drain one more time the pool
+/// but this time don't create a new one.
+///
+////////////////////////////////////////////////////////////
+static void destroyPool(void* data)
+{
+ NSAutoreleasePool* pool = (NSAutoreleasePool*)data;
+ [pool drain];
+}
+
+
+////////////////////////////////////////////////////////////
+/// \brief (local function) Init the pthread key for the pool
+///
+////////////////////////////////////////////////////////////
+static void createPoolKey(void)
+{
+ pthread_key_create(&poolKey, destroyPool);
+}
+
+
+////////////////////////////////////////////////////////////
+/// \brief (local function) Store a new pool for this thread
+///
+////////////////////////////////////////////////////////////
+static void createNewPool(void)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ pthread_setspecific(poolKey, pool);
+}
+
+
+////////////////////////////////////////////////////////////
+void ensureThreadHasPool(void)
+{
+ pthread_once(&initOnceToken, createPoolKey);
+ if (pthread_getspecific(poolKey) == NULL)
+ {
+ createNewPool();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void drainThreadPool(void)
+{
+ void* data = pthread_getspecific(poolKey);
+ assert(data != NULL);
+
+ // Drain the pool but keep it alive by creating a new one
+ destroyPool(data);
+ createNewPool();
+}
+
diff --git a/src/SFML/Window/OSX/ClipboardImpl.hpp b/src/SFML/Window/OSX/ClipboardImpl.hpp
new file mode 100644
index 0000000..d3aabef
--- /dev/null
+++ b/src/SFML/Window/OSX/ClipboardImpl.hpp
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPLCOCOA_HPP
+#define SFML_CLIPBOARDIMPLCOCOA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class ClipboardImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \param text sf::String object containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARDIMPLCOCOA_HPP
+
diff --git a/src/SFML/Window/OSX/ClipboardImpl.mm b/src/SFML/Window/OSX/ClipboardImpl.mm
new file mode 100644
index 0000000..a14d871
--- /dev/null
+++ b/src/SFML/Window/OSX/ClipboardImpl.mm
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/ClipboardImpl.hpp>
+
+#import <AppKit/AppKit.h>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getString()
+{
+ NSPasteboard* pboard = [NSPasteboard generalPasteboard];
+ NSString* data = [pboard stringForType:NSPasteboardTypeString];
+
+ char const* utf8 = [data cStringUsingEncoding:NSUTF8StringEncoding];
+ NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ return String::fromUtf8(utf8, utf8 + length);
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setString(const String& text)
+{
+ std::basic_string<Uint8> utf8 = text.toUtf8();
+ NSString* data = [[NSString alloc] initWithBytes:utf8.data()
+ length:utf8.length()
+ encoding:NSUTF8StringEncoding];
+
+ NSPasteboard* pboard = [NSPasteboard generalPasteboard];
+ [pboard declareTypes:@[NSPasteboardTypeString] owner:nil];
+ [pboard setString:data forType:NSPasteboardTypeString];
+
+ [data release];
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/CursorImpl.hpp b/src/SFML/Window/OSX/CursorImpl.hpp
new file mode 100644
index 0000000..43af792
--- /dev/null
+++ b/src/SFML/Window/OSX/CursorImpl.hpp
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_CURSORIMPLOSX_HPP
+#define SFML_CURSORIMPLOSX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+
+////////////////////////////////////////////////////////////
+// Predefine OBJ-C classes
+////////////////////////////////////////////////////////////
+#ifdef __OBJC__
+
+@class NSCursor;
+typedef NSCursor* NSCursorRef;
+
+#else // If C++
+
+typedef void* NSCursorRef;
+
+#endif
+
+namespace sf
+{
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Mac OS X implementation of Cursor
+///
+////////////////////////////////////////////////////////////
+class CursorImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Refer to sf::Cursor::Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// Refer to sf::Cursor::~Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ ~CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// Refer to sf::Cursor::loadFromPixels().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Refer to sf::Cursor::loadFromSystem().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Cursor::Type type);
+
+private:
+
+ friend class WindowImplCocoa;
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ NSCursorRef m_cursor; ///< System cursor handle
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_CURSORIMPLOSX_HPP
diff --git a/src/SFML/Window/OSX/CursorImpl.mm b/src/SFML/Window/OSX/CursorImpl.mm
new file mode 100644
index 0000000..ed905ef
--- /dev/null
+++ b/src/SFML/Window/OSX/CursorImpl.mm
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/CursorImpl.hpp>
+
+#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
+#import <SFML/Window/OSX/NSImage+raw.h>
+#import <AppKit/AppKit.h>
+
+namespace
+{
+
+////////////////////////////////////////////////////////////
+NSCursor* loadFromSelector(SEL selector)
+{
+ // The caller is responsible for retaining the cursor.
+ if ([NSCursor respondsToSelector:selector])
+ return [NSCursor performSelector:selector];
+ else
+ return nil;
+}
+
+}
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+CursorImpl::CursorImpl() :
+m_cursor(nil)
+{
+ // Just ask for a pool
+ ensureThreadHasPool();
+}
+
+
+////////////////////////////////////////////////////////////
+CursorImpl::~CursorImpl()
+{
+ [m_cursor release];
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ [m_cursor release];
+
+ NSSize nssize = NSMakeSize(size.x, size.y);
+ NSImage* image = [NSImage imageWithRawData:pixels andSize:nssize];
+ NSPoint nshotspot = NSMakePoint(hotspot.x, hotspot.y);
+
+ m_cursor = [[NSCursor alloc] initWithImage:image hotSpot:nshotspot];
+
+ return m_cursor != nil;
+}
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromSystem(Cursor::Type type)
+{
+ [m_cursor release];
+
+ switch (type)
+ {
+ default: return false;
+
+ case Cursor::Arrow: m_cursor = [NSCursor arrowCursor]; break;
+ case Cursor::Text: m_cursor = [NSCursor IBeamCursor]; break;
+ case Cursor::Hand: m_cursor = [NSCursor pointingHandCursor]; break;
+ case Cursor::SizeHorizontal: m_cursor = [NSCursor resizeLeftRightCursor]; break;
+ case Cursor::SizeVertical: m_cursor = [NSCursor resizeUpDownCursor]; break;
+ case Cursor::Cross: m_cursor = [NSCursor crosshairCursor]; break;
+ case Cursor::NotAllowed: m_cursor = [NSCursor operationNotAllowedCursor]; break;
+
+ // These cursor types are undocumented, may not be available on some platforms
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundeclared-selector"
+ case Cursor::SizeBottomLeftTopRight:
+ m_cursor = loadFromSelector(@selector(_windowResizeNorthEastSouthWestCursor));
+ break;
+
+ case Cursor::SizeTopLeftBottomRight:
+ m_cursor = loadFromSelector(@selector(_windowResizeNorthWestSouthEastCursor));
+ break;
+
+ case Cursor::Help:
+ m_cursor = loadFromSelector(@selector(_helpCursor));
+ break;
+#pragma clang diagnostic pop
+ }
+
+ if (m_cursor)
+ [m_cursor retain];
+
+ return m_cursor != nil;
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/HIDInputManager.hpp b/src/SFML/Window/OSX/HIDInputManager.hpp
new file mode 100644
index 0000000..388d008
--- /dev/null
+++ b/src/SFML/Window/OSX/HIDInputManager.hpp
@@ -0,0 +1,236 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_HIDINPUTMANAGER_HPP
+#define SFML_HIDINPUTMANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <Carbon/Carbon.h>
+#include <IOKit/hid/IOHIDDevice.h>
+#include <IOKit/hid/IOHIDManager.h>
+#include <vector>
+
+namespace sf
+{
+namespace priv
+{
+
+typedef std::vector<IOHIDElementRef> IOHIDElements;
+
+////////////////////////////////////////////////////////////
+/// \brief sf::priv::InputImpl helper
+///
+/// This class manage as a singleton instance the keyboard state.
+/// Its purpose is to help sf::priv::InputImpl class.
+///
+////////////////////////////////////////////////////////////
+class HIDInputManager : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the unique instance of the class
+ ///
+ /// \note Private use only
+ ///
+ /// \return Reference to the HIDInputManager instance
+ ///
+ ////////////////////////////////////////////////////////////
+ static HIDInputManager& getInstance();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isKeyPressed(Keyboard::Key key);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the usb location ID of a given device
+ ///
+ /// This location ID is unique and can be used a usb port identifier
+ ///
+ /// \param device HID device to query
+ /// \return the device's location ID or 0 if something went wrong
+ ///
+ ////////////////////////////////////////////////////////////
+ static long getLocationID(IOHIDDeviceRef device);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a mask (dictionary) for an IOHIDManager
+ ///
+ /// \param page HID page
+ /// \param usage HID usage page
+ /// \return a retained CFDictionaryRef
+ ///
+ ////////////////////////////////////////////////////////////
+ static CFDictionaryRef copyDevicesMask(UInt32 page, UInt32 usage);
+
+ ////////////////////////////////////////////////////////////
+ /// Try to convert a character into a SFML key code.
+ ///
+ /// Return sf::Keyboard::Unknown if it doesn't match any 'localized' keys.
+ ///
+ /// By 'localized' I mean keys that depend on the keyboard layout
+ /// and might not be the same as the US keycode in some country
+ /// (e.g. the keys 'Y' and 'Z' are switched on QWERTZ keyboard and
+ /// US keyboard layouts.)
+ ///
+ ////////////////////////////////////////////////////////////
+ static Keyboard::Key localizedKeys(UniChar ch);
+
+ ////////////////////////////////////////////////////////////
+ /// Try to convert a virtual keycode into a SFML key code.
+ ///
+ /// Return sf::Keyboard::Unknown if the keycode is unknown.
+ ///
+ ////////////////////////////////////////////////////////////
+ static Keyboard::Key nonLocalizedKeys(UniChar virtualKeycode);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ HIDInputManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~HIDInputManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Initialize the keyboard part of this class
+ ///
+ /// If something went wrong freeUp is called
+ ///
+ ////////////////////////////////////////////////////////////
+ void initializeKeyboard();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load the given keyboard into m_keys
+ ///
+ /// If the given keyboard has no key this function simply
+ /// returns. freeUp is _not_ called because this is not fatal.
+ ///
+ /// \param keyboard Keyboard to load
+ ///
+ ////////////////////////////////////////////////////////////
+ void loadKeyboard(IOHIDDeviceRef keyboard);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load the given key into m_keys
+ ///
+ /// freeUp is _not_ called by this function.
+ ///
+ /// \param key Key to load
+ ///
+ ////////////////////////////////////////////////////////////
+ void loadKey(IOHIDElementRef key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Release all resources
+ ///
+ /// Close all connections to any devices, if required
+ /// Set m_isValid to false
+ ///
+ ////////////////////////////////////////////////////////////
+ void freeUp();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Filter the devices and return them
+ ///
+ /// freeUp is _not_ called by this function.
+ ///
+ /// \param page HID page like kHIDPage_GenericDesktop
+ /// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
+ /// \return a retained CFSetRef of IOHIDDeviceRef or NULL
+ ///
+ ////////////////////////////////////////////////////////////
+ CFSetRef copyDevices(UInt32 page, UInt32 usage);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param elements HID elements mapping to this key
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ /// \see isKeyPressed, isMouseButtonPressed
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isPressed(IOHIDElements& elements);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a HID key usage to its corresponding virtual code
+ ///
+ /// See IOHIDUsageTables.h
+ ///
+ /// \param usage Any kHIDUsage_Keyboard* usage
+ /// \return the virtual code associate with the given HID key usage
+ /// or 0xff if it is associate with no virtual code
+ ///
+ ////////////////////////////////////////////////////////////
+ static UInt8 usageToVirtualCode(UInt32 usage);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ bool m_isValid; ///< If any error occurs this variable is false
+ CFDataRef m_layoutData; ///< CFData containing the layout
+ UCKeyboardLayout* m_layout; ///< Current Keyboard Layout
+ IOHIDManagerRef m_manager; ///< HID Manager
+
+ IOHIDElements m_keys[Keyboard::KeyCount]; ///< All the keys on any connected keyboard
+
+ ////////////////////////////////////////////////////////////
+ /// m_keys' index corresponds to sf::Keyboard::Key enum.
+ /// if no key is assigned with key XYZ then m_keys[XYZ].size() == 0.
+ /// if there are several keyboards connected and several HID keys associate
+ /// with the same sf::Keyboard::Key then m_keys[XYZ] contains all these
+ /// HID keys.
+ ///
+ ////////////////////////////////////////////////////////////
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif
diff --git a/src/SFML/Window/OSX/HIDInputManager.mm b/src/SFML/Window/OSX/HIDInputManager.mm
new file mode 100644
index 0000000..a332932
--- /dev/null
+++ b/src/SFML/Window/OSX/HIDInputManager.mm
@@ -0,0 +1,870 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/HIDInputManager.hpp>
+#include <SFML/System/Err.hpp>
+#include <AppKit/AppKit.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+HIDInputManager& HIDInputManager::getInstance()
+{
+ static HIDInputManager instance;
+ return instance;
+}
+
+
+////////////////////////////////////////////////////////////
+bool HIDInputManager::isKeyPressed(Keyboard::Key key)
+{
+ return isPressed(m_keys[key]);
+}
+
+
+////////////////////////////////////////////////////////////
+long HIDInputManager::getLocationID(IOHIDDeviceRef device)
+{
+ long loc = 0;
+
+ // Get a unique ID: its USB location ID
+ CFTypeRef typeRef = IOHIDDeviceGetProperty(device,
+ CFSTR(kIOHIDLocationIDKey));
+ if (!typeRef || (CFGetTypeID(typeRef) != CFNumberGetTypeID()))
+ return 0;
+
+ CFNumberRef locRef = (CFNumberRef)typeRef;
+
+ if (!CFNumberGetValue(locRef, kCFNumberLongType, &loc))
+ return 0;
+
+ return loc;
+}
+
+
+////////////////////////////////////////////////////////////
+CFDictionaryRef HIDInputManager::copyDevicesMask(UInt32 page, UInt32 usage)
+{
+ // Create the dictionary.
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ // Add the page value.
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
+ CFRelease(value);
+
+ // Add the usage value (which is only valid if page value exists).
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
+ CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
+ CFRelease(value);
+
+ return dict;
+}
+
+
+////////////////////////////////////////////////////////////
+HIDInputManager::HIDInputManager() :
+m_isValid(true),
+m_layoutData(0),
+m_layout(0),
+m_manager(0)
+{
+ // Get the current keyboard layout
+ TISInputSourceRef tis = TISCopyCurrentKeyboardLayoutInputSource();
+ m_layoutData = (CFDataRef)TISGetInputSourceProperty(tis,
+ kTISPropertyUnicodeKeyLayoutData);
+
+ if (m_layoutData == 0)
+ {
+ sf::err() << "Cannot get the keyboard layout" << std::endl;
+ freeUp();
+ return;
+ }
+
+ // Keep a reference for ourself
+ CFRetain(m_layoutData);
+ m_layout = (UCKeyboardLayout *)CFDataGetBytePtr(m_layoutData);
+
+ // The TIS is no more needed
+ CFRelease(tis);
+
+ // Create an HID Manager reference
+ m_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+
+ // Open the HID Manager reference
+ IOReturn openStatus = IOHIDManagerOpen(m_manager, kIOHIDOptionsTypeNone);
+
+ if (openStatus != kIOReturnSuccess)
+ {
+ sf::err() << "Error when opening the HID manager" << std::endl;
+ freeUp();
+ return;
+ }
+
+ // Initialize the keyboard
+ initializeKeyboard();
+}
+
+
+////////////////////////////////////////////////////////////
+HIDInputManager::~HIDInputManager()
+{
+ freeUp();
+}
+
+
+void HIDInputManager::initializeKeyboard()
+{
+ ////////////////////////////////////////////////////////////
+ // The purpose of this function is to initialize m_keys so we can get
+ // the associate IOHIDElementRef with a sf::Keyboard::Key in ~constant~ time.
+
+ // Get only keyboards
+ CFSetRef keyboards = copyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
+ if (keyboards == NULL)
+ {
+ sf::err() << "No keyboard detected by the HID manager!" << std::endl;
+ freeUp();
+ return;
+ }
+
+ CFIndex keyboardCount = CFSetGetCount(keyboards); // >= 1 (asserted by copyDevices)
+
+ // Get an iterable array
+ CFTypeRef devicesArray[keyboardCount];
+ CFSetGetValues(keyboards, devicesArray);
+
+ for (CFIndex i = 0; i < keyboardCount; ++i)
+ {
+ IOHIDDeviceRef keyboard = (IOHIDDeviceRef)devicesArray[i];
+ loadKeyboard(keyboard);
+ }
+
+ // Release unused stuff
+ CFRelease(keyboards);
+
+ ////////////////////////////////////////////////////////////
+ // At this point m_keys is filled with as many IOHIDElementRef as possible
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDInputManager::loadKeyboard(IOHIDDeviceRef keyboard)
+{
+ CFArrayRef keys = IOHIDDeviceCopyMatchingElements(keyboard,
+ NULL,
+ kIOHIDOptionsTypeNone);
+ if (keys == NULL)
+ {
+ sf::err() << "We got a keyboard without any keys (1)" << std::endl;
+ return;
+ }
+
+ // How many elements are there?
+ CFIndex keysCount = CFArrayGetCount(keys);
+
+ if (keysCount == 0)
+ {
+ sf::err() << "We got a keyboard without any keys (2)" << std::endl;
+ CFRelease(keys);
+ return;
+ }
+
+ // Go through all connected elements.
+ for (CFIndex i = 0; i < keysCount; ++i)
+ {
+ IOHIDElementRef aKey = (IOHIDElementRef) CFArrayGetValueAtIndex(keys, i);
+
+ // Skip non-matching keys elements
+ if (IOHIDElementGetUsagePage(aKey) != kHIDPage_KeyboardOrKeypad)
+ continue;
+
+ loadKey(aKey);
+ }
+
+ // Release unused stuff
+ CFRelease(keys);
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDInputManager::loadKey(IOHIDElementRef key)
+{
+ // Get its virtual code
+ UInt32 usageCode = IOHIDElementGetUsage(key);
+ UInt8 virtualCode = usageToVirtualCode(usageCode);
+
+ if (virtualCode == 0xff)
+ return; // no corresponding virtual code -> skip
+
+ // Now translate the virtual code to Unicode according to
+ // the current keyboard layout
+
+ UInt32 deadKeyState = 0;
+ // Unicode string length is usually less or equal to 4
+ UniCharCount maxStringLength = 4;
+ UniCharCount actualStringLength = 0;
+ UniChar unicodeString[maxStringLength];
+
+ OSStatus error;
+
+ error = UCKeyTranslate(m_layout, // current layout
+ virtualCode, // our key
+ kUCKeyActionDown, // or kUCKeyActionUp ?
+ 0x100, // no modifiers
+ LMGetKbdType(), // keyboard's type
+ kUCKeyTranslateNoDeadKeysBit,// some sort of option
+ &deadKeyState, // unused stuff
+ maxStringLength, // our memory limit
+ &actualStringLength, // length of what we get
+ unicodeString); // what we get
+
+ if (error == noErr)
+ {
+ // Translation went fine
+
+ // The corresponding SFML key code
+ Keyboard::Key code = Keyboard::Unknown; // KeyCound means 'none'
+
+ // First we look if the key down is from a list of characters
+ // that depend on keyboard localization
+ if (actualStringLength > 0)
+ code = localizedKeys(unicodeString[0]);
+
+ // The key is not a localized one so we try to find a
+ // corresponding code through virtual key code
+ if (code == Keyboard::Unknown)
+ code = nonLocalizedKeys(virtualCode);
+
+ // A code was found, wonderful!
+ if (code != Keyboard::Unknown)
+ {
+ // Ok, everything went fine. Now we have a unique
+ // corresponding sf::Keyboard::Key to one IOHIDElementRef
+ m_keys[code].push_back(key);
+
+ // And don't forget to keep the reference alive for our usage
+ CFRetain(m_keys[code].back());
+ }
+
+ ////////////////////////////////////////////////////////////
+ // These are known to be unbound:
+ // Supposed Virtual | HID | Supposed Key
+ // ===============================================
+ // 0x1b | 0x2d | Hyphen
+ // 0x39 | 0x39 | CapsLock
+ // 0x47 | 0x53 | NumLock
+ // 0x6e | 0x65 | Application
+ // 0x4c | 0x77 | Select
+
+ //if (code == Keyboard::Unknown) { // The key is unknown.
+ // sf::err() << "This is an unknown key. Virtual key code is 0x"
+ // << std::hex
+ // << (UInt32)virtualCode
+ // << " and HID usage code is 0x"
+ // << usageCode
+ // << std::dec
+ // << "."
+ // << std::endl;
+ //}
+
+ } /* if (error == noErr) */
+ else
+ {
+ sf::err() << "Cannot translate the virtual key code, error: "
+ << error
+ << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDInputManager::freeUp()
+{
+ m_isValid = false;
+
+ if (m_layoutData != 0)
+ CFRelease(m_layoutData);
+ m_layoutData = 0;
+ // Do not release m_layout! It is owned by m_layoutData.
+ if (m_manager != 0)
+ CFRelease(m_manager);
+ m_manager = 0;
+
+ for (unsigned int i = 0; i < Keyboard::KeyCount; ++i)
+ {
+ for (IOHIDElements::iterator it = m_keys[i].begin(); it != m_keys[i].end(); ++it)
+ CFRelease(*it);
+
+ m_keys[i].clear();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+CFSetRef HIDInputManager::copyDevices(UInt32 page, UInt32 usage)
+{
+ // Filter and keep only the requested devices
+ CFDictionaryRef mask = copyDevicesMask(page, usage);
+
+ IOHIDManagerSetDeviceMatching(m_manager, mask);
+
+ CFRelease(mask);
+ mask = 0;
+
+ CFSetRef devices = IOHIDManagerCopyDevices(m_manager);
+ if (devices == NULL)
+ return NULL;
+
+ // Is there at least one device?
+ CFIndex deviceCount = CFSetGetCount(devices);
+ if (deviceCount < 1)
+ {
+ CFRelease(devices);
+ return NULL;
+ }
+
+ return devices;
+}
+
+bool HIDInputManager::isPressed(IOHIDElements& elements)
+{
+ if (!m_isValid)
+ return false;
+
+ // state = true if at least one corresponding HID button is pressed
+ bool state = false;
+
+ for (IOHIDElements::iterator it = elements.begin(); it != elements.end(); /* noop */)
+ {
+ IOHIDValueRef value = 0;
+
+ IOHIDDeviceRef device = IOHIDElementGetDevice(*it);
+ IOHIDDeviceGetValue(device, *it, &value);
+
+ if (!value)
+ {
+ // This means some kind of error / disconnection so we remove this
+ // element from our buttons
+ CFRelease(*it);
+ it = elements.erase(it);
+ }
+ else if (IOHIDValueGetIntegerValue(value) == 1)
+ {
+ // This means the button is pressed
+ state = true;
+ break; // Stop here
+ }
+ else
+ {
+ // This means the button is released
+ ++it;
+ }
+ }
+
+ return state;
+}
+
+
+////////////////////////////////////////////////////////////
+UInt8 HIDInputManager::usageToVirtualCode(UInt32 usage)
+{
+ // Some usage key doesn't have any corresponding virtual
+ // code or it was not found (return 0xff).
+ switch (usage)
+ {
+ case kHIDUsage_KeyboardErrorRollOver: return 0xff;
+ case kHIDUsage_KeyboardPOSTFail: return 0xff;
+ case kHIDUsage_KeyboardErrorUndefined: return 0xff;
+
+ case kHIDUsage_KeyboardA: return 0x00;
+ case kHIDUsage_KeyboardB: return 0x0b;
+ case kHIDUsage_KeyboardC: return 0x08;
+ case kHIDUsage_KeyboardD: return 0x02;
+ case kHIDUsage_KeyboardE: return 0x0e;
+ case kHIDUsage_KeyboardF: return 0x03;
+ case kHIDUsage_KeyboardG: return 0x05;
+ case kHIDUsage_KeyboardH: return 0x04;
+ case kHIDUsage_KeyboardI: return 0x22;
+ case kHIDUsage_KeyboardJ: return 0x26;
+ case kHIDUsage_KeyboardK: return 0x28;
+ case kHIDUsage_KeyboardL: return 0x25;
+ case kHIDUsage_KeyboardM: return 0x2e;
+ case kHIDUsage_KeyboardN: return 0x2d;
+ case kHIDUsage_KeyboardO: return 0x1f;
+ case kHIDUsage_KeyboardP: return 0x23;
+ case kHIDUsage_KeyboardQ: return 0x0c;
+ case kHIDUsage_KeyboardR: return 0x0f;
+ case kHIDUsage_KeyboardS: return 0x01;
+ case kHIDUsage_KeyboardT: return 0x11;
+ case kHIDUsage_KeyboardU: return 0x20;
+ case kHIDUsage_KeyboardV: return 0x09;
+ case kHIDUsage_KeyboardW: return 0x0d;
+ case kHIDUsage_KeyboardX: return 0x07;
+ case kHIDUsage_KeyboardY: return 0x10;
+ case kHIDUsage_KeyboardZ: return 0x06;
+
+ case kHIDUsage_Keyboard1: return 0x12;
+ case kHIDUsage_Keyboard2: return 0x13;
+ case kHIDUsage_Keyboard3: return 0x14;
+ case kHIDUsage_Keyboard4: return 0x15;
+ case kHIDUsage_Keyboard5: return 0x17;
+ case kHIDUsage_Keyboard6: return 0x16;
+ case kHIDUsage_Keyboard7: return 0x1a;
+ case kHIDUsage_Keyboard8: return 0x1c;
+ case kHIDUsage_Keyboard9: return 0x19;
+ case kHIDUsage_Keyboard0: return 0x1d;
+
+ case kHIDUsage_KeyboardReturnOrEnter: return 0x24;
+ case kHIDUsage_KeyboardEscape: return 0x35;
+ case kHIDUsage_KeyboardDeleteOrBackspace: return 0x33;
+ case kHIDUsage_KeyboardTab: return 0x30;
+ case kHIDUsage_KeyboardSpacebar: return 0x31;
+ case kHIDUsage_KeyboardHyphen: return 0x1b;
+ case kHIDUsage_KeyboardEqualSign: return 0x18;
+ case kHIDUsage_KeyboardOpenBracket: return 0x21;
+ case kHIDUsage_KeyboardCloseBracket: return 0x1e;
+ case kHIDUsage_KeyboardBackslash: return 0x2a;
+ case kHIDUsage_KeyboardNonUSPound: return 0xff;
+ case kHIDUsage_KeyboardSemicolon: return 0x29;
+ case kHIDUsage_KeyboardQuote: return 0x27;
+ case kHIDUsage_KeyboardGraveAccentAndTilde: return 0x32;
+ case kHIDUsage_KeyboardComma: return 0x2b;
+ case kHIDUsage_KeyboardPeriod: return 0x2F;
+ case kHIDUsage_KeyboardSlash: return 0x2c;
+ case kHIDUsage_KeyboardCapsLock: return 0x39;
+
+ case kHIDUsage_KeyboardF1: return 0x7a;
+ case kHIDUsage_KeyboardF2: return 0x78;
+ case kHIDUsage_KeyboardF3: return 0x63;
+ case kHIDUsage_KeyboardF4: return 0x76;
+ case kHIDUsage_KeyboardF5: return 0x60;
+ case kHIDUsage_KeyboardF6: return 0x61;
+ case kHIDUsage_KeyboardF7: return 0x62;
+ case kHIDUsage_KeyboardF8: return 0x64;
+ case kHIDUsage_KeyboardF9: return 0x65;
+ case kHIDUsage_KeyboardF10: return 0x6d;
+ case kHIDUsage_KeyboardF11: return 0x67;
+ case kHIDUsage_KeyboardF12: return 0x6f;
+
+ case kHIDUsage_KeyboardPrintScreen: return 0xff;
+ case kHIDUsage_KeyboardScrollLock: return 0xff;
+ case kHIDUsage_KeyboardPause: return 0xff;
+ case kHIDUsage_KeyboardInsert: return 0x72;
+ case kHIDUsage_KeyboardHome: return 0x73;
+ case kHIDUsage_KeyboardPageUp: return 0x74;
+ case kHIDUsage_KeyboardDeleteForward: return 0x75;
+ case kHIDUsage_KeyboardEnd: return 0x77;
+ case kHIDUsage_KeyboardPageDown: return 0x79;
+
+ case kHIDUsage_KeyboardRightArrow: return 0x7c;
+ case kHIDUsage_KeyboardLeftArrow: return 0x7b;
+ case kHIDUsage_KeyboardDownArrow: return 0x7d;
+ case kHIDUsage_KeyboardUpArrow: return 0x7e;
+
+ case kHIDUsage_KeypadNumLock: return 0x47;
+ case kHIDUsage_KeypadSlash: return 0x4b;
+ case kHIDUsage_KeypadAsterisk: return 0x43;
+ case kHIDUsage_KeypadHyphen: return 0x4e;
+ case kHIDUsage_KeypadPlus: return 0x45;
+ case kHIDUsage_KeypadEnter: return 0x4c;
+
+ case kHIDUsage_Keypad1: return 0x53;
+ case kHIDUsage_Keypad2: return 0x54;
+ case kHIDUsage_Keypad3: return 0x55;
+ case kHIDUsage_Keypad4: return 0x56;
+ case kHIDUsage_Keypad5: return 0x57;
+ case kHIDUsage_Keypad6: return 0x58;
+ case kHIDUsage_Keypad7: return 0x59;
+ case kHIDUsage_Keypad8: return 0x5b;
+ case kHIDUsage_Keypad9: return 0x5c;
+ case kHIDUsage_Keypad0: return 0x52;
+
+ case kHIDUsage_KeypadPeriod: return 0x41;
+ case kHIDUsage_KeyboardNonUSBackslash: return 0xff;
+ case kHIDUsage_KeyboardApplication: return 0x6e;
+ case kHIDUsage_KeyboardPower: return 0xff;
+ case kHIDUsage_KeypadEqualSign: return 0x51;
+
+ case kHIDUsage_KeyboardF13: return 0x69;
+ case kHIDUsage_KeyboardF14: return 0x6b;
+ case kHIDUsage_KeyboardF15: return 0x71;
+ case kHIDUsage_KeyboardF16: return 0xff;
+ case kHIDUsage_KeyboardF17: return 0xff;
+ case kHIDUsage_KeyboardF18: return 0xff;
+ case kHIDUsage_KeyboardF19: return 0xff;
+ case kHIDUsage_KeyboardF20: return 0xff;
+ case kHIDUsage_KeyboardF21: return 0xff;
+ case kHIDUsage_KeyboardF22: return 0xff;
+ case kHIDUsage_KeyboardF23: return 0xff;
+ case kHIDUsage_KeyboardF24: return 0xff;
+
+ case kHIDUsage_KeyboardExecute: return 0xff;
+ case kHIDUsage_KeyboardHelp: return 0xff;
+ case kHIDUsage_KeyboardMenu: return 0x7F;
+ case kHIDUsage_KeyboardSelect: return 0x4c;
+ case kHIDUsage_KeyboardStop: return 0xff;
+ case kHIDUsage_KeyboardAgain: return 0xff;
+ case kHIDUsage_KeyboardUndo: return 0xff;
+ case kHIDUsage_KeyboardCut: return 0xff;
+ case kHIDUsage_KeyboardCopy: return 0xff;
+ case kHIDUsage_KeyboardPaste: return 0xff;
+ case kHIDUsage_KeyboardFind: return 0xff;
+
+ case kHIDUsage_KeyboardMute: return 0xff;
+ case kHIDUsage_KeyboardVolumeUp: return 0xff;
+ case kHIDUsage_KeyboardVolumeDown: return 0xff;
+
+ case kHIDUsage_KeyboardLockingCapsLock: return 0xff;
+ case kHIDUsage_KeyboardLockingNumLock: return 0xff;
+ case kHIDUsage_KeyboardLockingScrollLock: return 0xff;
+
+ case kHIDUsage_KeypadComma: return 0xff;
+ case kHIDUsage_KeypadEqualSignAS400: return 0xff;
+ case kHIDUsage_KeyboardInternational1: return 0xff;
+ case kHIDUsage_KeyboardInternational2: return 0xff;
+ case kHIDUsage_KeyboardInternational3: return 0xff;
+ case kHIDUsage_KeyboardInternational4: return 0xff;
+ case kHIDUsage_KeyboardInternational5: return 0xff;
+ case kHIDUsage_KeyboardInternational6: return 0xff;
+ case kHIDUsage_KeyboardInternational7: return 0xff;
+ case kHIDUsage_KeyboardInternational8: return 0xff;
+ case kHIDUsage_KeyboardInternational9: return 0xff;
+
+ case kHIDUsage_KeyboardLANG1: return 0xff;
+ case kHIDUsage_KeyboardLANG2: return 0xff;
+ case kHIDUsage_KeyboardLANG3: return 0xff;
+ case kHIDUsage_KeyboardLANG4: return 0xff;
+ case kHIDUsage_KeyboardLANG5: return 0xff;
+ case kHIDUsage_KeyboardLANG6: return 0xff;
+ case kHIDUsage_KeyboardLANG7: return 0xff;
+ case kHIDUsage_KeyboardLANG8: return 0xff;
+ case kHIDUsage_KeyboardLANG9: return 0xff;
+
+ case kHIDUsage_KeyboardAlternateErase: return 0xff;
+ case kHIDUsage_KeyboardSysReqOrAttention: return 0xff;
+ case kHIDUsage_KeyboardCancel: return 0xff;
+ case kHIDUsage_KeyboardClear: return 0xff;
+ case kHIDUsage_KeyboardPrior: return 0xff;
+ case kHIDUsage_KeyboardReturn: return 0xff;
+ case kHIDUsage_KeyboardSeparator: return 0xff;
+ case kHIDUsage_KeyboardOut: return 0xff;
+ case kHIDUsage_KeyboardOper: return 0xff;
+ case kHIDUsage_KeyboardClearOrAgain: return 0xff;
+ case kHIDUsage_KeyboardCrSelOrProps: return 0xff;
+ case kHIDUsage_KeyboardExSel: return 0xff;
+
+ /* 0xa5-0xdf Reserved */
+
+ case kHIDUsage_KeyboardLeftControl: return 0x3b;
+ case kHIDUsage_KeyboardLeftShift: return 0x38;
+ case kHIDUsage_KeyboardLeftAlt: return 0x3a;
+ case kHIDUsage_KeyboardLeftGUI: return 0x37;
+ case kHIDUsage_KeyboardRightControl: return 0x3e;
+ case kHIDUsage_KeyboardRightShift: return 0x3c;
+ case kHIDUsage_KeyboardRightAlt: return 0x3d;
+ case kHIDUsage_KeyboardRightGUI: return 0x36;
+
+ /* 0xe8-0xffff Reserved */
+
+ case kHIDUsage_Keyboard_Reserved: return 0xff;
+ default: return 0xff;
+ }
+}
+
+
+////////////////////////////////////////////////////////
+Keyboard::Key HIDInputManager::localizedKeys(UniChar ch)
+{
+ switch (ch)
+ {
+ case 'a':
+ case 'A': return sf::Keyboard::A;
+
+ case 'b':
+ case 'B': return sf::Keyboard::B;
+
+ case 'c':
+ case 'C': return sf::Keyboard::C;
+
+ case 'd':
+ case 'D': return sf::Keyboard::D;
+
+ case 'e':
+ case 'E': return sf::Keyboard::E;
+
+ case 'f':
+ case 'F': return sf::Keyboard::F;
+
+ case 'g':
+ case 'G': return sf::Keyboard::G;
+
+ case 'h':
+ case 'H': return sf::Keyboard::H;
+
+ case 'i':
+ case 'I': return sf::Keyboard::I;
+
+ case 'j':
+ case 'J': return sf::Keyboard::J;
+
+ case 'k':
+ case 'K': return sf::Keyboard::K;
+
+ case 'l':
+ case 'L': return sf::Keyboard::L;
+
+ case 'm':
+ case 'M': return sf::Keyboard::M;
+
+ case 'n':
+ case 'N': return sf::Keyboard::N;
+
+ case 'o':
+ case 'O': return sf::Keyboard::O;
+
+ case 'p':
+ case 'P': return sf::Keyboard::P;
+
+ case 'q':
+ case 'Q': return sf::Keyboard::Q;
+
+ case 'r':
+ case 'R': return sf::Keyboard::R;
+
+ case 's':
+ case 'S': return sf::Keyboard::S;
+
+ case 't':
+ case 'T': return sf::Keyboard::T;
+
+ case 'u':
+ case 'U': return sf::Keyboard::U;
+
+ case 'v':
+ case 'V': return sf::Keyboard::V;
+
+ case 'w':
+ case 'W': return sf::Keyboard::W;
+
+ case 'x':
+ case 'X': return sf::Keyboard::X;
+
+ case 'y':
+ case 'Y': return sf::Keyboard::Y;
+
+ case 'z':
+ case 'Z': return sf::Keyboard::Z;
+
+ // The key is not 'localized'.
+ default: return sf::Keyboard::Unknown;
+ }
+}
+
+
+////////////////////////////////////////////////////////
+Keyboard::Key HIDInputManager::nonLocalizedKeys(UniChar virtualKeycode)
+{
+ // (Some) 0x code based on https://forums.macrumors.com/showthread.php?t=780577
+ // Some sf::Keyboard::Key are present twice.
+ switch (virtualKeycode)
+ {
+ // These cases should not be used but anyway...
+ case 0x00: return sf::Keyboard::A;
+ case 0x0b: return sf::Keyboard::B;
+ case 0x08: return sf::Keyboard::C;
+ case 0x02: return sf::Keyboard::D;
+ case 0x0e: return sf::Keyboard::E;
+ case 0x03: return sf::Keyboard::F;
+ case 0x05: return sf::Keyboard::G;
+ case 0x04: return sf::Keyboard::H;
+ case 0x22: return sf::Keyboard::I;
+ case 0x26: return sf::Keyboard::J;
+ case 0x28: return sf::Keyboard::K;
+ case 0x25: return sf::Keyboard::L;
+ case 0x2e: return sf::Keyboard::M;
+ case 0x2d: return sf::Keyboard::N;
+ case 0x1f: return sf::Keyboard::O;
+ case 0x23: return sf::Keyboard::P;
+ case 0x0c: return sf::Keyboard::Q;
+ case 0x0f: return sf::Keyboard::R;
+ case 0x01: return sf::Keyboard::S;
+ case 0x11: return sf::Keyboard::T;
+ case 0x20: return sf::Keyboard::U;
+ case 0x09: return sf::Keyboard::V;
+ case 0x0d: return sf::Keyboard::W;
+ case 0x07: return sf::Keyboard::X;
+ case 0x10: return sf::Keyboard::Y;
+ case 0x06: return sf::Keyboard::Z;
+
+ // These cases should not be used but anyway...
+ case 0x1d: return sf::Keyboard::Num0;
+ case 0x12: return sf::Keyboard::Num1;
+ case 0x13: return sf::Keyboard::Num2;
+ case 0x14: return sf::Keyboard::Num3;
+ case 0x15: return sf::Keyboard::Num4;
+ case 0x17: return sf::Keyboard::Num5;
+ case 0x16: return sf::Keyboard::Num6;
+ case 0x1a: return sf::Keyboard::Num7;
+ case 0x1c: return sf::Keyboard::Num8;
+ case 0x19: return sf::Keyboard::Num9;
+
+ case 0x35: return sf::Keyboard::Escape;
+
+ // Modifier keys : never happen with keyDown/keyUp methods (?)
+ case 0x3b: return sf::Keyboard::LControl;
+ case 0x38: return sf::Keyboard::LShift;
+ case 0x3a: return sf::Keyboard::LAlt;
+ case 0x37: return sf::Keyboard::LSystem;
+ case 0x3e: return sf::Keyboard::RControl;
+ case 0x3c: return sf::Keyboard::RShift;
+ case 0x3d: return sf::Keyboard::RAlt;
+ case 0x36: return sf::Keyboard::RSystem;
+
+ case 0x7f: return sf::Keyboard::Menu;
+ case NSMenuFunctionKey: return sf::Keyboard::Menu;
+
+ case 0x21: return sf::Keyboard::LBracket;
+ case 0x1e: return sf::Keyboard::RBracket;
+ case 0x29: return sf::Keyboard::Semicolon;
+ case 0x2b: return sf::Keyboard::Comma;
+ case 0x41: /* keypad */ return sf::Keyboard::Period;
+ case 0x2f: /* keyboard */ return sf::Keyboard::Period;
+ case 0x27: return sf::Keyboard::Quote;
+ case 0x2c: return sf::Keyboard::Slash;
+ case 0x2a: return sf::Keyboard::Backslash;
+
+ // sf::Keyboard::Tilde might be in conflict with some other key.
+ // 0x0a is for "Non-US Backslash" according to HID Calibrator,
+ // a sample provided by Apple.
+ case 0x0a: return sf::Keyboard::Tilde;
+
+ case 0x51: /* keypad */ return sf::Keyboard::Equal;
+ case 0x18: /* keyboard */ return sf::Keyboard::Equal;
+ case 0x32: return sf::Keyboard::Hyphen;
+ case 0x31: return sf::Keyboard::Space;
+ case 0x4c: /* keypad */ return sf::Keyboard::Enter;
+ case 0x24: /* keyboard */ return sf::Keyboard::Enter;
+ case 0x33: return sf::Keyboard::Backspace;
+ case 0x30: return sf::Keyboard::Tab;
+
+ // Duplicates (see next section).
+ case 0x74: return sf::Keyboard::PageUp;
+ case 0x79: return sf::Keyboard::PageDown;
+ case 0x77: return sf::Keyboard::End;
+ case 0x73: return sf::Keyboard::Home;
+
+ case NSPageUpFunctionKey: return sf::Keyboard::PageUp;
+ case NSPageDownFunctionKey: return sf::Keyboard::PageDown;
+ case NSEndFunctionKey: return sf::Keyboard::End;
+ case NSHomeFunctionKey: return sf::Keyboard::Home;
+
+ case 0x72: return sf::Keyboard::Insert;
+ case NSInsertFunctionKey: return sf::Keyboard::Insert;
+ case 0x75: return sf::Keyboard::Delete;
+ case NSDeleteFunctionKey: return sf::Keyboard::Delete;
+
+ case 0x45: return sf::Keyboard::Add;
+ case 0x4e: return sf::Keyboard::Subtract;
+ case 0x43: return sf::Keyboard::Multiply;
+ case 0x4b: return sf::Keyboard::Divide;
+
+ // Duplicates (see next section).
+ case 0x7b: return sf::Keyboard::Left;
+ case 0x7c: return sf::Keyboard::Right;
+ case 0x7e: return sf::Keyboard::Up;
+ case 0x7d: return sf::Keyboard::Down;
+
+ case NSLeftArrowFunctionKey: return sf::Keyboard::Left;
+ case NSRightArrowFunctionKey: return sf::Keyboard::Right;
+ case NSUpArrowFunctionKey: return sf::Keyboard::Up;
+ case NSDownArrowFunctionKey: return sf::Keyboard::Down;
+
+ case 0x52: return sf::Keyboard::Numpad0;
+ case 0x53: return sf::Keyboard::Numpad1;
+ case 0x54: return sf::Keyboard::Numpad2;
+ case 0x55: return sf::Keyboard::Numpad3;
+ case 0x56: return sf::Keyboard::Numpad4;
+ case 0x57: return sf::Keyboard::Numpad5;
+ case 0x58: return sf::Keyboard::Numpad6;
+ case 0x59: return sf::Keyboard::Numpad7;
+ case 0x5b: return sf::Keyboard::Numpad8;
+ case 0x5c: return sf::Keyboard::Numpad9;
+
+ // Duplicates (see next section).
+ case 0x7a: return sf::Keyboard::F1;
+ case 0x78: return sf::Keyboard::F2;
+ case 0x63: return sf::Keyboard::F3;
+ case 0x76: return sf::Keyboard::F4;
+ case 0x60: return sf::Keyboard::F5;
+ case 0x61: return sf::Keyboard::F6;
+ case 0x62: return sf::Keyboard::F7;
+ case 0x64: return sf::Keyboard::F8;
+ case 0x65: return sf::Keyboard::F9;
+ case 0x6d: return sf::Keyboard::F10;
+ case 0x67: return sf::Keyboard::F11;
+ case 0x6f: return sf::Keyboard::F12;
+ case 0x69: return sf::Keyboard::F13;
+ case 0x6b: return sf::Keyboard::F14;
+ case 0x71: return sf::Keyboard::F15;
+
+ case NSF1FunctionKey: return sf::Keyboard::F1;
+ case NSF2FunctionKey: return sf::Keyboard::F2;
+ case NSF3FunctionKey: return sf::Keyboard::F3;
+ case NSF4FunctionKey: return sf::Keyboard::F4;
+ case NSF5FunctionKey: return sf::Keyboard::F5;
+ case NSF6FunctionKey: return sf::Keyboard::F6;
+ case NSF7FunctionKey: return sf::Keyboard::F7;
+ case NSF8FunctionKey: return sf::Keyboard::F8;
+ case NSF9FunctionKey: return sf::Keyboard::F9;
+ case NSF10FunctionKey: return sf::Keyboard::F10;
+ case NSF11FunctionKey: return sf::Keyboard::F11;
+ case NSF12FunctionKey: return sf::Keyboard::F12;
+ case NSF13FunctionKey: return sf::Keyboard::F13;
+ case NSF14FunctionKey: return sf::Keyboard::F14;
+ case NSF15FunctionKey: return sf::Keyboard::F15;
+
+ case NSPauseFunctionKey: return sf::Keyboard::Pause;
+
+ // keycode 0x1b is not bound to any key.
+ // This key is ' on CH-FR, ) on FR and - on US layouts.
+
+ // An unknown key.
+ default: return sf::Keyboard::Unknown;
+ }
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/HIDJoystickManager.cpp b/src/SFML/Window/OSX/HIDJoystickManager.cpp
new file mode 100644
index 0000000..72c165a
--- /dev/null
+++ b/src/SFML/Window/OSX/HIDJoystickManager.cpp
@@ -0,0 +1,152 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/HIDInputManager.hpp>
+#include <SFML/Window/OSX/HIDJoystickManager.hpp>
+
+////////////////////////////////////////////////////////////
+// Private data
+////////////////////////////////////////////////////////////
+namespace
+{
+ // Using a custom run loop mode solve some issues that appears when SFML
+ // is used with Cocoa.
+ const CFStringRef RunLoopMode = CFSTR("SFML_RUN_LOOP_MODE");
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+HIDJoystickManager& HIDJoystickManager::getInstance()
+{
+ static HIDJoystickManager manager;
+ return manager;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int HIDJoystickManager::getJoystickCount()
+{
+ update();
+ return m_joystickCount;
+}
+
+
+////////////////////////////////////////////////////////////
+CFSetRef HIDJoystickManager::copyJoysticks()
+{
+ CFSetRef devices = IOHIDManagerCopyDevices(m_manager);
+ return devices;
+}
+
+
+////////////////////////////////////////////////////////////
+HIDJoystickManager::HIDJoystickManager() :
+m_manager(0),
+m_joystickCount(0)
+{
+ m_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+
+ CFDictionaryRef mask0 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop,
+ kHIDUsage_GD_Joystick);
+
+ CFDictionaryRef mask1 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop,
+ kHIDUsage_GD_GamePad);
+
+ CFDictionaryRef maskArray[2];
+ maskArray[0] = mask0;
+ maskArray[1] = mask1;
+
+ CFArrayRef mask = CFArrayCreate(NULL, (const void**)maskArray, 2, NULL);
+
+ IOHIDManagerSetDeviceMatchingMultiple(m_manager, mask);
+ CFRelease(mask);
+ CFRelease(mask1);
+ CFRelease(mask0);
+
+
+ IOHIDManagerRegisterDeviceMatchingCallback(m_manager, pluggedIn, this);
+ IOHIDManagerRegisterDeviceRemovalCallback(m_manager, pluggedOut, this);
+
+ IOHIDManagerScheduleWithRunLoop(m_manager,
+ CFRunLoopGetCurrent(),
+ RunLoopMode);
+
+ IOHIDManagerOpen(m_manager, kIOHIDOptionsTypeNone);
+}
+
+
+////////////////////////////////////////////////////////////
+HIDJoystickManager::~HIDJoystickManager()
+{
+ IOHIDManagerUnscheduleFromRunLoop(m_manager,
+ CFRunLoopGetCurrent(),
+ RunLoopMode);
+
+ IOHIDManagerRegisterDeviceMatchingCallback(m_manager, NULL, 0);
+ IOHIDManagerRegisterDeviceRemovalCallback(m_manager, NULL, 0);
+
+ IOHIDManagerClose(m_manager, kIOHIDOptionsTypeNone);
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDJoystickManager::update()
+{
+ SInt32 status = kCFRunLoopRunHandledSource;
+
+ while (status == kCFRunLoopRunHandledSource)
+ {
+ status = CFRunLoopRunInMode(RunLoopMode, 0, true);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDJoystickManager::pluggedIn(void* context, IOReturn, void*, IOHIDDeviceRef)
+{
+ HIDJoystickManager* manager = static_cast<HIDJoystickManager*>(context);
+ manager->m_joystickCount++;
+}
+
+
+////////////////////////////////////////////////////////////
+void HIDJoystickManager::pluggedOut(void* context, IOReturn, void*, IOHIDDeviceRef)
+{
+ HIDJoystickManager* manager = static_cast<HIDJoystickManager*>(context);
+ manager->m_joystickCount--;
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/HIDJoystickManager.hpp b/src/SFML/Window/OSX/HIDJoystickManager.hpp
new file mode 100644
index 0000000..eb249cc
--- /dev/null
+++ b/src/SFML/Window/OSX/HIDJoystickManager.hpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_HIDJOYSTICKMANAGER_HPP
+#define SFML_HIDJOYSTICKMANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/NonCopyable.hpp>
+#include <IOKit/hid/IOHIDDevice.h>
+#include <IOKit/hid/IOHIDManager.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief sf::priv::InputImpl helper
+///
+/// This class manage as a singleton instance the joysticks.
+/// It's only purpose is to help sf::priv::JoystickImpl class.
+///
+////////////////////////////////////////////////////////////
+class HIDJoystickManager : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the unique instance of the class
+ ///
+ /// \note Private use only
+ ///
+ /// \return Reference to the HIDJoystickManager instance
+ ///
+ ////////////////////////////////////////////////////////////
+ static HIDJoystickManager& getInstance();
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the number of currently connected joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getJoystickCount();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Copy the devices associated with this HID manager
+ ///
+ /// \return a retained CFSetRef of IOHIDDeviceRef or NULL
+ ///
+ ////////////////////////////////////////////////////////////
+ CFSetRef copyJoysticks();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ HIDJoystickManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~HIDJoystickManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Make sure all event have been processed in the run loop
+ ///
+ ////////////////////////////////////////////////////////////
+ void update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Private "plug-in" callback
+ /// \note Only 'context' parameter is used.
+ /// \see IOHIDDeviceCallback
+ ///
+ ////////////////////////////////////////////////////////////
+ static void pluggedIn(void* context, IOReturn, void*, IOHIDDeviceRef);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Private "plug-out" callback
+ /// \note Only 'context' parameter is used.
+ /// \see IOHIDDeviceCallback
+ ///
+ ////////////////////////////////////////////////////////////
+ static void pluggedOut(void* context, IOReturn, void*, IOHIDDeviceRef);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ IOHIDManagerRef m_manager; ///< HID Manager
+ unsigned int m_joystickCount;///< Number of joysticks currently connected
+};
+
+
+} // namespace priv
+
+} // namespace sf
+
+#endif
diff --git a/src/SFML/Window/OSX/InputImpl.hpp b/src/SFML/Window/OSX/InputImpl.hpp
new file mode 100644
index 0000000..6f874bc
--- /dev/null
+++ b/src/SFML/Window/OSX/InputImpl.hpp
@@ -0,0 +1,169 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_INPUTIMPLOSX_HPP
+#define SFML_INPUTIMPLOSX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Mac OS X implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(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.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 isTouchDown(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 getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLOSX_HPP
diff --git a/src/SFML/Window/OSX/InputImpl.mm b/src/SFML/Window/OSX/InputImpl.mm
new file mode 100644
index 0000000..361e1be
--- /dev/null
+++ b/src/SFML/Window/OSX/InputImpl.mm
@@ -0,0 +1,237 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/Window.hpp>
+#include <SFML/Window/OSX/InputImpl.hpp>
+#include <SFML/Window/OSX/HIDInputManager.hpp>
+#include <SFML/System/Err.hpp>
+
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <AppKit/AppKit.h>
+
+////////////////////////////////////////////////////////////
+/// In order to keep track of the keyboard's state and mouse buttons' state
+/// we use the HID manager. Mouse position is handled differently.
+///
+/// NB: we probably could use
+/// NSEvent +addGlobalMonitorForEventsMatchingMask:handler: for mouse only.
+///
+////////////////////////////////////////////////////////////
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Extract the dedicated SFOpenGLView from the SFML window
+///
+/// \param window a SFML window
+/// \return nil if something went wrong or a SFOpenGLView*.
+///
+////////////////////////////////////////////////////////////
+SFOpenGLView* getSFOpenGLViewFromSFMLWindow(const Window& window)
+{
+ id nsHandle = (id)window.getSystemHandle();
+
+ // Get our SFOpenGLView from ...
+ SFOpenGLView* view = nil;
+
+ if ([nsHandle isKindOfClass:[NSWindow class]])
+ {
+ // If system handle is a window then from its content view.
+ view = [nsHandle contentView];
+
+ // Subview doesn't match ?
+ if (![view isKindOfClass:[SFOpenGLView class]])
+ {
+ if([view isKindOfClass:[NSView class]])
+ {
+ NSArray* subviews = [view subviews];
+ for (NSView* subview in subviews)
+ {
+ if ([subview isKindOfClass:[SFOpenGLView class]])
+ {
+ view = (SFOpenGLView*)subview;
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ sf::err() << "The content view is not a valid SFOpenGLView"
+ << std::endl;
+
+ view = nil;
+ }
+ }
+
+ }
+ else if ([nsHandle isKindOfClass:[NSView class]])
+ {
+ // If system handle is a view then from a subview of kind SFOpenGLView.
+ NSArray* subviews = [nsHandle subviews];
+ for (NSView* subview in subviews)
+ {
+ if ([subview isKindOfClass:[SFOpenGLView class]])
+ {
+ view = (SFOpenGLView*)subview;
+ break;
+ }
+ }
+
+ // No matching subview ?
+ if (view == nil)
+ sf::err() << "Cannot find a valid SFOpenGLView subview." << std::endl;
+ }
+ else
+ {
+ if (nsHandle != 0)
+ sf::err() << "The system handle is neither a <NSWindow*> nor <NSView*>"
+ << "object. This shouldn't happen."
+ << std::endl;
+ // Else: this probably means the SFML window was previously closed.
+ }
+
+ return view;
+}
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ return HIDInputManager::getInstance().isKeyPressed(key);
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ NSUInteger state = [NSEvent pressedMouseButtons];
+ NSUInteger flag = 1 << button;
+ return (state & flag) != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ // Reverse Y axis to match SFML coord.
+ NSPoint pos = [NSEvent mouseLocation];
+ pos.y = sf::VideoMode::getDesktopMode().height - pos.y;
+
+ int scale = [[NSScreen mainScreen] backingScaleFactor];
+ return Vector2i(pos.x, pos.y) * scale;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ SFOpenGLView* view = getSFOpenGLViewFromSFMLWindow(relativeTo);
+
+ // No view ?
+ if (view == nil)
+ return Vector2i();
+
+ // Use -cursorPositionFromEvent: with nil.
+ NSPoint pos = [view cursorPositionFromEvent:nil];
+
+ int scale = [view displayScaleFactor];
+ return Vector2i(pos.x, pos.y) * scale;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ // Here we don't need to reverse the coordinates.
+ int scale = [[NSScreen mainScreen] backingScaleFactor];
+ CGPoint pos = CGPointMake(position.x / scale, position.y / scale);
+
+ // Place the cursor.
+ CGEventRef event = CGEventCreateMouseEvent(NULL,
+ kCGEventMouseMoved,
+ pos,
+ /* we don't care about this: */ kCGMouseButtonLeft);
+ CGEventPost(kCGHIDEventTap, event);
+ CFRelease(event);
+ // This is a workaround to deprecated CGSetLocalEventsSuppressionInterval.
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ SFOpenGLView* view = getSFOpenGLViewFromSFMLWindow(relativeTo);
+
+ // No view ?
+ if (view == nil)
+ return;
+
+ // Let SFOpenGLView compute the position in global coordinate
+ int scale = [view displayScaleFactor];
+ NSPoint p = NSMakePoint(position.x / scale, position.y / scale);
+ p = [view computeGlobalPositionOfRelativePoint:p];
+ setMousePosition(sf::Vector2i(p.x, p.y) * scale);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int /*finger*/)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*relativeTo*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/OSX/JoystickImpl.cpp b/src/SFML/Window/OSX/JoystickImpl.cpp
new file mode 100644
index 0000000..9552b19
--- /dev/null
+++ b/src/SFML/Window/OSX/JoystickImpl.cpp
@@ -0,0 +1,524 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/Window/OSX/HIDInputManager.hpp>
+#include <SFML/Window/OSX/HIDJoystickManager.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace
+{
+ bool JoystickButtonSortPredicate(IOHIDElementRef b1, IOHIDElementRef b2)
+ {
+ return IOHIDElementGetUsage(b1) < IOHIDElementGetUsage(b2);
+ }
+
+ // Convert a CFStringRef to std::string
+ std::string stringFromCFString(CFStringRef cfString)
+ {
+ CFIndex length = CFStringGetLength(cfString);
+ std::vector<char> str(length);
+ CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
+ CFStringGetCString(cfString, &str[0], maxSize, kCFStringEncodingUTF8);
+ return &str[0];
+ }
+
+ // Get HID device property key as a string
+ std::string getDeviceString(IOHIDDeviceRef ref, CFStringRef prop, unsigned int index)
+ {
+ CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop);
+ if (typeRef && (CFGetTypeID(typeRef) == CFStringGetTypeID()))
+ {
+ CFStringRef str = static_cast<CFStringRef>(typeRef);
+ return stringFromCFString(str);
+ }
+
+ sf::err() << "Unable to read string value for property '" << stringFromCFString(prop) << "' for joystick at index " << index << std::endl;
+ return "Unknown Joystick";
+ }
+
+
+ // Get HID device property key as an unsigned int
+ unsigned int getDeviceUint(IOHIDDeviceRef ref, CFStringRef prop, unsigned int index)
+ {
+ CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop);
+ if (typeRef && (CFGetTypeID(typeRef) == CFNumberGetTypeID()))
+ {
+ SInt32 value;
+ CFNumberGetValue((CFNumberRef)typeRef, kCFNumberSInt32Type, &value);
+ return value;
+ }
+
+ sf::err() << "Unable to read uint value for property '" << stringFromCFString(prop) << "' for joystick at index " << index << std::endl;
+ return 0;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+JoystickImpl::Location JoystickImpl::m_locationIDs[sf::Joystick::Count] = { 0 };
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ bool state = false; // Is the index-th joystick connected?
+
+ // First, let's check if the device was previously detected:
+ if (m_locationIDs[index] != 0)
+ {
+ state = true;
+ }
+ else
+ {
+ // Otherwise, let's check if it is now connected
+ // i.e., m_locationIDs[index] == 0
+
+ // if there is more connected joystick to the HID manager than
+ // opened joystick devices then we find the new one.
+
+ unsigned int openedCount = 0;
+ for (unsigned int i(0); i < sf::Joystick::Count; ++i)
+ {
+ if (m_locationIDs[i] != 0)
+ openedCount++;
+ }
+
+
+ unsigned int connectedCount = HIDJoystickManager::getInstance().getJoystickCount();
+
+ if (connectedCount > openedCount)
+ {
+ // Get all devices
+ CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks();
+
+ if (devices != NULL)
+ {
+ CFIndex size = CFSetGetCount(devices);
+ if (size > 0)
+ {
+ CFTypeRef array[size]; // array of IOHIDDeviceRef
+ CFSetGetValues(devices, array);
+
+ // If there exists a device d s.t. there is no j s.t.
+ // m_locationIDs[j] == d's location then we have a new device.
+
+ for (CFIndex didx(0); !state && didx < size; ++didx)
+ {
+ IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx];
+ Location dloc = HIDInputManager::getLocationID(d);
+
+ bool foundJ = false;
+ for (unsigned int j(0); !foundJ && j < Joystick::Count; ++j)
+ {
+ if (m_locationIDs[j] == dloc)
+ foundJ = true;
+ }
+
+ if (!foundJ) {
+ // This is a new device
+ // We set it up for Open(..)
+ m_locationIDs[index] = dloc;
+ state = true;
+ }
+ }
+ }
+
+ CFRelease(devices);
+ }
+ }
+ }
+
+ return state;
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ m_index = index;
+ m_hat = NULL;
+ Location deviceLoc = m_locationIDs[index]; // The device we need to load
+
+ // Get all devices
+ CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks();
+ if (devices == NULL)
+ return false;
+
+ // Get a usable copy of the joysticks devices.
+ CFIndex joysticksCount = CFSetGetCount(devices);
+ CFTypeRef devicesArray[joysticksCount];
+ CFSetGetValues(devices, devicesArray);
+
+ // Get the desired joystick.
+ IOHIDDeviceRef self = 0;
+ for (CFIndex i(0); self == 0 && i < joysticksCount; ++i)
+ {
+ IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
+ if (deviceLoc == HIDInputManager::getLocationID(d))
+ self = d;
+ }
+
+ if (self == 0)
+ {
+ CFRelease(devices);
+ return false;
+ }
+
+ m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index);
+ m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index);
+ m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index);
+
+ // Get a list of all elements attached to the device.
+ CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone);
+
+ if (elements == NULL)
+ {
+ CFRelease(devices);
+ return false;
+ }
+
+ // Go through all connected elements.
+ CFIndex elementsCount = CFArrayGetCount(elements);
+ for (int i = 0; i < elementsCount; ++i)
+ {
+ IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
+ switch (IOHIDElementGetUsagePage(element))
+ {
+ case kHIDPage_GenericDesktop:
+ switch (IOHIDElementGetUsage(element))
+ {
+ case kHIDUsage_GD_X: m_axis[Joystick::X] = element; break;
+ case kHIDUsage_GD_Y: m_axis[Joystick::Y] = element; break;
+ case kHIDUsage_GD_Z: m_axis[Joystick::Z] = element; break;
+ case kHIDUsage_GD_Rx: m_axis[Joystick::U] = element; break;
+ case kHIDUsage_GD_Ry: m_axis[Joystick::V] = element; break;
+ case kHIDUsage_GD_Rz: m_axis[Joystick::R] = element; break;
+
+ case kHIDUsage_GD_Hatswitch:
+ // From §4.3 MiscellaneousControls of HUT v1.12:
+ //
+ // > Hat Switch:
+ // > A typical example is four switches that are capable of generating
+ // > information about four possible directions in which the knob can be
+ // > tilted. Intermediate positions can also be decoded if the hardware
+ // > allows two switches to be reported simultaneously.
+ //
+ // We assume this model here as well. Hence, with 4 switches and intermediate
+ // positions we have 8 values (0-7) plus the "null" state (8).
+ {
+ CFIndex min = IOHIDElementGetLogicalMin(element);
+ CFIndex max = IOHIDElementGetLogicalMax(element);
+
+ if (min != 0 || max != 7)
+ {
+ sf::err() << std::hex
+ << "Joystick (vendor/product id: 0x" << m_identification.vendorId
+ << "/0x" << m_identification.productId << std::dec
+ << ") range is an unexpected one: [" << min << ", " << max << "]"
+ << std::endl;
+ }
+ else
+ {
+ m_hat = element;
+ }
+ }
+ break;
+
+ case kHIDUsage_GD_GamePad:
+ // We assume a game pad is an application collection, meaning it doesn't hold
+ // any values per say. They kind of "emit" the joystick's usages.
+ // See §3.4.3 Usage Types (Collection) of HUT v1.12
+ if (IOHIDElementGetCollectionType(element) != kIOHIDElementCollectionTypeApplication)
+ {
+ sf::err() << std::hex << "Gamepage (vendor/product id: 0x" << m_identification.vendorId
+ << "/0x" << m_identification.productId << ") is not an CA but a 0x"
+ << IOHIDElementGetCollectionType(element) << std::dec << std::endl;
+ }
+ break;
+
+ default:
+#ifdef SFML_DEBUG
+ sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex << IOHIDElementGetUsage(element) << std::dec << std::endl;
+#endif
+ break;
+ }
+ break;
+
+ case kHIDPage_Button:
+ if (m_buttons.size() < Joystick::ButtonCount) // If we have free slot...
+ m_buttons.push_back(element); // ...we add this element to the list
+ // Else: too many buttons. We ignore this one.
+ break;
+
+ default: /* No other page is expected because of the mask applied by the HID manager. */ break;
+ }
+ }
+
+ // Ensure that the buttons will be indexed in the same order as their
+ // HID Usage (assigned by manufacturer and/or a driver).
+ std::sort(m_buttons.begin(), m_buttons.end(), JoystickButtonSortPredicate);
+
+ // Retain all these objects for personal use
+ for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it)
+ CFRetain(*it);
+ for (AxisMap::iterator it(m_axis.begin()); it != m_axis.end(); ++it)
+ CFRetain(it->second);
+ if (m_hat != NULL)
+ CFRetain(m_hat);
+
+ // Note: we didn't retain element in the switch because we might have multiple
+ // Axis X (for example) and we want to keep only the last one. To prevent
+ // leaking we retain objects 'only' now.
+
+ CFRelease(devices);
+ CFRelease(elements);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it)
+ CFRelease(*it);
+ m_buttons.clear();
+
+ for (AxisMap::iterator it(m_axis.begin()); it != m_axis.end(); ++it)
+ CFRelease(it->second);
+ m_axis.clear();
+
+ if (m_hat != NULL)
+ CFRelease(m_hat);
+ m_hat = NULL;
+
+ // And we unregister this joystick
+ m_locationIDs[m_index] = 0;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ JoystickCaps caps;
+
+ // Buttons:
+ caps.buttonCount = m_buttons.size();
+
+ // Axis:
+ for (AxisMap::const_iterator it(m_axis.begin()); it != m_axis.end(); ++it)
+ caps.axes[it->first] = true;
+
+ if (m_hat != NULL)
+ caps.axes[Joystick::PovX] = caps.axes[Joystick::PovY] = true;
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::update()
+{
+ static const JoystickState disconnectedState; // return this if joystick was disconnected
+ JoystickState state; // otherwise return that
+ state.connected = true;
+
+ // Note: free up is done in close() which is called, if required,
+ // by the joystick manager. So we don't release buttons nor axes here.
+
+ // First, let's determine if the joystick is still connected
+ Location selfLoc = m_locationIDs[m_index];
+
+ // Get all devices
+ CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks();
+ if (devices == NULL)
+ return disconnectedState;
+
+ // Get a usable copy of the joysticks devices.
+ CFIndex joysticksCount = CFSetGetCount(devices);
+ CFTypeRef devicesArray[joysticksCount];
+ CFSetGetValues(devices, devicesArray);
+
+ // Search for it
+ bool found = false;
+ for (CFIndex i(0); !found && i < joysticksCount; ++i)
+ {
+ IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
+ if (selfLoc == HIDInputManager::getLocationID(d))
+ found = true;
+ }
+
+ // Release unused stuff
+ CFRelease(devices);
+
+ // If not found we consider it disconnected
+ if (!found)
+ return disconnectedState;
+
+ // Update buttons' state
+ unsigned int i = 0;
+ for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it, ++i)
+ {
+ IOHIDValueRef value = 0;
+ IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value);
+
+ // Check for plug out.
+ if (!value)
+ {
+ return disconnectedState;
+ }
+
+ // 1 means pressed, others mean released
+ state.buttons[i] = IOHIDValueGetIntegerValue(value) == 1;
+ }
+
+ // Update axes' state
+ for (AxisMap::iterator it = m_axis.begin(); it != m_axis.end(); ++it)
+ {
+ IOHIDValueRef value = 0;
+ IOHIDDeviceGetValue(IOHIDElementGetDevice(it->second), it->second, &value);
+
+ // Check for plug out.
+ if (!value)
+ {
+ return disconnectedState;
+ }
+
+ // We want to bind [physicalMin,physicalMax] to [-100=min,100=max].
+ //
+ // General formula to bind [a,b] to [c,d] with a linear progression:
+ //
+ // f: [a, b] -> [c, d]
+ // x |-> (x-a)(d-c)/(b-a)+c
+ //
+ // This method might not be very accurate (the "0 position" can be
+ // slightly shift with some device) but we don't care because most
+ // of devices are so sensitive that this is not relevant.
+ double physicalMax = IOHIDElementGetPhysicalMax(it->second);
+ double physicalMin = IOHIDElementGetPhysicalMin(it->second);
+ double scaledMin = -100;
+ double scaledMax = 100;
+ double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
+ float scaledValue = (((physicalValue - physicalMin) * (scaledMax - scaledMin)) / (physicalMax - physicalMin)) + scaledMin;
+ state.axes[it->first] = scaledValue;
+ }
+
+ // Update POV/Hat state. Assuming model described in `open`, values are:
+ //
+ // North-West / 7 North / 0 North-East / 1
+ // West / 6 Null / 8 East / 2
+ // South-West / 5 South / 4 South-East / 3
+ //
+ if (m_hat != NULL)
+ {
+ IOHIDValueRef value = 0;
+ IOHIDDeviceGetValue(IOHIDElementGetDevice(m_hat), m_hat, &value);
+
+ // Check for plug out.
+ if (!value)
+ {
+ return disconnectedState;
+ }
+
+ CFIndex raw = IOHIDValueGetIntegerValue(value);
+
+ // Load PovX
+ switch (raw)
+ {
+ case 1:
+ case 2:
+ case 3:
+ state.axes[Joystick::PovX] = +100;
+ break;
+
+ case 5:
+ case 6:
+ case 7:
+ state.axes[Joystick::PovX] = -100;
+ break;
+
+ default:
+ state.axes[Joystick::PovX] = 0;
+ break;
+ }
+
+ // Load PovY
+ switch (raw)
+ {
+ case 0:
+ case 1:
+ case 7:
+ state.axes[Joystick::PovY] = +100;
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ state.axes[Joystick::PovY] = -100;
+ break;
+
+ default:
+ state.axes[Joystick::PovY] = 0;
+ break;
+ }
+ }
+
+ return state;
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/JoystickImpl.hpp b/src/SFML/Window/OSX/JoystickImpl.hpp
new file mode 100644
index 0000000..f4ad680
--- /dev/null
+++ b/src/SFML/Window/OSX/JoystickImpl.hpp
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_JOYSTICKIMPLOSX_HPP
+#define SFML_JOYSTICKIMPLOSX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/hid/IOHIDDevice.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <map>
+#include <vector>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Mac OS X implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ typedef long Location;
+ typedef std::map<sf::Joystick::Axis, IOHIDElementRef> AxisMap;
+ typedef std::vector<IOHIDElementRef> ButtonsVector;
+
+ AxisMap m_axis; ///< Axes (but not POV/Hat) of the joystick
+ IOHIDElementRef m_hat; ///< POV/Hat axis of the joystick
+ ButtonsVector m_buttons; ///< Buttons of the joystick
+ unsigned int m_index; ///< SFML index
+ Joystick::Identification m_identification; ///< Joystick identification
+
+ static Location m_locationIDs[sf::Joystick::Count]; ///< Global Joystick register
+ /// For a corresponding SFML index, m_locationIDs is either some USB
+ /// location or 0 if there isn't currently a connected joystick device
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLOSX_HPP
diff --git a/src/SFML/Window/OSX/NSImage+raw.h b/src/SFML/Window/OSX/NSImage+raw.h
new file mode 100644
index 0000000..99e0484
--- /dev/null
+++ b/src/SFML/Window/OSX/NSImage+raw.h
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+
+#import <AppKit/AppKit.h>
+
+////////////////////////////////////////////////////////////
+/// Extends NSImage with a convenience method to load images
+/// from raw data.
+///
+////////////////////////////////////////////////////////////
+
+@interface NSImage (raw)
+
+////////////////////////////////////////////////////////////
+/// \brief Load an image from raw RGBA pixels
+///
+/// \param pixels array of 4 * `size` bytes representing the image
+/// \param size size of the image
+///
+/// \return an instance of NSImage that needs to be released by the caller
+///
+////////////////////////////////////////////////////////////
++(NSImage*)imageWithRawData:(const sf::Uint8*)pixels andSize:(NSSize)size;
+
+@end
diff --git a/src/SFML/Window/OSX/NSImage+raw.mm b/src/SFML/Window/OSX/NSImage+raw.mm
new file mode 100644
index 0000000..56ee6c9
--- /dev/null
+++ b/src/SFML/Window/OSX/NSImage+raw.mm
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/NSImage+raw.h>
+
+@implementation NSImage (raw)
+
++(NSImage*)imageWithRawData:(const sf::Uint8*)pixels andSize:(NSSize)size
+{
+ // Create an empty image representation.
+ NSBitmapImageRep* bitmap =
+ [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 // if 0: only allocate memory
+ pixelsWide:size.width
+ pixelsHigh:size.height
+ bitsPerSample:8 // The number of bits used to specify
+ // one pixel in a single component of the data.
+ samplesPerPixel:4 // 3 if no alpha, 4 with it
+ hasAlpha:YES
+ isPlanar:NO // I don't know what it is but it works
+ colorSpaceName:NSCalibratedRGBColorSpace
+ bytesPerRow:0 // 0 == determine automatically
+ bitsPerPixel:0]; // 0 == determine automatically
+
+ // Load data pixels.
+ for (unsigned int y = 0; y < size.height; ++y)
+ {
+ for (unsigned int x = 0; x < size.width; ++x, pixels += 4)
+ {
+ NSUInteger pixel[4] = { pixels[0], pixels[1], pixels[2], pixels[3] };
+ [bitmap setPixel:pixel atX:x y:y];
+ }
+ }
+
+ // Create an image from the representation.
+ NSImage* image = [[NSImage alloc] initWithSize:size];
+ [image addRepresentation:bitmap];
+
+ [bitmap release];
+
+ return image;
+}
+
+@end
diff --git a/src/SFML/Window/OSX/SFApplication.h b/src/SFML/Window/OSX/SFApplication.h
new file mode 100644
index 0000000..5f2071f
--- /dev/null
+++ b/src/SFML/Window/OSX/SFApplication.h
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+////////////////////////////////////////////////////////////
+/// \brief Event processing & Menu bar initialization
+///
+////////////////////////////////////////////////////////////
+@interface SFApplication : NSApplication
+
+
+////////////////////////////////////////////////////////////
+/// \brief Event processing
+///
+////////////////////////////////////////////////////////////
++(void)processEvent;
+
+
+////////////////////////////////////////////////////////////
+/// \brief Set up the menu bar and its items
+///
+////////////////////////////////////////////////////////////
++(void)setUpMenuBar;
+
+
+////////////////////////////////////////////////////////////
+/// \brief Dispatch events
+///
+/// This overload of -[NSApplication sendEvent:] is used to
+/// fix KeyRelease events when the command key is down.
+///
+////////////////////////////////////////////////////////////
+-(void)sendEvent:(NSEvent*)anEvent;
+
+
+@end
diff --git a/src/SFML/Window/OSX/SFApplication.m b/src/SFML/Window/OSX/SFApplication.m
new file mode 100644
index 0000000..a922543
--- /dev/null
+++ b/src/SFML/Window/OSX/SFApplication.m
@@ -0,0 +1,266 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/SFApplication.h>
+
+
+////////////////////////////////////////////////////////////
+@implementation SFApplication
+
+
+////////////////////////////////////////////////////////////
++(void)processEvent
+{
+ [SFApplication sharedApplication]; // Make sure NSApp exists
+ NSEvent* event = nil;
+
+ while ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES])) // Remove the event from the queue
+ {
+ [NSApp sendEvent:event];
+ }
+}
+
+
+////////////////////////////////////////////////////////
++(void)setUpMenuBar
+{
+ [SFApplication sharedApplication]; // Make sure NSApp exists
+
+ // Set the main menu bar
+ NSMenu* mainMenu = [NSApp mainMenu];
+ if (mainMenu != nil)
+ return;
+ mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ [NSApp setMainMenu:mainMenu];
+
+ // Application Menu (aka Apple Menu)
+ NSMenuItem* appleItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ NSMenu* appleMenu = [[SFApplication newAppleMenu] autorelease];
+ [appleItem setSubmenu:appleMenu];
+
+ // File Menu
+ NSMenuItem* fileItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ NSMenu* fileMenu = [[SFApplication newFileMenu] autorelease];
+ [fileItem setSubmenu:fileMenu];
+
+ // Window menu
+ NSMenuItem* windowItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ NSMenu* windowMenu = [[SFApplication newWindowMenu] autorelease];
+ [windowItem setSubmenu:windowMenu];
+ [NSApp setWindowsMenu:windowMenu];
+}
+
+
+////////////////////////////////////////////////////////
++(NSMenu*)newAppleMenu
+{
+ // Apple menu is as follow:
+ //
+ // AppName >
+ // About AppName
+ // --------------------
+ // Preferences... [greyed]
+ // --------------------
+ // Services >
+ // / default empty menu /
+ // --------------------
+ // Hide AppName Command+H
+ // Hide Others Option+Command+H
+ // Show All
+ // --------------------
+ // Quit AppName Command+Q
+
+ NSString* appName = [SFApplication applicationName];
+
+ // APPLE MENU
+ NSMenu* appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ // ABOUT
+ [appleMenu addItemWithTitle:[@"About " stringByAppendingString:appName]
+ action:@selector(orderFrontStandardAboutPanel:)
+ keyEquivalent:@""];
+
+ // SEPARATOR
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ // PREFERENCES
+ [appleMenu addItemWithTitle:@"Preferences..."
+ action:nil
+ keyEquivalent:@""];
+
+ // SEPARATOR
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ // SERVICES
+ NSMenu* serviceMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ NSMenuItem* serviceItem = [appleMenu addItemWithTitle:@"Services"
+ action:nil
+ keyEquivalent:@""];
+ [serviceItem setSubmenu:serviceMenu];
+ [NSApp setServicesMenu:serviceMenu];
+
+ // SEPARATOR
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ // HIDE
+ [appleMenu addItemWithTitle:[@"Hide " stringByAppendingString:appName]
+ action:@selector(hide:)
+ keyEquivalent:@"h"];
+
+ // HIDE OTHER
+ NSMenuItem* hideOtherItem = [appleMenu addItemWithTitle:@"Hide Others"
+ action:@selector(hideOtherApplications:)
+ keyEquivalent:@"h"];
+ [hideOtherItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+
+ // SHOW ALL
+ [appleMenu addItemWithTitle:@"Show All"
+ action:@selector(unhideAllApplications:)
+ keyEquivalent:@""];
+
+ // SEPARATOR
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ // QUIT
+ [appleMenu addItemWithTitle:[@"Quit " stringByAppendingString:appName]
+ action:@selector(terminate:)
+ keyEquivalent:@"q"];
+
+ return appleMenu;
+}
+
+
+////////////////////////////////////////////////////////
++(NSMenu*)newFileMenu
+{
+ // The File menu is as follow:
+ //
+ // File >
+ // Close Command+W
+
+ // FILE MENU
+ NSMenu* fileMenu = [[NSMenu alloc] initWithTitle:@"File"];
+
+ // CLOSE WINDOW
+ NSMenuItem* closeItem = [[NSMenuItem alloc] initWithTitle:@"Close Window"
+ action:@selector(performClose:)
+ keyEquivalent:@"w"];
+ [fileMenu addItem:closeItem];
+ [closeItem release];
+
+ return fileMenu;
+}
+
+
+////////////////////////////////////////////////////////
++(NSMenu*)newWindowMenu
+{
+ // The Window menu is as follow:
+ //
+ // Window >
+ // Minimize Command+M
+ // Zoom
+ // --------------------
+ // Bring All to Front
+
+ // WINDOW MENU
+ NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ // MINIMIZE
+ NSMenuItem* minimizeItem = [[NSMenuItem alloc] initWithTitle:@"Minimize"
+ action:@selector(performMiniaturize:)
+ keyEquivalent:@"m"];
+ [windowMenu addItem:minimizeItem];
+ [minimizeItem release];
+
+ // ZOOM
+ [windowMenu addItemWithTitle:@"Zoom"
+ action:@selector(performZoom:)
+ keyEquivalent:@""];
+
+ // SEPARATOR
+ [windowMenu addItem:[NSMenuItem separatorItem]];
+
+ // BRING ALL TO FRONT
+ [windowMenu addItemWithTitle:@"Bring All to Front"
+ action:@selector(bringAllToFront:)
+ keyEquivalent:@""];
+
+ return windowMenu;
+}
+
+
+////////////////////////////////////////////////////////
++(NSString*)applicationName
+{
+ // First, try localized name
+ NSString* appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"];
+
+ // Then, try non-localized name
+ if ((appName == nil) || ([appName length] == 0))
+ appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
+
+ // Finally, fallback to the process info
+ if ((appName == nil) || ([appName length] == 0))
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)bringAllToFront:(id)sender
+{
+ (void)sender;
+ [[NSApp windows] makeObjectsPerformSelector:@selector(orderFrontRegardless)];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)sendEvent:(NSEvent *)anEvent
+{
+ // Fullscreen windows have a strange behaviour with key up. To make
+ // sure the user gets an event we call (if possible) sfKeyUp on our
+ // custom OpenGL view. See -[SFOpenGLView sfKeyUp:] for more details.
+
+ id firstResponder = [[anEvent window] firstResponder];
+ if (([anEvent type] != NSKeyUp) || (![firstResponder tryToPerform:@selector(sfKeyUp:) with:anEvent]))
+ {
+ // It's either not a key up event or no responder has a sfKeyUp
+ // message implemented.
+ [super sendEvent:anEvent];
+ }
+}
+
+
+@end
+
+
diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.h b/src/SFML/Window/OSX/SFApplicationDelegate.h
new file mode 100644
index 0000000..542c0a1
--- /dev/null
+++ b/src/SFML/Window/OSX/SFApplicationDelegate.h
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+
+////////////////////////////////////////////////////////////
+/// \brief Process some application specific events
+///
+////////////////////////////////////////////////////////////
+@interface SFApplicationDelegate : NSObject <NSApplicationDelegate>
+
+////////////////////////////////////////////////////////////
+/// \brief React to a termination notification
+///
+/// Send a close message to all windows and cancel the termination.
+///
+////////////////////////////////////////////////////////////
+-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
+
+////////////////////////////////////////////////////////////
+/// \brief Exit the app when all windows are closed
+///
+////////////////////////////////////////////////////////////
+-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
+
+@end
diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.m b/src/SFML/Window/OSX/SFApplicationDelegate.m
new file mode 100644
index 0000000..d7e6050
--- /dev/null
+++ b/src/SFML/Window/OSX/SFApplicationDelegate.m
@@ -0,0 +1,54 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/SFApplicationDelegate.h>
+
+////////////////////////////////////////////////////////////
+@implementation SFApplicationDelegate
+
+
+////////////////////////////////////////////////////////////
+-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
+{
+ (void)sender;
+ // Generate close event for each SFML window
+ [NSApp makeWindowsPerform:@selector(sfClose) inOrder:NO];
+ return NSTerminateCancel;
+}
+
+
+////////////////////////////////////////////////////////////
+-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
+{
+ (void)theApplication;
+ return YES;
+}
+
+
+@end
+
diff --git a/src/SFML/Window/OSX/SFContext.hpp b/src/SFML/Window/OSX/SFContext.hpp
new file mode 100644
index 0000000..5fa3b21
--- /dev/null
+++ b/src/SFML/Window/OSX/SFContext.hpp
@@ -0,0 +1,173 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_SFCONTEXT_HPP
+#define SFML_SFCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+
+////////////////////////////////////////////////////////////
+/// Predefine OBJC classes
+////////////////////////////////////////////////////////////
+#ifdef __OBJC__
+
+@class NSOpenGLContext;
+typedef NSOpenGLContext* NSOpenGLContextRef;
+
+@class NSOpenGLView;
+typedef NSOpenGLView* NSOpenGLViewRef;
+
+@class NSWindow;
+typedef NSWindow* NSWindowRef;
+
+#else // If C++
+
+typedef void* NSOpenGLContextRef;
+typedef void* NSOpenGLViewRef;
+typedef void* NSWindowRef;
+
+#endif
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief OSX (Cocoa) implementation of OpenGL contexts
+///
+////////////////////////////////////////////////////////////
+class SFContext : public GlContext
+{
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context, not associated to a window
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ SFContext(SFContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ SFContext(SFContext* shared, const ContextSettings& settings,
+ const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ SFContext(SFContext* shared, const ContextSettings& settings,
+ unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SFContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \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 Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+protected:
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate the context as the current target
+ /// for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current);
+
+private:
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context
+ /// \note Must only be called from Ctor.
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ /// \param bitsPerPixel bpp
+ /// \param settings Creation parameters
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(SFContext* shared,
+ unsigned int bitsPerPixel,
+ const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ NSOpenGLContextRef m_context; ///< OpenGL context.
+ NSOpenGLViewRef m_view; ///< Only for offscreen context.
+ NSWindowRef m_window; ///< Only for offscreen context.
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_SFCONTEXT_HPP
diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm
new file mode 100644
index 0000000..cf74de9
--- /dev/null
+++ b/src/SFML/Window/OSX/SFContext.mm
@@ -0,0 +1,310 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/SFContext.hpp>
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <SFML/System/Err.hpp>
+#include <dlfcn.h>
+#include <stdint.h>
+
+#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
+
+namespace sf
+{
+namespace priv
+{
+
+
+////////////////////////////////////////////////////////////
+SFContext::SFContext(SFContext* shared) :
+m_view(0),
+m_window(0)
+{
+ // Ask for a pool.
+ ensureThreadHasPool();
+
+ // Create the context
+ createContext(shared,
+ VideoMode::getDesktopMode().bitsPerPixel,
+ ContextSettings(0, 0, 0));
+}
+
+
+////////////////////////////////////////////////////////////
+SFContext::SFContext(SFContext* shared, const ContextSettings& settings,
+ const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_view(0),
+m_window(0)
+{
+ // Ask for a pool.
+ ensureThreadHasPool();
+
+ // Create the context.
+ createContext(shared, bitsPerPixel, settings);
+
+ // Apply context.
+ const WindowImplCocoa* ownerCocoa = static_cast<const WindowImplCocoa*>(owner);
+ ownerCocoa->applyContext(m_context);
+}
+
+
+////////////////////////////////////////////////////////////
+SFContext::SFContext(SFContext* shared, const ContextSettings& settings,
+ unsigned int width, unsigned int height) :
+m_view(0),
+m_window(0)
+{
+ // Ensure the process is setup in order to create a valid window.
+ WindowImplCocoa::setUpProcess();
+
+ // Ask for a pool.
+ ensureThreadHasPool();
+
+ // Create the context.
+ createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings);
+
+ // Create a dummy window/view pair (hidden) and assign it our context.
+ m_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]; // Don't defer it!
+ m_view = [[NSOpenGLView alloc] initWithFrame:NSMakeRect(0, 0, width, height)];
+ [m_window setContentView:m_view];
+ [m_view setOpenGLContext:m_context];
+ [m_context setView:m_view];
+}
+
+
+////////////////////////////////////////////////////////////
+SFContext::~SFContext()
+{
+ // Notify unshared OpenGL resources of context destruction
+ cleanupUnsharedResources();
+
+ [m_context clearDrawable];
+
+ if (m_context == [NSOpenGLContext currentContext])
+ [NSOpenGLContext clearCurrentContext];
+
+ [m_context release];
+
+ [m_view release]; // Might be nil but we don't care.
+ [m_window release]; // Idem.
+}
+
+
+////////////////////////////////////////////////////////////
+GlFunctionPointer SFContext::getFunction(const char* name)
+{
+ static void* image = NULL;
+
+ if (!image)
+ image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
+
+ return (image ? reinterpret_cast<GlFunctionPointer>(reinterpret_cast<intptr_t>(dlsym(image, name))) : 0);
+}
+
+
+////////////////////////////////////////////////////////////
+bool SFContext::makeCurrent(bool current)
+{
+ if (current)
+ {
+ [m_context makeCurrentContext];
+ return m_context == [NSOpenGLContext currentContext]; // Should be true.
+ }
+ else
+ {
+ [NSOpenGLContext clearCurrentContext];
+ return m_context != [NSOpenGLContext currentContext]; // Should be true.
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void SFContext::display()
+{
+ [m_context flushBuffer];
+}
+
+
+////////////////////////////////////////////////////////////
+void SFContext::setVerticalSyncEnabled(bool enabled)
+{
+ GLint swapInterval = enabled ? 1 : 0;
+
+ [m_context setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+}
+
+
+////////////////////////////////////////////////////////////
+void SFContext::createContext(SFContext* shared,
+ unsigned int bitsPerPixel,
+ const ContextSettings& settings)
+{
+ // Save the settings. (OpenGL version is updated elsewhere.)
+ m_settings = settings;
+
+ // Choose the attributes of OGL context.
+ std::vector<NSOpenGLPixelFormatAttribute> attrs;
+ attrs.reserve(20); // max attributes (estimation).
+
+ // These casts are safe. C++ is much more strict than Obj-C.
+
+ attrs.push_back(NSOpenGLPFAClosestPolicy);
+ attrs.push_back(NSOpenGLPFADoubleBuffer);
+
+ if (bitsPerPixel > 24)
+ {
+ attrs.push_back(NSOpenGLPFAAlphaSize);
+ attrs.push_back((NSOpenGLPixelFormatAttribute)8);
+ }
+
+ attrs.push_back(NSOpenGLPFADepthSize);
+ attrs.push_back((NSOpenGLPixelFormatAttribute)m_settings.depthBits);
+
+ attrs.push_back(NSOpenGLPFAStencilSize);
+ attrs.push_back((NSOpenGLPixelFormatAttribute)m_settings.stencilBits);
+
+ if (m_settings.antialiasingLevel > 0)
+ {
+ /*
+ * Antialiasing techniques are described in the
+ * "OpenGL Programming Guide for Mac OS X" document.
+ *
+ * According to this document, the specification currently allows
+ * only one multisample buffer.
+ *
+ * The document also states that software renderers should be avoided
+ * because antialisaing techniques are very slow with them.
+ */
+
+ // Prefer multisampling over supersampling
+ attrs.push_back(NSOpenGLPFAMultisample);
+
+ // Only one buffer is currently available
+ attrs.push_back(NSOpenGLPFASampleBuffers);
+ attrs.push_back((NSOpenGLPixelFormatAttribute)1);
+
+ // Antialiasing level
+ attrs.push_back(NSOpenGLPFASamples);
+ attrs.push_back((NSOpenGLPixelFormatAttribute)m_settings.antialiasingLevel);
+
+ // No software renderer - only hardware renderer
+ attrs.push_back(NSOpenGLPFAAccelerated);
+ }
+
+ // Support for OpenGL 3.2 on Mac OS X Lion and later:
+ // SFML 2 Graphics module uses some OpenGL features that are deprecated in
+ // OpenGL 3.0 and that are no longer available in 3.1 and 3.2+ with a core context.
+ // Therefore the Graphics module won't work as expected.
+
+ // 1.x/2.x are mapped to 2.1 since Apple only support that legacy version.
+ // >=3.0 are mapped to a 3.2 core profile.
+ bool legacy = m_settings.majorVersion < 3;
+
+ if (legacy)
+ {
+ m_settings.attributeFlags &= ~ContextSettings::Core;
+ m_settings.majorVersion = 2;
+ m_settings.minorVersion = 1;
+ attrs.push_back(NSOpenGLPFAOpenGLProfile);
+ attrs.push_back(NSOpenGLProfileVersionLegacy);
+ }
+ else
+ {
+ if (!(m_settings.attributeFlags & ContextSettings::Core))
+ {
+ sf::err() << "Warning. Compatibility profile not supported on this platform." << std::endl;
+ m_settings.attributeFlags |= ContextSettings::Core;
+ }
+ m_settings.majorVersion = 3;
+ m_settings.minorVersion = 2;
+ attrs.push_back(NSOpenGLPFAOpenGLProfile);
+ attrs.push_back(NSOpenGLProfileVersion3_2Core);
+ }
+
+ if (m_settings.attributeFlags & ContextSettings::Debug)
+ {
+ sf::err() << "Warning. OpenGL debugging not supported on this platform." << std::endl;
+ m_settings.attributeFlags &= ~ContextSettings::Debug;
+ }
+
+ attrs.push_back((NSOpenGLPixelFormatAttribute)0); // end of array
+
+ // All OS X pixel formats are sRGB capable
+ m_settings.sRgbCapable = true;
+
+ // Create the pixel format.
+ NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attrs[0]];
+
+ if (pixFmt == nil)
+ {
+ sf::err() << "Error. Unable to find a suitable pixel format." << std::endl;
+ return;
+ }
+
+ // Use the shared context if one is given.
+ NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil;
+
+ if (sharedContext != nil)
+ {
+ [NSOpenGLContext clearCurrentContext];
+
+ if (sharedContext == [NSOpenGLContext currentContext])
+ {
+ sf::err() << "Failed to deactivate shared context before sharing" << std::endl;
+ return;
+ }
+ }
+
+ // Create the context.
+ m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt
+ shareContext:sharedContext];
+
+ if (m_context == nil)
+ {
+ sf::err() << "Error. Unable to create the context. Retrying without shared context." << std::endl;
+ m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt
+ shareContext:nil];
+
+ if (m_context == nil)
+ sf::err() << "Error. Unable to create the context." << std::endl;
+ else
+ sf::err() << "Warning. New context created without shared context." << std::endl;
+ }
+
+ // Free up.
+ [pixFmt release];
+
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h
new file mode 100644
index 0000000..ee2ef66
--- /dev/null
+++ b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h
@@ -0,0 +1,70 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+
+namespace sf {
+ namespace priv {
+ class WindowImplCocoa;
+ }
+}
+
+////////////////////////////////////////////////////////////
+/// Keyboard Modifiers Helper
+///
+/// Handle left & right modifiers (cmd, ctrl, alt, shift)
+/// events and send them back to the requester.
+///
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+/// \brief Initialize the global state (only if needed)
+///
+/// It needs to be called before any event, e.g. in the window constructor.
+///
+////////////////////////////////////////////////////////////
+void initialiseKeyboardHelper(void);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Set up a SFML key event based on the given modifiers flags and key code
+///
+////////////////////////////////////////////////////////////
+sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Handle the state of modifiers keys
+///
+/// Send key released & pressed events to the requester.
+///
+////////////////////////////////////////////////////////////
+void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& requester);
+
+
diff --git a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm
new file mode 100644
index 0000000..763f2ca
--- /dev/null
+++ b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm
@@ -0,0 +1,240 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+
+#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h>
+
+
+////////////////////////////////////////////////////////////
+/// Here are define the mask value for the 'modifiers'
+/// keys (cmd, ctrl, alt, shift)
+///
+////////////////////////////////////////////////////////////
+#define NSRightShiftKeyMask 0x020004
+#define NSLeftShiftKeyMask 0x020002
+#define NSRightCommandKeyMask 0x100010
+#define NSLeftCommandKeyMask 0x100008
+#define NSRightAlternateKeyMask 0x080040
+#define NSLeftAlternateKeyMask 0x080020
+#define NSRightControlKeyMask 0x042000
+#define NSLeftControlKeyMask 0x040001
+
+
+////////////////////////////////////////////////////////////
+// Local Data Structures
+////////////////////////////////////////////////////////////
+
+/// Modifiers states
+struct ModifiersState
+{
+ BOOL rightShiftWasDown;
+ BOOL leftShiftWasDown;
+ BOOL rightCommandWasDown;
+ BOOL leftCommandWasDown;
+ BOOL rightAlternateWasDown;
+ BOOL leftAlternateWasDown;
+ BOOL leftControlWasDown;
+ BOOL rightControlWasDown;
+};
+
+
+////////////////////////////////////////////////////////////
+// Global Variables
+////////////////////////////////////////////////////////////
+
+/// Share 'modifiers' state with all windows to correctly fire pressed/released events
+static ModifiersState state;
+static BOOL isStateInitialized = NO;
+
+
+////////////////////////////////////////////////////////////
+// Local & Private Functions
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+/// \brief Carefully observe if the key mask is on in the modifiers
+///
+////////////////////////////////////////////////////////////
+BOOL isKeyMaskActive(NSUInteger modifiers, NSUInteger mask);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Handle one modifier key mask
+///
+/// Update the key state and send events to the requester
+///
+////////////////////////////////////////////////////////////
+void processOneModifier(NSUInteger modifiers, NSUInteger mask,
+ BOOL& wasDown, sf::Keyboard::Key key,
+ sf::priv::WindowImplCocoa& requester);
+
+
+////////////////////////////////////////////////////////////
+/// \brief Handle left & right modifier keys
+///
+/// Update the keys state and send events to the requester
+///
+////////////////////////////////////////////////////////////
+void processLeftRightModifiers(NSUInteger modifiers,
+ NSUInteger leftMask, NSUInteger rightMask,
+ BOOL& leftWasDown, BOOL& rightWasDown,
+ sf::Keyboard::Key leftKey, sf::Keyboard::Key rightKey,
+ sf::priv::WindowImplCocoa& requester);
+
+
+
+////////////////////////////////////////////////////////////
+// Implementations
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////
+void initialiseKeyboardHelper(void)
+{
+ if (isStateInitialized) return;
+
+ NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
+
+ // Load current keyboard state
+ state.leftShiftWasDown = isKeyMaskActive(modifiers, NSLeftShiftKeyMask);
+ state.rightShiftWasDown = isKeyMaskActive(modifiers, NSRightShiftKeyMask);
+ state.leftCommandWasDown = isKeyMaskActive(modifiers, NSLeftCommandKeyMask);
+ state.rightCommandWasDown = isKeyMaskActive(modifiers, NSRightCommandKeyMask);
+ state.leftAlternateWasDown = isKeyMaskActive(modifiers, NSLeftAlternateKeyMask);
+ state.rightAlternateWasDown = isKeyMaskActive(modifiers, NSRightAlternateKeyMask);
+ state.leftControlWasDown = isKeyMaskActive(modifiers, NSLeftControlKeyMask);
+ state.rightControlWasDown = isKeyMaskActive(modifiers, NSRightControlKeyMask);
+
+ isStateInitialized = YES;
+}
+
+
+////////////////////////////////////////////////////////
+sf::Event::KeyEvent keyEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key)
+{
+ sf::Event::KeyEvent event;
+ event.code = key;
+ event.alt = modifiers & NSAlternateKeyMask;
+ event.control = modifiers & NSControlKeyMask;
+ event.shift = modifiers & NSShiftKeyMask;
+ event.system = modifiers & NSCommandKeyMask;
+
+ return event;
+}
+
+
+////////////////////////////////////////////////////////
+void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& requester)
+{
+ // Handle shift
+ processLeftRightModifiers(
+ modifiers,
+ NSLeftShiftKeyMask, NSRightShiftKeyMask,
+ state.leftShiftWasDown, state.rightShiftWasDown,
+ sf::Keyboard::LShift, sf::Keyboard::RShift,
+ requester
+ );
+
+ // Handle command
+ processLeftRightModifiers(
+ modifiers,
+ NSLeftCommandKeyMask, NSRightCommandKeyMask,
+ state.leftCommandWasDown, state.rightCommandWasDown,
+ sf::Keyboard::LSystem, sf::Keyboard::RSystem,
+ requester
+ );
+
+ // Handle option (alt)
+ processLeftRightModifiers(
+ modifiers,
+ NSLeftAlternateKeyMask, NSRightAlternateKeyMask,
+ state.leftAlternateWasDown, state.rightAlternateWasDown,
+ sf::Keyboard::LAlt, sf::Keyboard::RAlt,
+ requester
+ );
+
+ // Handle control
+ processLeftRightModifiers(
+ modifiers,
+ NSLeftControlKeyMask, NSRightControlKeyMask,
+ state.leftControlWasDown, state.rightControlWasDown,
+ sf::Keyboard::LControl, sf::Keyboard::RControl,
+ requester
+ );
+}
+
+
+////////////////////////////////////////////////////////
+BOOL isKeyMaskActive(NSUInteger modifiers, NSUInteger mask)
+{
+ // Here we need to make sure it's exactly the mask since some masks
+ // share some bits such that the & operation would result in a non zero
+ // value without corresponding to the processed key.
+ return (modifiers & mask) == mask;
+}
+
+
+////////////////////////////////////////////////////////
+void processOneModifier(NSUInteger modifiers, NSUInteger mask,
+ BOOL& wasDown, sf::Keyboard::Key key,
+ sf::priv::WindowImplCocoa& requester)
+{
+ // Setup a potential event key.
+ sf::Event::KeyEvent event = keyEventWithModifiers(modifiers, key);
+
+ // State
+ BOOL isDown = isKeyMaskActive(modifiers, mask);
+
+ // Check for key pressed event
+ if (isDown && !wasDown)
+ requester.keyDown(event);
+
+ // And check for key released event
+ else if (!isDown && wasDown)
+ requester.keyUp(event);
+
+ // else isDown == wasDown, so no change
+
+ // Update state
+ wasDown = isDown;
+}
+
+
+////////////////////////////////////////////////////////
+void processLeftRightModifiers(NSUInteger modifiers,
+ NSUInteger leftMask, NSUInteger rightMask,
+ BOOL& leftWasDown, BOOL& rightWasDown,
+ sf::Keyboard::Key leftKey, sf::Keyboard::Key rightKey,
+ sf::priv::WindowImplCocoa& requester)
+{
+ processOneModifier(modifiers, leftMask, leftWasDown, leftKey, requester);
+ processOneModifier(modifiers, rightMask, rightWasDown, rightKey, requester);
+}
+
+
diff --git a/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm b/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm
new file mode 100644
index 0000000..907de16
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm
@@ -0,0 +1,220 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <SFML/Window/OSX/HIDInputManager.hpp> // For localizedKeys and nonLocalizedKeys
+
+#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h>
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFOpenGLView+keyboard_priv.h>
+
+////////////////////////////////////////////////////////////
+/// In this file, we implement keyboard handling for SFOpenGLView
+///
+////////////////////////////////////////////////////////////
+
+
+@implementation SFOpenGLView (keyboard)
+
+
+////////////////////////////////////////////////////////
+-(BOOL)acceptsFirstResponder
+{
+ // Accepts key event.
+ return YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)canBecomeKeyView
+{
+ // Accepts key event.
+ return YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)enableKeyRepeat
+{
+ m_useKeyRepeat = YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)disableKeyRepeat
+{
+ m_useKeyRepeat = NO;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)keyDown:(NSEvent*)theEvent
+{
+ // Transmit to non-SFML responder
+ [[self nextResponder] keyDown:theEvent];
+
+ if (m_requester == 0)
+ return;
+
+ // Handle key down event
+ if (m_useKeyRepeat || ![theEvent isARepeat])
+ {
+ sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
+
+ if (key.code != sf::Keyboard::Unknown) // The key is recognized.
+ m_requester->keyDown(key);
+ }
+
+
+ // Handle text entered event:
+ // Ignore event if we don't want repeated keystrokes
+ if (m_useKeyRepeat || ![theEvent isARepeat])
+ {
+ // Ignore escape key and other non text keycode (See NSEvent.h)
+ // because they produce a sound alert.
+ if ([SFOpenGLView isValidTextUnicode:theEvent])
+ {
+ // Send the event to the hidden text view for processing
+ [m_hiddenTextView interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ }
+
+ // Carefully handle backspace and delete..
+ // Note: the event is intentionally sent to the hidden view
+ // even if we do something more specific below. This way
+ // key combination are correctly interpreted.
+
+ unsigned short keycode = [theEvent keyCode];
+
+ // Backspace
+ if (keycode == 0x33)
+ {
+ // Send the correct Unicode value (i.e. 8) instead of 127 (which is 'delete')
+ m_requester->textEntered(8);
+ }
+
+ // Delete
+ else if ((keycode == 0x75) || (keycode == NSDeleteFunctionKey))
+ {
+ // Instead of the value 63272 we send 127.
+ m_requester->textEntered(127);
+ }
+
+ // Otherwise, let's see what our hidden field has computed
+ else
+ {
+ NSString* string = [m_hiddenTextView string];
+
+ // Send each character to SFML event requester
+ for (NSUInteger index = 0; index < [string length]; ++index)
+ m_requester->textEntered([string characterAtIndex:index]);
+
+ // Empty our hidden cache
+ [m_hiddenTextView setString:@""];
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)sfKeyUp:(NSEvent*)theEvent
+{
+ // For some mystic reasons, key released events don't work the same way
+ // as key pressed events... We somewhat hijack the event chain of response
+ // in -[SFApplication sendEvent:] and resume this chain with the next
+ // responder.
+ // This is workaround to make sure key released events are fired in
+ // fullscreen window too.
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] keyUp:theEvent];
+
+ if (m_requester == 0)
+ return;
+
+ sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
+
+ if (key.code != sf::Keyboard::Unknown) // The key is recognized.
+ m_requester->keyUp(key);
+}
+
+
+////////////////////////////////////////////////////////
+-(void)flagsChanged:(NSEvent*)theEvent
+{
+ // Transmit to non-SFML responder
+ [[self nextResponder] flagsChanged:theEvent];
+
+ if (m_requester == 0)
+ return;
+
+ NSUInteger modifiers = [theEvent modifierFlags];
+ handleModifiersChanged(modifiers, *m_requester);
+}
+
+
+////////////////////////////////////////////////////////
++(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event
+{
+ // Key code
+ sf::Keyboard::Key key = sf::Keyboard::Unknown;
+
+ // First we look if the key down is from a list of characters
+ // that depend on keyboard localization.
+ NSString* string = [event charactersIgnoringModifiers];
+ if ([string length] > 0)
+ key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]);
+
+ // If the key is not a localized one, we try to find a corresponding code
+ // through virtual key code.
+ if (key == sf::Keyboard::Unknown)
+ key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]);
+
+ return keyEventWithModifiers([event modifierFlags], key);
+}
+
+
+////////////////////////////////////////////////////////
++(BOOL)isValidTextUnicode:(NSEvent*)event
+{
+ if ([event keyCode] == 0x35) // Escape
+ {
+ return false;
+ }
+ else if ([[event characters] length] > 0)
+ {
+ unichar code = [[event characters] characterAtIndex:0];
+ return ((code < 0xF700) || (code > 0xF8FF));
+ }
+ else
+ {
+ return true;
+ }
+}
+
+@end
+
diff --git a/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h b/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h
new file mode 100644
index 0000000..6003c00
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Mouse.hpp>
+
+#import <AppKit/AppKit.h>
+
+
+////////////////////////////////////////////////////////////
+/// Here are defined a few private messages for keyboard
+/// handling in SFOpenGLView.
+///
+////////////////////////////////////////////////////////////
+
+
+@interface SFOpenGLView (keyboard_priv)
+
+////////////////////////////////////////////////////////////
+/// \brief Convert a key down/up NSEvent into an SFML key event
+///
+/// The conversion is based on localizedKeys and nonLocalizedKeys functions.
+///
+/// \param event a key event
+///
+/// \return sf::Keyboard::Unknown as Code if the key is unknown
+///
+////////////////////////////////////////////////////////////
++(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event;
+
+////////////////////////////////////////////////////////////
+/// \brief Check if the event represent some Unicode text
+///
+/// The event is assumed to be a key down event.
+/// False is returned if the event is either escape or a non text Unicode.
+///
+/// \param event a key down event
+///
+/// \return true if event represents a Unicode character, false otherwise
+///
+////////////////////////////////////////////////////////////
++(BOOL)isValidTextUnicode:(NSEvent*)event;
+
+@end
diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm
new file mode 100644
index 0000000..4b23042
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm
@@ -0,0 +1,421 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <cmath>
+
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h>
+
+
+////////////////////////////////////////////////////////////
+/// In this file, we implement mouse handling for SFOpenGLView
+///
+////////////////////////////////////////////////////////////
+
+@implementation SFOpenGLView (mouse)
+
+////////////////////////////////////////////////////////
+-(void)setCursor:(NSCursor*)cursor
+{
+ m_cursor = cursor;
+
+ // indirect call to resetCursorRects to set the cursor
+ [self.window invalidateCursorRectsForView:self];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)resetCursorRects
+{
+ // addCursorRect:cursor: has to be called from within this function!
+ [self addCursorRect:[self frame] cursor:m_cursor];
+ [m_cursor setOnMouseEntered:YES];
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)isMouseInside
+{
+ NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream];
+ NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil];
+
+ return NSPointInRect(relativeToView, [self bounds]);
+}
+
+
+////////////////////////////////////////////////////////
+-(void)updateMouseState
+{
+ // Update in/out state
+ BOOL mouseWasIn = m_mouseIsIn;
+ m_mouseIsIn = [self isMouseInside];
+
+ // Send event if needed.
+ if (m_requester != 0)
+ {
+ if (mouseWasIn && !m_mouseIsIn)
+ m_requester->mouseMovedOut();
+ else if (!mouseWasIn && m_mouseIsIn)
+ m_requester->mouseMovedIn();
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed
+{
+ m_cursorGrabbed = grabbed;
+
+ [self updateCursorGrabbed];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)handleMouseDown:(NSEvent*)theEvent
+{
+ sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent];
+
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ if (button != sf::Mouse::ButtonCount)
+ m_requester->mouseDownAt(button, loc.x, loc.y);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////////
+-(void)handleMouseUp:(NSEvent*)theEvent
+{
+ sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent];
+
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ if (button != sf::Mouse::ButtonCount)
+ m_requester->mouseUpAt(button, loc.x, loc.y);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseMoved:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseMoved:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseDragged:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseDragged:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)handleMouseMove:(NSEvent*)theEvent
+{
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ // If the cursor is grabbed, cursorPositionFromEvent: will
+ // return its correct position but not move actually it
+ // so we do it now.
+ if ([self isCursorCurrentlyGrabbed])
+ [self moveCursorTo:loc];
+
+ // Make sure the point is inside the view.
+ // (mouseEntered: and mouseExited: are not immediately called
+ // when the mouse is dragged. That would be too easy!)
+ [self updateMouseState];
+ if ((m_requester != 0) && m_mouseIsIn)
+ m_requester->mouseMovedAt(loc.x, loc.y);
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)isCursorCurrentlyGrabbed
+{
+ return [[self window] isKeyWindow] && m_cursorGrabbed;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)updateCursorGrabbed
+{
+ // Disable/enable normal movements of the cursor
+ // and project the cursor if needed.
+ if ([self isCursorCurrentlyGrabbed])
+ {
+ CGAssociateMouseAndMouseCursorPosition(NO);
+
+ // Similarly to handleMouseMove: but without event.
+ NSPoint loc = [self cursorPositionFromEvent:nil];
+ [self moveCursorTo:loc];
+ }
+ else
+ {
+ CGAssociateMouseAndMouseCursorPosition(YES);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)moveCursorTo:(NSPoint)loc
+{
+ // Convert the point from SFML coord system to screen coord system.
+ NSPoint screenLocation = [self computeGlobalPositionOfRelativePoint:loc];
+
+ // This won't produce a move event, which is perfect if the cursor was grabbed
+ // as we move it manually based on delta values of the cursor.
+ CGDisplayMoveCursorToPoint([self displayId], NSPointToCGPoint(screenLocation));
+}
+
+
+////////////////////////////////////////////////////////
+-(CGDirectDisplayID)displayId
+{
+ NSScreen* screen = [[self window] screen];
+ NSNumber* displayId = [[screen deviceDescription] objectForKey:@"NSScreenNumber"];
+ return [displayId intValue];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)scrollWheel:(NSEvent*)theEvent
+{
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+ m_requester->mouseWheelScrolledAt([theEvent deltaX], [theEvent deltaY], loc.x, loc.y);
+ }
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] scrollWheel:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseEntered:(NSEvent*)theEvent
+{
+ (void)theEvent;
+ [self updateMouseState];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseExited:(NSEvent*)theEvent
+{
+ (void)theEvent;
+ [self updateMouseState];
+}
+
+
+////////////////////////////////////////////////////////
+-(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil
+{
+ NSPoint rawPos;
+
+ // If no event given then get current mouse pos.
+ if (eventOrNil == nil)
+ rawPos = [[self window] mouseLocationOutsideOfEventStream];
+ else
+ rawPos = [eventOrNil locationInWindow];
+
+ if ([self isCursorCurrentlyGrabbed])
+ {
+ if (eventOrNil != nil)
+ {
+ // Special case when the mouse is grabbed:
+ // we need to take into account the delta since the cursor
+ // is dissociated from its position.
+
+ // Ignore any non-move related event
+ if (([eventOrNil type] == NSMouseMoved) ||
+ ([eventOrNil type] == NSLeftMouseDragged) ||
+ ([eventOrNil type] == NSRightMouseDragged) ||
+ ([eventOrNil type] == NSOtherMouseDragged))
+ {
+ // Without this factor, the cursor flies around waaay too fast!
+ // But I don't know if it because of retina display or because
+ // some event are sent twice (and that in itself is another mystery).
+ CGFloat factor = 2;
+
+ // Also, this factor is not the same when keeping track of how much
+ // we move the cursor (buffers) when projecting the cursor into the
+ // view when grabbing the cursor for the first time.
+ CGFloat factorBuffer = m_fullscreen ? 1 : 2;
+
+ CGFloat deltaX = [eventOrNil deltaX];
+ CGFloat deltaY = [eventOrNil deltaY];
+
+ // If the buffer for X is empty, move the cursor;
+ // otherwise decrement this buffer a bit.
+ if (m_deltaXBuffer <= 0)
+ rawPos.x += deltaX / factor;
+ else
+ m_deltaXBuffer -= std::abs(deltaX / factorBuffer);
+
+ // Rinse and repeat for Y.
+ if (m_deltaYBuffer <= 0)
+ rawPos.y -= deltaY / factor;
+ else
+ m_deltaYBuffer -= std::abs(deltaY / factorBuffer);
+ }
+ }
+
+ // We also make sure the new point is inside the view
+ NSSize size = [self frame].size;
+ NSPoint origin = [self frame].origin;
+ NSPoint oldPos = rawPos;
+ rawPos.x = std::min(std::max(origin.x, rawPos.x), origin.x + size.width - 1);
+ rawPos.y = std::min(std::max(origin.y + 1, rawPos.y), origin.y + size.height);
+ // Note: the `-1` and `+1` on the two lines above prevent the user to click
+ // on the left or below the window, repectively, and therefore prevent the
+ // application to lose focus by accident. The sign of this offset is determinded
+ // by the direction of the x and y axis.
+
+ // Increase X and Y buffer with the distance of the projection
+ m_deltaXBuffer += std::abs(rawPos.x - oldPos.x);
+ m_deltaYBuffer += std::abs(rawPos.y - oldPos.y);
+ }
+
+ NSPoint loc = [self convertPoint:rawPos fromView:nil];
+
+ // Don't forget to change to SFML coord system.
+ float h = [self frame].size.height;
+ loc.y = h - loc.y;
+
+ return loc;
+}
+
+
+////////////////////////////////////////////////////////
++(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event
+{
+ switch ([event buttonNumber])
+ {
+ case 0: return sf::Mouse::Left;
+ case 1: return sf::Mouse::Right;
+ case 2: return sf::Mouse::Middle;
+ case 3: return sf::Mouse::XButton1;
+ case 4: return sf::Mouse::XButton2;
+ default: return sf::Mouse::ButtonCount; // Never happens! (hopefully)
+ }
+}
+
+
+@end
diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h
new file mode 100644
index 0000000..6f509ad
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Mouse.hpp>
+
+#import <AppKit/AppKit.h>
+
+
+////////////////////////////////////////////////////////////
+/// Here are defined a few private messages for mouse
+/// handling in SFOpenGLView.
+///
+////////////////////////////////////////////////////////////
+
+
+@interface SFOpenGLView (mouse_priv)
+
+////////////////////////////////////////////////////////////
+/// \brief Update the mouse state (in or out)
+///
+/// Fire an event if its state has changed.
+///
+////////////////////////////////////////////////////////////
+-(void)updateMouseState;
+
+////////////////////////////////////////////////////////////
+/// \brief handle mouse down event
+///
+////////////////////////////////////////////////////////////
+-(void)handleMouseDown:(NSEvent*)theEvent;
+
+////////////////////////////////////////////////////////////
+/// \brief handle mouse up event
+///
+////////////////////////////////////////////////////////////
+-(void)handleMouseUp:(NSEvent*)theEvent;
+
+////////////////////////////////////////////////////////////
+/// \brief handle mouse move event
+///
+////////////////////////////////////////////////////////////
+-(void)handleMouseMove:(NSEvent*)theEvent;
+
+////////////////////////////////////////////////////////////
+/// \brief Check whether the cursor is grabbed or not
+///
+/// The cursor is grabbed if the window is active (key) and
+/// the user wants to grab it.
+///
+////////////////////////////////////////////////////////////
+-(BOOL)isCursorCurrentlyGrabbed;
+
+////////////////////////////////////////////////////////////
+/// \brief (Dis)connect the cursor's movements from/to the system
+/// and project the cursor into the view
+///
+////////////////////////////////////////////////////////////
+-(void)updateCursorGrabbed;
+
+////////////////////////////////////////////////////////////
+/// \brief Move the cursor to the given location
+///
+/// \param loc location expressed in SFML coordinate system
+///
+////////////////////////////////////////////////////////////
+-(void)moveCursorTo:(NSPoint)loc;
+
+////////////////////////////////////////////////////////////
+/// \brief Get the display identifier on which the view is
+///
+////////////////////////////////////////////////////////////
+-(CGDirectDisplayID)displayId;
+
+////////////////////////////////////////////////////////////
+/// \brief Convert the NSEvent mouse button type to SFML type
+///
+/// \param event a mouse button event
+///
+/// \return Left, Right, ..., or ButtonCount if the button is unknown
+///
+////////////////////////////////////////////////////////////
++(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event;
+
+@end
diff --git a/src/SFML/Window/OSX/SFOpenGLView.h b/src/SFML/Window/OSX/SFOpenGLView.h
new file mode 100644
index 0000000..7444ff7
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView.h
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+
+namespace sf {
+ namespace priv {
+ class WindowImplCocoa;
+ }
+}
+
+@class SFSilentResponder;
+
+////////////////////////////////////////////////////////////
+/// \brief Specialized NSOpenGLView
+///
+/// Handle event and send them back to the requester.
+///
+/// NSTrackingArea is used to keep track of mouse events. We also
+/// need to be able to ignore mouse event when exiting fullscreen.
+///
+/// Modifiers keys (cmd, ctrl, alt, shift) are handled by this class
+/// but the actual logic is done in SFKeyboardModifiersHelper.(h|mm).
+///
+/// The interface is subdivided into several categories in order
+/// to have multiple implementation files to divide this monolithic
+/// implementation. However, all attributes are defined in the main
+/// interface declaration right below.
+///
+/// Note about deltaXBuffer and deltaYBuffer: when grabbing the cursor
+/// for the first time, either by entering fullscreen or through
+/// setCursorGrabbed:, the cursor might be projected into the view.
+/// Doing this will result in a big delta (relative movement) in the
+/// next move event (cursorPositionFromEvent:), because no move event
+/// is generated, which in turn will give the impression that the user
+/// want to move the cursor by the same distance it was projected. To
+/// prevent the cursor to fly twice the distance we keep track of how
+/// much the cursor was projected in deltaXBuffer and deltaYBuffer. In
+/// cursorPositionFromEvent: we can then reduce/augment those buffers
+/// to determine when a move event should result in an actual move of
+/// the cursor (that was disconnected from the system).
+///
+////////////////////////////////////////////////////////////
+@interface SFOpenGLView : NSOpenGLView
+{
+ sf::priv::WindowImplCocoa* m_requester; ///< View's requester
+ BOOL m_useKeyRepeat; ///< Key repeat setting
+ BOOL m_mouseIsIn; ///< Mouse positional state
+ NSCursor* m_cursor; ///< Active cursor
+ NSTrackingArea* m_trackingArea; ///< Mouse tracking area
+ BOOL m_fullscreen; ///< Indicate whether the window is fullscreen or not
+ CGFloat m_scaleFactor; ///< Display scale factor (e.g. 1x for classic display, 2x for retina)
+ BOOL m_cursorGrabbed; ///< Is the mouse cursor trapped?
+ CGFloat m_deltaXBuffer; ///< See note about cursor grabbing above
+ CGFloat m_deltaYBuffer; ///< See note about cursor grabbing above
+
+ // Hidden text view used to convert key event to actual chars.
+ // We use a silent responder to prevent sound alerts.
+ SFSilentResponder* m_silentResponder;
+ NSTextView* m_hiddenTextView;
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Create the SFML OpenGL view
+///
+/// NB: -initWithFrame: is also implemented to default isFullscreen to NO
+/// in case SFOpenGLView is created with the standard message.
+///
+/// To finish the initialization -finishInit should be called too.
+///
+/// \param frameRect dimension of the view
+/// \param isFullscreen fullscreen flag
+///
+/// \return an initialized view
+///
+////////////////////////////////////////////////////////////
+-(id)initWithFrame:(NSRect)frameRect fullscreen:(BOOL)isFullscreen;
+
+////////////////////////////////////////////////////////////
+/// \brief Finish the creation of the SFML OpenGL view
+///
+/// This method should be called after the view was added to a window
+///
+////////////////////////////////////////////////////////////
+-(void)finishInit;
+
+////////////////////////////////////////////////////////////
+/// \brief Apply the given requester to the view
+///
+/// \param requester new 'requester' of the view
+///
+////////////////////////////////////////////////////////////
+-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester;
+
+////////////////////////////////////////////////////////////
+/// \brief Compute the position in global coordinate
+///
+/// \param point a point in SFML coordinate
+///
+/// \return the global coordinates of the point
+///
+////////////////////////////////////////////////////////////
+-(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point;
+
+////////////////////////////////////////////////////////////
+/// \brief Get the display scale factor
+///
+/// \return e.g. 1.0 for classic display, 2.0 for retina display
+///
+////////////////////////////////////////////////////////////
+-(CGFloat)displayScaleFactor;
+
+@end
+
+@interface SFOpenGLView (keyboard)
+
+////////////////////////////////////////////////////////////
+/// \brief Enable key repeat
+///
+////////////////////////////////////////////////////////////
+-(void)enableKeyRepeat;
+
+////////////////////////////////////////////////////////////
+/// \brief Disable key repeat
+///
+////////////////////////////////////////////////////////////
+-(void)disableKeyRepeat;
+
+@end
+
+@interface SFOpenGLView (mouse)
+
+////////////////////////////////////////////////////////////
+/// \brief Set the system cursor for the window area
+///
+////////////////////////////////////////////////////////////
+-(void)setCursor:(NSCursor*)cursor;
+
+////////////////////////////////////////////////////////////
+/// \brief Compute the position of the cursor
+///
+/// \param eventOrNil if nil the cursor position is the current one
+///
+/// \return the mouse position in SFML coord system
+///
+////////////////////////////////////////////////////////////
+-(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil;
+
+////////////////////////////////////////////////////////////
+/// \brief Determine where the mouse is
+///
+/// \return true when the mouse is inside the OpenGL view, false otherwise
+///
+////////////////////////////////////////////////////////////
+-(BOOL)isMouseInside;
+
+////////////////////////////////////////////////////////////
+/// Clips or releases the mouse cursor
+///
+/// Generate a MouseEntered event when it makes sense.
+///
+/// \param grabbed YES to grab, NO to release
+///
+////////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed;
+
+////////////////////////////////////////////////////////////
+/// Update the cursor position according to the grabbing behaviour
+///
+/// This function has to be called when the window's state change
+///
+////////////////////////////////////////////////////////////
+-(void)updateCursorGrabbed;
+
+@end
diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm
new file mode 100644
index 0000000..e8fca84
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView.mm
@@ -0,0 +1,352 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <SFML/System/Err.hpp>
+
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h>
+#import <SFML/Window/OSX/SFSilentResponder.h>
+
+
+////////////////////////////////////////////////////////////
+/// SFOpenGLView class: Privates Methods Declaration
+///
+////////////////////////////////////////////////////////////
+@interface SFOpenGLView ()
+
+////////////////////////////////////////////////////////////
+/// \brief Handle screen changed event
+///
+////////////////////////////////////////////////////////////
+-(void)updateScaleFactor;
+
+////////////////////////////////////////////////////////////
+/// \brief Handle view resized event
+///
+////////////////////////////////////////////////////////////
+-(void)viewDidEndLiveResize;
+
+////////////////////////////////////////////////////////////
+/// \brief Callback for focus event
+///
+////////////////////////////////////////////////////////////
+-(void)windowDidBecomeKey:(NSNotification*)notification;
+
+////////////////////////////////////////////////////////////
+/// \brief Callback for unfocus event
+///
+////////////////////////////////////////////////////////////
+-(void)windowDidResignKey:(NSNotification*)notification;
+
+////////////////////////////////////////////////////////////
+/// \brief Handle going in fullscreen mode
+///
+////////////////////////////////////////////////////////////
+-(void)enterFullscreen;
+
+////////////////////////////////////////////////////////////
+/// \brief Handle exiting fullscreen mode
+///
+////////////////////////////////////////////////////////////
+-(void)exitFullscreen;
+
+@end
+
+@implementation SFOpenGLView
+
+#pragma mark
+#pragma mark SFOpenGLView's methods
+
+////////////////////////////////////////////////////////
+-(id)initWithFrame:(NSRect)frameRect
+{
+ return [self initWithFrame:frameRect fullscreen:NO];
+}
+
+////////////////////////////////////////////////////////
+-(id)initWithFrame:(NSRect)frameRect fullscreen:(BOOL)isFullscreen
+{
+ if ((self = [super initWithFrame:frameRect]))
+ {
+ [self setRequesterTo:0];
+ [self enableKeyRepeat];
+
+ // Register for mouse move event
+ m_mouseIsIn = [self isMouseInside];
+ NSUInteger opts = (NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag);
+ m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:opts
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:m_trackingArea];
+
+ m_fullscreen = isFullscreen;
+ m_scaleFactor = 1.0; // Default value; it will be updated in finishInit
+ m_cursorGrabbed = NO;
+ m_deltaXBuffer = 0;
+ m_deltaYBuffer = 0;
+ m_cursor = [NSCursor arrowCursor];
+
+ // Create a hidden text view for parsing key down event properly
+ m_silentResponder = [[SFSilentResponder alloc] init];
+ m_hiddenTextView = [[NSTextView alloc] initWithFrame:NSZeroRect];
+ [m_hiddenTextView setNextResponder:m_silentResponder];
+
+ // Request high resolution on high DPI displays
+ [self setWantsBestResolutionOpenGLSurface:YES];
+
+ // At that point, the view isn't attached to a window. We defer the rest of
+ // the initialization process to later.
+ }
+
+ return self;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)update
+{
+ // In order to prevent an infinite recursion when the window/view is
+ // resized to zero-height/width, we ignore update event when resizing.
+ if (![self inLiveResize]) {
+ [super update];
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)finishInit
+{
+ // Register for window focus events
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowDidBecomeKey:)
+ name:NSWindowDidBecomeKeyNotification
+ object:[self window]];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowDidResignKey:)
+ name:NSWindowDidResignKeyNotification
+ object:[self window]];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowDidResignKey:)
+ name:NSWindowWillCloseNotification
+ object:[self window]];
+
+ // Register for changed screen and changed screen's profile events
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(updateScaleFactor)
+ name:NSWindowDidChangeScreenNotification
+ object:[self window]];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(updateScaleFactor)
+ name:NSWindowDidChangeScreenProfileNotification
+ object:[self window]];
+
+ // Now that we have a window, set up correctly the scale factor and cursor grabbing
+ [self updateScaleFactor];
+ [self updateCursorGrabbed]; // update for fullscreen
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester
+{
+ m_requester = requester;
+}
+
+
+////////////////////////////////////////////////////////
+-(NSPoint)convertPointToScreen:(NSPoint)point
+{
+ NSRect rect = NSZeroRect;
+ rect.origin = point;
+ rect = [[self window] convertRectToScreen:rect];
+ return rect.origin;
+}
+
+
+////////////////////////////////////////////////////////
+-(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point
+{
+ // Flip SFML coordinates to match window coordinates
+ point.y = [self frame].size.height - point.y;
+
+ // Get the position of (x, y) in the coordinate system of the window.
+ point = [self convertPoint:point toView:self];
+ point = [self convertPoint:point toView:nil]; // nil means window
+
+ // Convert it to screen coordinates
+ point = [self convertPointToScreen:point];
+
+ // Flip screen coordinates to match CGDisplayMoveCursorToPoint referential.
+ const float screenHeight = [[[self window] screen] frame].size.height;
+ point.y = screenHeight - point.y;
+
+ return point;
+}
+
+
+////////////////////////////////////////////////////////
+-(CGFloat)displayScaleFactor
+{
+ return m_scaleFactor;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)updateScaleFactor
+{
+ NSWindow* window = [self window];
+ NSScreen* screen = window ? [window screen] : [NSScreen mainScreen];
+ CGFloat oldScaleFactor = m_scaleFactor;
+ m_scaleFactor = [screen backingScaleFactor];
+
+ // Send a resize event if the scaling factor changed
+ if ((m_scaleFactor != oldScaleFactor) && (m_requester != 0)) {
+ NSSize newSize = [self frame].size;
+ m_requester->windowResized(newSize.width, newSize.height);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)viewDidEndLiveResize
+{
+ // We use viewDidEndLiveResize to notify the user ONCE
+ // only, when the resizing is finished.
+ // In a perfect world we would like to notify the user
+ // in live that the window is being resized. However,
+ // it seems impossible to forward to the user
+ // NSViewFrameDidChangeNotification before the resizing
+ // is done. Several notifications are emitted but they
+ // are all delivered after when the work is done.
+
+ [super viewDidEndLiveResize];
+
+ // Update mouse internal state.
+ [self updateMouseState];
+ [self updateCursorGrabbed];
+
+ // Update the OGL view to fit the new size.
+ [self update];
+
+ // Send an event
+ if (m_requester == 0)
+ return;
+
+ // The new size
+ NSSize newSize = [self frame].size;
+ m_requester->windowResized(newSize.width, newSize.height);
+}
+
+////////////////////////////////////////////////////////
+-(void)windowDidBecomeKey:(NSNotification*)notification
+{
+ (void)notification;
+
+ [self updateCursorGrabbed];
+
+ if (m_requester)
+ m_requester->windowGainedFocus();
+
+ if (m_fullscreen)
+ [self enterFullscreen];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)windowDidResignKey:(NSNotification*)notification
+{
+ (void)notification;
+
+ [self updateCursorGrabbed];
+
+ if (m_requester)
+ m_requester->windowLostFocus();
+
+ if (m_fullscreen)
+ [self exitFullscreen];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)enterFullscreen
+{
+ // Remove the tracking area first,
+ // just to be sure we don't add it twice!
+ [self removeTrackingArea:m_trackingArea];
+ [self addTrackingArea:m_trackingArea];
+
+ // Fire an mouse entered event if needed
+ if (!m_mouseIsIn && (m_requester != 0))
+ m_requester->mouseMovedIn();
+
+ // Update status
+ m_mouseIsIn = YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)exitFullscreen
+{
+ [self removeTrackingArea:m_trackingArea];
+
+ // Fire an mouse left event if needed
+ if (m_mouseIsIn && (m_requester != 0))
+ m_requester->mouseMovedOut();
+
+ // Update status
+ m_mouseIsIn = NO;
+}
+
+
+#pragma mark
+#pragma mark Subclassing methods
+
+
+////////////////////////////////////////////////////////
+-(void)dealloc
+{
+ // Unregister for window focus events
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ // Unregister
+ [self removeTrackingArea:m_trackingArea];
+
+ // Release attributes
+ [m_hiddenTextView release];
+ [m_silentResponder release];
+ [m_trackingArea release];
+
+ [self setRequesterTo:0];
+
+ [super dealloc];
+}
+
+
+@end
diff --git a/src/SFML/Window/OSX/SFSilentResponder.h b/src/SFML/Window/OSX/SFSilentResponder.h
new file mode 100644
index 0000000..a9f9b7c
--- /dev/null
+++ b/src/SFML/Window/OSX/SFSilentResponder.h
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+
+////////////////////////////////////////////////////////////
+/// \brief Silent Responder used to prevent sound alert with key event
+///
+/// Mainly used by SFOpenGLView and its hidden text view.
+///
+////////////////////////////////////////////////////////////
+@interface SFSilentResponder : NSResponder
+
+-(void)doCommandBySelector:(SEL)sel;
+
+@end
+
diff --git a/src/SFML/Window/OSX/SFSilentResponder.m b/src/SFML/Window/OSX/SFSilentResponder.m
new file mode 100644
index 0000000..feb5783
--- /dev/null
+++ b/src/SFML/Window/OSX/SFSilentResponder.m
@@ -0,0 +1,40 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/SFSilentResponder.h>
+
+@implementation SFSilentResponder
+
+-(void)doCommandBySelector:(SEL)sel
+{
+ // Just do nothing, to prevent sound alerts
+ (void)sel;
+}
+
+@end
+
diff --git a/src/SFML/Window/OSX/SFViewController.h b/src/SFML/Window/OSX/SFViewController.h
new file mode 100644
index 0000000..69dc7a3
--- /dev/null
+++ b/src/SFML/Window/OSX/SFViewController.h
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/WindowImplDelegateProtocol.h>
+
+////////////////////////////////////////////////////////////
+/// Predefine some classes
+////////////////////////////////////////////////////////////
+@class SFOpenGLView;
+
+////////////////////////////////////////////////////////////
+/// \brief Implementation of WindowImplDelegateProtocol for view management
+///
+////////////////////////////////////////////////////////////
+
+@interface SFViewController : NSObject <WindowImplDelegateProtocol>
+{
+ NSView* m_view; ///< Underlying Cocoa view
+ SFOpenGLView* m_oglView; ///< OpenGL view
+ sf::priv::WindowImplCocoa* m_requester; ///< View's requester
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Initialize the view controller
+///
+/// \param view view to be controlled
+///
+/// \return an initialized view controller
+///
+////////////////////////////////////////////////////////////
+-(id)initWithView:(NSView*)view;
+
+@end
diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm
new file mode 100644
index 0000000..c92283b
--- /dev/null
+++ b/src/SFML/Window/OSX/SFViewController.mm
@@ -0,0 +1,279 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Err.hpp>
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+
+#import <SFML/Window/OSX/SFApplication.h>
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFViewController.h>
+
+@implementation SFViewController
+
+
+////////////////////////////////////////////////////////
+-(id)initWithView:(NSView *)view
+{
+ if ((self = [super init]))
+ {
+ m_requester = 0;
+
+ // Retain the view for our own use.
+ m_view = [view retain];
+
+ if (m_view == nil)
+ {
+ sf::err() << "No view was given to initWithWindow:." << std::endl;
+ return self;
+ }
+
+ // Create the view.
+ NSRect frame = [m_view frame];
+ frame.origin.x = 0;
+ frame.origin.y = 0;
+ m_oglView = [[SFOpenGLView alloc] initWithFrame:frame];
+
+ if (m_oglView == nil)
+ {
+ sf::err() << "Could not create an instance of NSOpenGLView "
+ << "in (SFViewController -initWithView:)."
+ << std::endl;
+
+ return self;
+ }
+
+ // Set the (OGL) view to the view as its "content" view.
+ [m_view addSubview:m_oglView];
+
+ [m_oglView setAutoresizingMask:[m_view autoresizingMask]];
+
+ [m_oglView finishInit];
+ }
+
+ return self;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)dealloc
+{
+ [self closeWindow];
+
+ [m_view release];
+ [m_oglView release];
+
+ [super dealloc];
+}
+
+
+////////////////////////////////////////////////////////
+-(CGFloat)displayScaleFactor
+{
+ return [m_oglView displayScaleFactor];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester
+{
+ // Forward to the view.
+ [m_oglView setRequesterTo:requester];
+ m_requester = requester;
+}
+
+
+////////////////////////////////////////////////////////
+-(sf::WindowHandle)getSystemHandle
+{
+ return m_view;
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)isMouseInside
+{
+ return [m_oglView isMouseInside];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed
+{
+ [m_oglView setCursorGrabbed:grabbed];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursor:(NSCursor*)cursor
+{
+ return [m_oglView setCursor:cursor];
+}
+
+
+////////////////////////////////////////////////////////////
+-(NSPoint)position
+{
+ // Origin is bottom-left corner of the window
+ return [m_view convertPoint:NSMakePoint(0, 0) toView:nil]; // nil means window
+}
+
+
+////////////////////////////////////////////////////////.
+-(void)setWindowPositionToX:(int)x Y:(int)y
+{
+ (void)x;
+ (void)y;
+ sf::err() << "Cannot move SFML area when SFML is integrated in a NSView. Use the view handler directly instead." << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+-(NSSize)size
+{
+ return [m_oglView frame].size;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)resizeTo:(unsigned int)width by:(unsigned int)height
+{
+ NSRect frame = NSMakeRect([m_view frame].origin.x,
+ [m_view frame].origin.y,
+ width,
+ height);
+
+ [m_view setFrame:frame];
+ [m_oglView setFrame:frame];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)changeTitle:(NSString*)title
+{
+ (void)title;
+ sf::err() << "Cannot change the title of the SFML area when SFML is integrated in a NSView." << std::endl;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)hideWindow
+{
+ [m_view setHidden:YES];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)showWindow
+{
+ [m_view setHidden:NO];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)closeWindow
+{
+ sf::err() << "Cannot close SFML area when SFML is integrated in a NSView." << std::endl;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)requestFocus
+{
+ // Note: this doesn't imply that the view will get any event.
+ // The user has to make sure events are forwarded to the view
+ // with the usual responder chain.
+ [[m_view window] makeKeyAndOrderFront:nil];
+
+ // In case the app is not active, make its dock icon bounce for one sec
+ [NSApp requestUserAttention:NSInformationalRequest];
+}
+
+
+////////////////////////////////////////////////////////////
+-(BOOL)hasFocus
+{
+ return [NSApp keyWindow] == [m_view window];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)enableKeyRepeat
+{
+ [m_oglView enableKeyRepeat];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)disableKeyRepeat
+{
+ [m_oglView disableKeyRepeat];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setIconTo:(unsigned int)width
+ by:(unsigned int)height
+ with:(const sf::Uint8*)pixels
+{
+ (void)width;
+ (void)height;
+ (void)pixels;
+ sf::err() << "Cannot set an icon when SFML is integrated in a NSView." << std::endl;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)processEvent
+{
+ // If we are not on the main thread we stop here and advice the user.
+ if ([NSThread currentThread] != [NSThread mainThread])
+ {
+ /*
+ * See https://lists.apple.com/archives/cocoa-dev/2011/Feb/msg00460.html
+ * for more information.
+ */
+ sf::err() << "Cannot fetch event from a worker thread. (OS X restriction)" << std::endl;
+
+ return;
+ }
+
+ // If we don't have a requester we don't fetch event.
+ if (m_requester != 0)
+ [SFApplication processEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)applyContext:(NSOpenGLContext*)context
+{
+ [m_oglView setOpenGLContext:context];
+ [context setView:m_oglView];
+}
+
+
+@end
diff --git a/src/SFML/Window/OSX/SFWindow.h b/src/SFML/Window/OSX/SFWindow.h
new file mode 100644
index 0000000..1d35245
--- /dev/null
+++ b/src/SFML/Window/OSX/SFWindow.h
@@ -0,0 +1,107 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <AppKit/AppKit.h>
+
+////////////////////////////////////////////////////////////
+/// \brief Here we redefine some methods to allow grabbing fullscreen events
+///
+////////////////////////////////////////////////////////////
+@interface SFWindow : NSWindow
+
+////////////////////////////////////////////////////////////
+/// \brief Allow to grab fullscreen events
+///
+/// acceptsFirstResponder and canBecomeKeyWindow messages must
+/// return YES to grab fullscreen events.
+///
+/// See https://stackoverflow.com/questions/999464/fullscreen-key-down-actions
+///
+/// \return YES
+///
+////////////////////////////////////////////////////////////
+-(BOOL)acceptsFirstResponder;
+
+////////////////////////////////////////////////////////////
+/// \brief Allow to grab fullscreen events
+///
+/// See acceptsFirstResponder documentation above.
+///
+/// \return YES
+///
+////////////////////////////////////////////////////////////
+-(BOOL)canBecomeKeyWindow;
+
+////////////////////////////////////////////////////////////
+/// \brief Prevent system alert
+///
+/// \param theEvent a Cocoa event
+///
+////////////////////////////////////////////////////////////
+-(void)keyDown:(NSEvent*)theEvent;
+
+////////////////////////////////////////////////////////////
+/// \brief This action method simulates the user clicking the close button
+///
+/// Override NSWindow implementation, see implementation for details
+///
+/// \param sender The message's sender
+///
+////////////////////////////////////////////////////////////
+-(void)performClose:(id)sender;
+
+////////////////////////////////////////////////////////////
+/// \brief Enabling or disabling a specific menu item
+///
+/// \param menuItem An NSMenuItem object that represents the menu item
+///
+/// \return YES to enable menuItem, NO to disable it.
+///
+////////////////////////////////////////////////////////////
+-(BOOL)validateMenuItem:(NSMenuItem*)menuItem;
+
+@end
+
+
+////////////////////////////////////////////////////////////
+/// \brief Extension of NSWindow
+///
+/// Add some extra messages for SFML internal usage.
+///
+////////////////////////////////////////////////////////////
+@interface NSWindow (SFML)
+
+////////////////////////////////////////////////////////////
+/// Proxy for performClose: for the app delegate
+///
+/// \return nil
+///
+////////////////////////////////////////////////////////////
+-(id)sfClose;
+
+@end
diff --git a/src/SFML/Window/OSX/SFWindow.m b/src/SFML/Window/OSX/SFWindow.m
new file mode 100644
index 0000000..087f990
--- /dev/null
+++ b/src/SFML/Window/OSX/SFWindow.m
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/SFWindow.h>
+
+
+@implementation SFWindow
+
+////////////////////////////////////////////////////////
+-(BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)canBecomeKeyWindow
+{
+ return YES;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)keyDown:(NSEvent*)theEvent
+{
+ // Do nothing except preventing a system alert each time a key is pressed
+ //
+ // Special Consideration :
+ // -----------------------
+ // Consider overriding NSResponder -keyDown: message in a Cocoa view/window
+ // that contains a SFML rendering area. Doing so will prevent a system
+ // alert to be thrown every time the user presses a key.
+ (void)theEvent;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)performClose:(id)sender
+{
+ // From Apple documentation:
+ //
+ // > If the window's delegate or the window itself implements windowShouldClose:,
+ // > that message is sent with the window as the argument. (Only one such message is sent;
+ // > if both the delegate and the NSWindow object implement the method, only the delegate
+ // > receives the message.) If the windowShouldClose: method returns NO, the window isn't
+ // > closed. If it returns YES, or if it isn't implemented, performClose: invokes the
+ // > close method to close the window.
+ // >
+ // > If the window doesn't have a close button or can't be closed (for example, if the
+ // > delegate replies NO to a windowShouldClose: message), the system emits the alert sound.
+ //
+ // The last paragraph is problematic for SFML fullscreen window since they don't have
+ // a close button (style is NSBorderlessWindowMask). So we reimplement this function.
+
+ BOOL shouldClose = NO;
+
+ if ([self delegate] && [[self delegate] respondsToSelector:@selector(windowShouldClose:)])
+ shouldClose = [[self delegate] windowShouldClose:sender];
+ // else if ([self respondsToSelector:@selector(windowShouldClose:)])
+ // shouldClose = [self windowShouldClose:sender];
+ // error: no visible @interface for 'SFWindow' declares the selector 'windowShouldClose:'
+
+ if (shouldClose)
+ [self close];
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)validateMenuItem:(NSMenuItem*)menuItem
+{
+ return [menuItem action] == @selector(performClose:) || [super validateMenuItem:menuItem];
+}
+
+
+@end
+
+
+@implementation NSWindow (SFML)
+
+////////////////////////////////////////////////////////////
+-(id)sfClose
+{
+ [self performClose:nil];
+ return nil;
+}
+
+@end
diff --git a/src/SFML/Window/OSX/SFWindowController.h b/src/SFML/Window/OSX/SFWindowController.h
new file mode 100644
index 0000000..df0585b
--- /dev/null
+++ b/src/SFML/Window/OSX/SFWindowController.h
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+
+#import <SFML/Window/OSX/WindowImplDelegateProtocol.h>
+
+////////////////////////////////////////////////////////////
+/// Predefine some classes
+////////////////////////////////////////////////////////////
+namespace sf {
+ namespace priv {
+ class WindowImplCocoa;
+ }
+}
+
+@class SFOpenGLView;
+
+////////////////////////////////////////////////////////////
+/// \brief Implementation of WindowImplDelegateProtocol for window management
+///
+/// Key, mouse and Window focus events are delegated to its view, SFOpenGLView.
+///
+/// Used when SFML handle everything and when a NSWindow* is given
+/// as handle to WindowImpl.
+///
+/// When grabbing the cursor, if the window is resizeable, m_restoreResize is
+/// set to YES and the window is marked as not resizeable. This is to prevent
+/// accidental resize by the user. When the cursor is released, the window
+/// style is restored.
+///
+////////////////////////////////////////////////////////////
+@interface SFWindowController : NSResponder <WindowImplDelegateProtocol, NSWindowDelegate>
+{
+ NSWindow* m_window; ///< Underlying Cocoa window to be controlled
+ SFOpenGLView* m_oglView; ///< OpenGL view for rendering
+ sf::priv::WindowImplCocoa* m_requester; ///< Requester
+ BOOL m_fullscreen; ///< Indicate whether the window is fullscreen or not
+ BOOL m_restoreResize; ///< See note above
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Create the SFML window with an external Cocoa window
+///
+/// \param window Cocoa window to be controlled
+///
+/// \return an initialized controller
+///
+////////////////////////////////////////////////////////////
+-(id)initWithWindow:(NSWindow*)window;
+
+////////////////////////////////////////////////////////////
+/// \brief Create the SFML window "from scratch" (SFML handle everything)
+///
+/// \param mode Video mode
+/// \param style Window's style, as described by sf::Style
+///
+/// \return an initialized controller
+///
+////////////////////////////////////////////////////////////
+-(id)initWithMode:(const sf::VideoMode&)mode andStyle:(unsigned long)style;
+
+@end
diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm
new file mode 100644
index 0000000..186a0fb
--- /dev/null
+++ b/src/SFML/Window/OSX/SFWindowController.mm
@@ -0,0 +1,629 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/WindowHandle.hpp>
+#include <SFML/Window/WindowStyle.hpp>
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <SFML/System/Err.hpp>
+#include <ApplicationServices/ApplicationServices.h>
+#include <algorithm>
+
+#import <SFML/Window/OSX/NSImage+raw.h>
+#import <SFML/Window/OSX/Scaling.h>
+#import <SFML/Window/OSX/SFApplication.h>
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFWindow.h>
+#import <SFML/Window/OSX/SFWindowController.h>
+#import <OpenGL/OpenGL.h>
+
+////////////////////////////////////////////////////////////
+/// SFBlackView is a simple view filled with black, nothing more
+///
+////////////////////////////////////////////////////////////
+@interface SFBlackView : NSView
+@end
+
+@implementation SFBlackView
+
+////////////////////////////////////////////////////////////
+-(void)drawRect:(NSRect)dirtyRect
+{
+ [[NSColor blackColor] setFill];
+ NSRectFill(dirtyRect);
+}
+
+@end
+
+////////////////////////////////////////////////////////////
+/// SFWindowController class: private interface
+///
+////////////////////////////////////////////////////////////
+@interface SFWindowController ()
+
+////////////////////////////////////////////////////////////
+/// \brief Retrieves the screen height
+///
+/// \return screen height
+///
+////////////////////////////////////////////////////////////
+-(float)screenHeight;
+
+////////////////////////////////////////////////////////////
+/// \brief Retrieves the title bar height
+///
+/// \return title bar height
+///
+////////////////////////////////////////////////////////////
+-(float)titlebarHeight;
+
+@end
+
+@implementation SFWindowController
+
+#pragma mark
+#pragma mark SFWindowController's methods
+
+////////////////////////////////////////////////////////
+-(id)initWithWindow:(NSWindow*)window
+{
+ if ((self = [super init]))
+ {
+ m_window = nil;
+ m_oglView = nil;
+ m_requester = 0;
+ m_fullscreen = NO; // assuming this is the case... too hard to handle anyway.
+ m_restoreResize = NO;
+
+ // Retain the window for our own use.
+ m_window = [window retain];
+
+ if (m_window == nil)
+ {
+ sf::err() << "No window was given to -[SFWindowController initWithWindow:]." << std::endl;
+ return self;
+ }
+
+ // Create the view.
+ m_oglView = [[SFOpenGLView alloc] initWithFrame:[[m_window contentView] frame]
+ fullscreen:NO];
+
+ if (m_oglView == nil)
+ {
+ sf::err() << "Could not create an instance of NSOpenGLView "
+ << "in -[SFWindowController initWithWindow:]."
+ << std::endl;
+ return self;
+ }
+
+ // Set the view to the window as its content view.
+ [m_window setContentView:m_oglView];
+ }
+
+ return self;
+}
+
+
+////////////////////////////////////////////////////////
+-(id)initWithMode:(const sf::VideoMode&)mode andStyle:(unsigned long)style
+{
+ // If we are not on the main thread we stop here and advice the user.
+ if ([NSThread currentThread] != [NSThread mainThread])
+ {
+ /*
+ * See https://lists.apple.com/archives/cocoa-dev/2011/Feb/msg00460.html
+ * for more information.
+ */
+ sf::err() << "Cannot create a window from a worker thread. (OS X limitation)" << std::endl;
+
+ return nil;
+ }
+
+ if ((self = [super init]))
+ {
+ m_window = nil;
+ m_oglView = nil;
+ m_requester = 0;
+ m_fullscreen = (style & sf::Style::Fullscreen);
+ m_restoreResize = NO;
+
+ if (m_fullscreen)
+ [self setupFullscreenViewWithMode:mode];
+ else
+ [self setupWindowWithMode:mode andStyle:style];
+
+ [m_oglView finishInit];
+ }
+ return self;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setupFullscreenViewWithMode:(const sf::VideoMode&)mode
+{
+ // Create a screen-sized window on the main display
+ sf::VideoMode desktop = sf::VideoMode::getDesktopMode();
+ sf::priv::scaleInWidthHeight(desktop, nil);
+ NSRect windowRect = NSMakeRect(0, 0, desktop.width, desktop.height);
+ m_window = [[SFWindow alloc] initWithContentRect:windowRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ if (m_window == nil)
+ {
+ sf::err() << "Could not create an instance of NSWindow "
+ << "in -[SFWindowController setupFullscreenViewWithMode:]."
+ << std::endl;
+ return;
+ }
+
+ // Set the window level to be above the menu bar
+ [m_window setLevel:NSMainMenuWindowLevel+1];
+
+ // More window configuration...
+ [m_window setOpaque:YES];
+ [m_window setHidesOnDeactivate:YES];
+ [m_window setAutodisplay:YES];
+ [m_window setReleasedWhenClosed:NO]; // We own the class, not AppKit
+
+ // Register for event
+ [m_window setDelegate:self];
+ [m_window setAcceptsMouseMovedEvents:YES];
+ [m_window setIgnoresMouseEvents:NO];
+
+ // Create a master view containing our OpenGL view
+ NSView* masterView = [[[SFBlackView alloc] initWithFrame:windowRect] autorelease];
+
+ if (masterView == nil)
+ {
+ sf::err() << "Could not create an instance of SFBlackView "
+ << "in -[SFWindowController setupFullscreenViewWithMode:]."
+ << std::endl;
+ return;
+ }
+
+ // Create our OpenGL view size and the view
+ CGFloat width = std::min(mode.width, desktop.width);
+ CGFloat height = std::min(mode.height, desktop.height);
+ CGFloat x = (desktop.width - width) / 2.0;
+ CGFloat y = (desktop.height - height) / 2.0;
+ NSRect oglRect = NSMakeRect(x, y, width, height);
+
+ m_oglView = [[SFOpenGLView alloc] initWithFrame:oglRect
+ fullscreen:YES];
+
+ if (m_oglView == nil)
+ {
+ sf::err() << "Could not create an instance of NSOpenGLView "
+ << "in -[SFWindowController setupFullscreenViewWithMode:]."
+ << std::endl;
+ return;
+ }
+
+ // Populate the window and views
+ [masterView addSubview:m_oglView];
+ [m_window setContentView:masterView];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setupWindowWithMode:(const sf::VideoMode&)mode andStyle:(unsigned long)style
+{
+ // We know that style & sf::Style::Fullscreen is false.
+
+ // Create our window size.
+ NSRect rect = NSMakeRect(0, 0, mode.width, mode.height);
+
+ // Convert the SFML window style to Cocoa window style.
+ unsigned int nsStyle = NSBorderlessWindowMask;
+ if (style & sf::Style::Titlebar)
+ nsStyle |= NSTitledWindowMask | NSMiniaturizableWindowMask;
+ if (style & sf::Style::Resize)
+ nsStyle |= NSResizableWindowMask;
+ if (style & sf::Style::Close)
+ nsStyle |= NSClosableWindowMask;
+
+ // Create the window.
+ m_window = [[SFWindow alloc] initWithContentRect:rect
+ styleMask:nsStyle
+ backing:NSBackingStoreBuffered
+ defer:NO]; // Don't defer it!
+ /*
+ "YES" produces some "invalid drawable".
+ See http://www.cocoabuilder.com/archive/cocoa/152482-nsviews-and-nsopenglcontext-invalid-drawable-error.html
+
+ [...]
+ As best as I can figure, this is happening because the NSWindow (and
+ hence my view) are not visible on screen yet, and the system doesn't like that.
+ [...]
+ */
+
+ if (m_window == nil)
+ {
+ sf::err() << "Could not create an instance of NSWindow "
+ << "in -[SFWindowController setupWindowWithMode:andStyle:]."
+ << std::endl;
+
+ return;
+ }
+
+ // Create the view.
+ m_oglView = [[SFOpenGLView alloc] initWithFrame:[[m_window contentView] frame]
+ fullscreen:NO];
+
+ if (m_oglView == nil)
+ {
+ sf::err() << "Could not create an instance of NSOpenGLView "
+ << "in -[SFWindowController setupWindowWithMode:andStyle:]."
+ << std::endl;
+
+ return;
+ }
+
+ // Set the view to the window as its content view.
+ [m_window setContentView:m_oglView];
+
+ // Register for event.
+ [m_window setDelegate:self];
+ [m_window setAcceptsMouseMovedEvents:YES];
+ [m_window setIgnoresMouseEvents:NO];
+
+ // And some other things...
+ [m_window center];
+ [m_window setAutodisplay:YES];
+ [m_window setReleasedWhenClosed:NO]; // We own the class, not AppKit
+}
+
+
+////////////////////////////////////////////////////////
+-(void)dealloc
+{
+ [self closeWindow];
+ [NSMenu setMenuBarVisible:YES];
+
+ [m_window release];
+ [m_oglView release];
+
+ [super dealloc];
+}
+
+
+#pragma mark
+#pragma mark WindowImplDelegateProtocol's methods
+
+
+////////////////////////////////////////////////////////
+-(CGFloat)displayScaleFactor
+{
+ return [m_oglView displayScaleFactor];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester
+{
+ // Forward to the view.
+ [m_oglView setRequesterTo:requester];
+ m_requester = requester;
+}
+
+
+////////////////////////////////////////////////////////
+-(sf::WindowHandle)getSystemHandle
+{
+ return m_window;
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)isMouseInside
+{
+ return [m_oglView isMouseInside];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed
+{
+ // Remove or restore resizeable style if needed
+ BOOL resizeable = [m_window styleMask] & NSResizableWindowMask;
+ if (grabbed && resizeable)
+ {
+ m_restoreResize = YES;
+ NSUInteger newStyle = [m_window styleMask] & ~NSResizableWindowMask;
+ [m_window setStyleMask:newStyle];
+ }
+ else if (!grabbed && m_restoreResize)
+ {
+ m_restoreResize = NO;
+ NSUInteger newStyle = [m_window styleMask] | NSResizableWindowMask;
+ [m_window setStyleMask:newStyle];
+ }
+
+ // Forward to our view
+ [m_oglView setCursorGrabbed:grabbed];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursor:(NSCursor*)cursor
+{
+ return [m_oglView setCursor:cursor];
+}
+
+
+////////////////////////////////////////////////////////////
+-(NSPoint)position
+{
+ // Note: since 10.7 the conversion API works with NSRect
+ // instead of NSPoint. Therefore we use a NSRect but ignore
+ // its width and height.
+
+ // Position of the bottom-left corner in the different coordinate systems:
+ NSRect corner = [m_oglView frame]; // bottom left; size is ignored
+ NSRect view = [m_oglView convertRectToBacking:corner];
+ NSRect window = [m_oglView convertRect:view toView:nil];
+ NSRect screen = [[m_oglView window] convertRectToScreen:window];
+
+ // Get the top-left corner in screen coordinates
+ CGFloat x = screen.origin.x;
+ CGFloat y = screen.origin.y + [m_oglView frame].size.height;
+
+ // Flip y-axis (titlebar was already taken into account above)
+ y = [self screenHeight] - y;
+
+ return NSMakePoint(x, y);
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setWindowPositionToX:(int)x Y:(int)y
+{
+ NSPoint point = NSMakePoint(x, y);
+
+ // Flip for SFML window coordinate system and take titlebar into account
+ point.y = [self screenHeight] - point.y + [self titlebarHeight];
+
+ // Place the window.
+ [m_window setFrameTopLeftPoint:point];
+
+ // In case the cursor was grabbed we need to update its position
+ [m_oglView updateCursorGrabbed];
+}
+
+
+////////////////////////////////////////////////////////
+-(NSSize)size
+{
+ return [m_oglView frame].size;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)resizeTo:(unsigned int)width by:(unsigned int)height
+{
+ if (m_fullscreen)
+ {
+ // Special case when fullscreen: only resize the opengl view
+ // and make sure the requested size is not bigger than the window.
+ sf::VideoMode desktop = sf::VideoMode::getDesktopMode();
+ sf::priv::scaleInWidthHeight(desktop, nil);
+
+ width = std::min(width, desktop.width);
+ height = std::min(height, desktop.height);
+
+ CGFloat x = (desktop.width - width) / 2.0;
+ CGFloat y = (desktop.height - height) / 2.0;
+ NSRect oglRect = NSMakeRect(x, y, width, height);
+
+ [m_oglView setFrame:oglRect];
+ [m_oglView setNeedsDisplay:YES];
+ }
+ else
+ {
+ // Before resizing, remove resizable mask to be able to resize
+ // beyond the desktop boundaries.
+ NSUInteger styleMask = [m_window styleMask];
+
+ [m_window setStyleMask:styleMask ^ NSResizableWindowMask];
+
+ // Add titlebar height.
+ height += [self titlebarHeight];
+
+ // Corner case: don't set the window height bigger than the screen height
+ // or the view will be resized _later_ without generating a resize event.
+ NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
+ CGFloat maxVisibleHeight = screenFrame.size.height;
+ if (height > maxVisibleHeight)
+ {
+ height = maxVisibleHeight;
+
+ // The size is not the requested one, we fire an event
+ if (m_requester != 0)
+ m_requester->windowResized(width, height - [self titlebarHeight]);
+ }
+
+ NSRect frame = NSMakeRect([m_window frame].origin.x,
+ [m_window frame].origin.y,
+ width,
+ height);
+
+ [m_window setFrame:frame display:YES];
+
+ // And restore the mask
+ [m_window setStyleMask:styleMask];
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)changeTitle:(NSString*)title
+{
+ [m_window setTitle:title];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)hideWindow
+{
+ [m_window orderOut:nil];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)showWindow
+{
+ [m_window makeKeyAndOrderFront:nil];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)closeWindow
+{
+ [self applyContext:nil];
+ [m_window close];
+ [m_window setDelegate:nil];
+ [self setRequesterTo:0];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)requestFocus
+{
+ [m_window makeKeyAndOrderFront:nil];
+
+ // In case the app is not active, make its dock icon bounce for one sec
+ [NSApp requestUserAttention:NSInformationalRequest];
+}
+
+
+////////////////////////////////////////////////////////////
+-(BOOL)hasFocus
+{
+ return [NSApp keyWindow] == m_window;
+}
+
+
+////////////////////////////////////////////////////////
+-(void)enableKeyRepeat
+{
+ [m_oglView enableKeyRepeat];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)disableKeyRepeat
+{
+ [m_oglView disableKeyRepeat];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setIconTo:(unsigned int)width
+ by:(unsigned int)height
+ with:(const sf::Uint8*)pixels
+{
+ // Load image and set app icon.
+ NSImage* icon = [NSImage imageWithRawData:pixels
+ andSize:NSMakeSize(width, height)];
+
+ [[SFApplication sharedApplication] setApplicationIconImage:icon];
+
+ [icon release];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)processEvent
+{
+ // If we are not on the main thread we stop here and advice the user.
+ if ([NSThread currentThread] != [NSThread mainThread])
+ {
+ /*
+ * See https://lists.apple.com/archives/cocoa-dev/2011/Feb/msg00460.html
+ * for more information.
+ */
+ sf::err() << "Cannot fetch event from a worker thread. (OS X restriction)" << std::endl;
+
+ return;
+ }
+
+ // If we don't have a requester we don't fetch event.
+ if (m_requester != 0)
+ [SFApplication processEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)applyContext:(NSOpenGLContext*)context
+{
+ [m_oglView setOpenGLContext:context];
+ [context setView:m_oglView];
+}
+
+
+#pragma mark
+#pragma mark NSWindowDelegate's methods
+
+
+////////////////////////////////////////////////////////
+-(BOOL)windowShouldClose:(id)sender
+{
+ (void)sender;
+
+ if (m_requester == 0)
+ return YES;
+
+ m_requester->windowClosed();
+ return NO;
+}
+
+
+#pragma mark
+#pragma mark Other methods
+
+////////////////////////////////////////////////////////
+-(float)screenHeight
+{
+ NSDictionary* deviceDescription = [[m_window screen] deviceDescription];
+ NSNumber* screenNumber = [deviceDescription valueForKey:@"NSScreenNumber"];
+ CGDirectDisplayID screenID = (CGDirectDisplayID)[screenNumber intValue];
+ CGFloat height = CGDisplayPixelsHigh(screenID);
+ return height;
+}
+
+
+////////////////////////////////////////////////////////
+-(float)titlebarHeight
+{
+ return NSHeight([m_window frame]) - NSHeight([[m_window contentView] frame]);
+}
+
+@end
+
diff --git a/src/SFML/Window/OSX/Scaling.h b/src/SFML/Window/OSX/Scaling.h
new file mode 100644
index 0000000..62f13ae
--- /dev/null
+++ b/src/SFML/Window/OSX/Scaling.h
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#import <SFML/Window/OSX/WindowImplDelegateProtocol.h>
+
+#import <AppKit/AppKit.h>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// \brief Get the scale factor of the main screen
+///
+////////////////////////////////////////////////////////////
+inline CGFloat getDefaultScaleFactor()
+{
+ return [[NSScreen mainScreen] backingScaleFactor];
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Scale SFML coordinates to backing coordinates
+///
+/// \param in SFML coordinates to be converted
+/// \param delegate an object implementing WindowImplDelegateProtocol, or nil for default scale
+///
+////////////////////////////////////////////////////////////
+template <class T>
+void scaleIn(T& in, id<WindowImplDelegateProtocol> delegate)
+{
+ in /= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor();
+}
+
+template <class T>
+void scaleInWidthHeight(T& in, id<WindowImplDelegateProtocol> delegate)
+{
+ scaleIn(in.width, delegate);
+ scaleIn(in.height, delegate);
+}
+
+template <class T>
+void scaleInXY(T& in, id<WindowImplDelegateProtocol> delegate)
+{
+ scaleIn(in.x, delegate);
+ scaleIn(in.y, delegate);
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Scale backing coordinates to SFML coordinates
+///
+/// \param out backing coordinates to be converted
+/// \param delegate an object implementing WindowImplDelegateProtocol, or nil for default scale
+///
+////////////////////////////////////////////////////////////
+template <class T>
+void scaleOut(T& out, id<WindowImplDelegateProtocol> delegate)
+{
+ out *= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor();
+}
+
+template <class T>
+void scaleOutWidthHeight(T& out, id<WindowImplDelegateProtocol> delegate)
+{
+ scaleOut(out.width, delegate);
+ scaleOut(out.height, delegate);
+}
+
+template <class T>
+void scaleOutXY(T& out, id<WindowImplDelegateProtocol> delegate)
+{
+ scaleOut(out.x, delegate);
+ scaleOut(out.y, delegate);
+}
+
+} // namespace priv
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/SensorImpl.cpp b/src/SFML/Window/OSX/SensorImpl.cpp
new file mode 100644
index 0000000..3496265
--- /dev/null
+++ b/src/SFML/Window/OSX/SensorImpl.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ // To be implemented
+ return Vector3f(0, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool /*enabled*/)
+{
+ // To be implemented
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/OSX/SensorImpl.hpp b/src/SFML/Window/OSX/SensorImpl.hpp
new file mode 100644
index 0000000..fe81b8d
--- /dev/null
+++ b/src/SFML/Window/OSX/SensorImpl.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPLOSX_HPP
+#define SFML_SENSORIMPLOSX_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Mac OS X implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLOSX_HPP
diff --git a/src/SFML/Window/OSX/VideoModeImpl.cpp b/src/SFML/Window/OSX/VideoModeImpl.cpp
new file mode 100644
index 0000000..efd5e46
--- /dev/null
+++ b/src/SFML/Window/OSX/VideoModeImpl.cpp
@@ -0,0 +1,99 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <SFML/Window/OSX/cg_sf_conversion.hpp>
+#include <SFML/System/Err.hpp>
+#include <algorithm>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ std::vector<VideoMode> modes;
+
+ // Retrieve all modes available for main screen only.
+ CFArrayRef cgmodes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL);
+
+ if (cgmodes == NULL)
+ {
+ sf::err() << "Couldn't get VideoMode for main display." << std::endl;
+ return modes;
+ }
+
+ VideoMode desktop = getDesktopMode();
+
+ // Loop on each mode and convert it into a sf::VideoMode object.
+ const CFIndex modesCount = CFArrayGetCount(cgmodes);
+ for (CFIndex i = 0; i < modesCount; i++)
+ {
+ CGDisplayModeRef cgmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(cgmodes, i);
+
+ VideoMode mode = convertCGModeToSFMode(cgmode);
+
+ // Skip if bigger than desktop as we currently don't perform hard resolution switch
+ if ((mode.width > desktop.width) || (mode.height > desktop.height))
+ continue;
+
+ // If not yet listed we add it to our modes array.
+ if (std::find(modes.begin(), modes.end(), mode) == modes.end())
+ modes.push_back(mode);
+ }
+
+ // Clean up memory.
+ CFRelease(cgmodes);
+
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ VideoMode mode; // RVO
+
+ // Rely exclusively on mode and convertCGModeToSFMode
+ // instead of display id and CGDisplayPixelsHigh/Wide.
+
+ CGDirectDisplayID display = CGMainDisplayID();
+ CGDisplayModeRef cgmode = CGDisplayCopyDisplayMode(display);
+
+ mode = convertCGModeToSFMode(cgmode);
+
+ CGDisplayModeRelease(cgmode);
+
+ return mode;
+}
+
+} // namespace priv
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/WindowImplCocoa.hpp b/src/SFML/Window/OSX/WindowImplCocoa.hpp
new file mode 100644
index 0000000..eea318d
--- /dev/null
+++ b/src/SFML/Window/OSX/WindowImplCocoa.hpp
@@ -0,0 +1,377 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_WINDOWIMPLCOCOA_HPP
+#define SFML_WINDOWIMPLCOCOA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/System/String.hpp>
+
+////////////////////////////////////////////////////////////
+/// Predefine OBJ-C classes
+////////////////////////////////////////////////////////////
+#ifdef __OBJC__
+
+#import <SFML/Window/OSX/WindowImplDelegateProtocol.h>
+typedef id<WindowImplDelegateProtocol,NSObject> WindowImplDelegateRef;
+
+@class NSOpenGLContext;
+typedef NSOpenGLContext* NSOpenGLContextRef;
+
+#else // If C++
+
+typedef unsigned short unichar; // See NSString.h
+
+typedef void* WindowImplDelegateRef;
+typedef void* NSOpenGLContextRef;
+
+#endif
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Mac OS X (Cocoa) implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplCocoa : public WindowImpl
+{
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplCocoa(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style (resizeable, fixed, or fullscren)
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplCocoa(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplCocoa();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Window Closed Event - called by the cocoa window object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ ////////////////////////////////////////////////////////////
+ void windowClosed(void);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Window Resized Event - called by the cocoa window object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param width new width
+ /// \param height new height
+ ///
+ ////////////////////////////////////////////////////////////
+ void windowResized(unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Window Lost Focus Event - called by the cocoa window object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ ////////////////////////////////////////////////////////////
+ void windowLostFocus(void);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Window Get Focus Event - called by the cocoa window object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ ////////////////////////////////////////////////////////////
+ void windowGainedFocus(void);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse Down Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param button active button
+ /// \param x mouse x position
+ /// \param y mouse y position
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseDownAt(Mouse::Button button, int x, int y);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse Up Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param button active button
+ /// \param x mouse x position
+ /// \param y mouse y position
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseUpAt(Mouse::Button button, int x, int y);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse Moved Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param x mouse x position
+ /// \param y mouse y position
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseMovedAt(int x, int y);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse Wheel Scrolled Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param deltaX horizontal scrolling delta
+ /// \param deltaY vertical scrolling delta
+ /// \param x mouse x position
+ /// \param y mouse y position
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseWheelScrolledAt(float deltaX, float deltaY, int x, int y);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse In Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseMovedIn(void);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Mouse Out Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ ////////////////////////////////////////////////////////////
+ void mouseMovedOut(void);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Key Down Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param key active key
+ ///
+ ////////////////////////////////////////////////////////////
+ void keyDown(Event::KeyEvent key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Key Up Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param key active key
+ ///
+ ////////////////////////////////////////////////////////////
+ void keyUp(Event::KeyEvent key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Text Entred Event - called by the cocoa view object
+ ///
+ /// Send the event to SFML WindowImpl class.
+ ///
+ /// \param charcode Unicode input
+ ///
+ ////////////////////////////////////////////////////////////
+ void textEntered(unichar charcode);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Apply the context to the view
+ ///
+ /// Called by the SFML context object to finalize its creation.
+ ///
+ /// \param context The context to bind to the window
+ ///
+ ////////////////////////////////////////////////////////////
+ void applyContext(NSOpenGLContextRef context) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the type of the current process
+ ///
+ /// The type of the process is changed to become a full GUI app.
+ /// Also ensure NSApp is constructed.
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setUpProcess(void);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Grab or release the mouse cursor
+ ///
+ /// \param grabbed True to grab, false to release
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ WindowImplDelegateRef m_delegate; ///< Implementation in Obj-C.
+ bool m_showCursor; ///< Is the cursor displayed or hidden?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPLCOCOA_HPP
diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm
new file mode 100644
index 0000000..edb6935
--- /dev/null
+++ b/src/SFML/Window/OSX/WindowImplCocoa.mm
@@ -0,0 +1,530 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <SFML/System/Err.hpp>
+
+#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
+#import <SFML/Window/OSX/cpp_objc_conversion.h>
+#import <SFML/Window/OSX/Scaling.h>
+#import <SFML/Window/OSX/SFApplication.h>
+#import <SFML/Window/OSX/SFApplicationDelegate.h>
+#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h>
+#import <SFML/Window/OSX/SFViewController.h>
+#import <SFML/Window/OSX/SFWindowController.h>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// According to Apple's documentation, each invocation of
+/// unhide must be balanced by an invocation of hide in
+/// order for the cursor display to be correct.
+/// So we keep track of those calls ourself.
+////////////////////////////////////////////////////////////
+
+namespace
+{
+ bool isCursorHidden = false; // initially, the cursor is visible
+}
+
+
+////////////////////////////////////////////////////////
+void hideMouseCursor()
+{
+ if (!isCursorHidden)
+ {
+ [NSCursor hide];
+ isCursorHidden = true;
+ }
+}
+
+
+////////////////////////////////////////////////////////
+void showMouseCursor()
+{
+ if (isCursorHidden)
+ {
+ [NSCursor unhide];
+ isCursorHidden = false;
+ }
+}
+
+#pragma mark
+#pragma mark WindowImplCocoa's ctor/dtor
+
+////////////////////////////////////////////////////////////
+WindowImplCocoa::WindowImplCocoa(WindowHandle handle) :
+m_showCursor(true)
+{
+ // Ask for a pool.
+ ensureThreadHasPool();
+
+ // Treat the handle as it real type
+ id nsHandle = (id)handle;
+ if ([nsHandle isKindOfClass:[NSWindow class]])
+ {
+ // We have a window.
+ m_delegate = [[SFWindowController alloc] initWithWindow:nsHandle];
+ }
+ else if ([nsHandle isKindOfClass:[NSView class]])
+ {
+ // We have a view.
+ m_delegate = [[SFViewController alloc] initWithView:nsHandle];
+ }
+ else
+ {
+
+ sf::err() << "Cannot import this Window Handle because it is neither "
+ << "a <NSWindow*> nor <NSView*> object "
+ << "(or any of their subclasses). You gave a <"
+ << [[nsHandle className] UTF8String]
+ << "> object."
+ << std::endl;
+ return;
+
+ }
+
+ [m_delegate setRequesterTo:this];
+
+ // Finally, set up keyboard helper
+ initialiseKeyboardHelper();
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplCocoa::WindowImplCocoa(VideoMode mode,
+ const String& title,
+ unsigned long style,
+ const ContextSettings& /*settings*/) :
+m_showCursor(true)
+{
+ // Transform the app process.
+ setUpProcess();
+
+ // Ask for a pool.
+ ensureThreadHasPool();
+
+ // Use backing size
+ scaleInWidthHeight(mode, nil);
+
+ m_delegate = [[SFWindowController alloc] initWithMode:mode andStyle:style];
+ [m_delegate changeTitle:sfStringToNSString(title)];
+ [m_delegate setRequesterTo:this];
+
+ // Finally, set up keyboard helper
+ initialiseKeyboardHelper();
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplCocoa::~WindowImplCocoa()
+{
+ [m_delegate closeWindow];
+
+ [m_delegate release];
+
+ // Put the next window in front, if any.
+ NSArray* windows = [NSApp orderedWindows];
+ if ([windows count] > 0)
+ [[windows objectAtIndex:0] makeKeyAndOrderFront:nil];
+
+ drainThreadPool(); // Make sure everything was freed
+ // This solve some issue when sf::Window::Create is called for the
+ // second time (nothing was render until the function was called again)
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::applyContext(NSOpenGLContextRef context) const
+{
+ [m_delegate applyContext:context];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setUpProcess(void)
+{
+ static bool isTheProcessSetAsApplication = false;
+
+ if (!isTheProcessSetAsApplication)
+ {
+ // Do it only once !
+ isTheProcessSetAsApplication = true;
+
+ // Make sure NSApp is properly initialized
+ [SFApplication sharedApplication];
+
+ // Set the process as a normal application so it can get focus
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+ [NSApp activateIgnoringOtherApps:YES];
+
+ // Register an application delegate if there is none
+ if (![[SFApplication sharedApplication] delegate])
+ [[NSApplication sharedApplication] setDelegate:[[SFApplicationDelegate alloc] init]];
+
+ // Create menus for the application (before finishing launching!)
+ [SFApplication setUpMenuBar];
+
+ // Tell the application to stop bouncing in the Dock.
+ [[SFApplication sharedApplication] finishLaunching];
+ // NOTE: This last call won't harm anything even if SFML window was
+ // created with an external handle.
+ }
+}
+
+
+#pragma mark
+#pragma mark WindowImplCocoa's window-event methods
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::windowClosed(void)
+{
+ Event event;
+ event.type = Event::Closed;
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::windowResized(unsigned int width, unsigned int height)
+{
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = width;
+ event.size.height = height;
+ scaleOutWidthHeight(event.size, m_delegate);
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::windowLostFocus(void)
+{
+ if (!m_showCursor && [m_delegate isMouseInside])
+ showMouseCursor(); // Make sure the cursor is visible
+
+ Event event;
+ event.type = Event::LostFocus;
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::windowGainedFocus(void)
+{
+ if (!m_showCursor && [m_delegate isMouseInside])
+ hideMouseCursor(); // Restore user's setting
+
+ Event event;
+ event.type = Event::GainedFocus;
+
+ pushEvent(event);
+}
+
+#pragma mark
+#pragma mark WindowImplCocoa's mouse-event methods
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseDownAt(Mouse::Button button, int x, int y)
+{
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = button;
+ event.mouseButton.x = x;
+ event.mouseButton.y = y;
+ scaleOutXY(event.mouseButton, m_delegate);
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseUpAt(Mouse::Button button, int x, int y)
+{
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = button;
+ event.mouseButton.x = x;
+ event.mouseButton.y = y;
+ scaleOutXY(event.mouseButton, m_delegate);
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseMovedAt(int x, int y)
+{
+ Event event;
+ event.type = Event::MouseMoved;
+ event.mouseMove.x = x;
+ event.mouseMove.y = y;
+ scaleOutXY(event.mouseMove, m_delegate);
+
+ pushEvent(event);
+}
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseWheelScrolledAt(float deltaX, float deltaY, int x, int y)
+{
+ Event event;
+
+ event.type = Event::MouseWheelMoved;
+ event.mouseWheel.delta = deltaY;
+ event.mouseWheel.x = x;
+ event.mouseWheel.y = y;
+ scaleOutXY(event.mouseWheel, m_delegate);
+ pushEvent(event);
+
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::VerticalWheel;
+ event.mouseWheelScroll.delta = deltaY;
+ event.mouseWheelScroll.x = x;
+ event.mouseWheelScroll.y = y;
+ scaleOutXY(event.mouseWheelScroll, m_delegate);
+ pushEvent(event);
+
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::HorizontalWheel;
+ event.mouseWheelScroll.delta = deltaX;
+ event.mouseWheelScroll.x = x;
+ event.mouseWheelScroll.y = y;
+ scaleOutXY(event.mouseWheelScroll, m_delegate);
+ pushEvent(event);
+}
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseMovedIn(void)
+{
+ if (!m_showCursor)
+ hideMouseCursor(); // Restore user's setting
+
+ Event event;
+ event.type = Event::MouseEntered;
+
+ pushEvent(event);
+}
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::mouseMovedOut(void)
+{
+ if (!m_showCursor)
+ showMouseCursor(); // Make sure the cursor is visible
+
+ Event event;
+ event.type = Event::MouseLeft;
+
+ pushEvent(event);
+}
+
+
+#pragma mark
+#pragma mark WindowImplCocoa's key-event methods
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::keyDown(Event::KeyEvent key)
+{
+ Event event;
+ event.type = Event::KeyPressed;
+ event.key = key;
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::keyUp(Event::KeyEvent key)
+{
+ Event event;
+ event.type = Event::KeyReleased;
+ event.key = key;
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::textEntered(unichar charcode)
+{
+ Event event;
+ event.type = Event::TextEntered;
+ event.text.unicode = charcode;
+
+ pushEvent(event);
+}
+
+
+#pragma mark
+#pragma mark WindowImplCocoa's event-related methods
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::processEvents()
+{
+ [m_delegate processEvent];
+ drainThreadPool(); // Reduce memory footprint
+}
+
+#pragma mark
+#pragma mark WindowImplCocoa's private methods
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplCocoa::getSystemHandle() const
+{
+ return [m_delegate getSystemHandle];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplCocoa::getPosition() const
+{
+ NSPoint pos = [m_delegate position];
+ sf::Vector2i ret(pos.x, pos.y);
+ scaleOutXY(ret, m_delegate);
+ return ret;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setPosition(const Vector2i& position)
+{
+ sf::Vector2i backingPosition = position;
+ scaleInXY(backingPosition, m_delegate);
+ [m_delegate setWindowPositionToX:backingPosition.x Y:backingPosition.y];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplCocoa::getSize() const
+{
+ NSSize size = [m_delegate size];
+ Vector2u ret(size.width, size.height);
+ scaleOutXY(ret, m_delegate);
+ return ret;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setSize(const Vector2u& size)
+{
+ sf::Vector2u backingSize = size;
+ scaleInXY(backingSize, m_delegate);
+ [m_delegate resizeTo:backingSize.x by:backingSize.y];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setTitle(const String& title)
+{
+ [m_delegate changeTitle:sfStringToNSString(title)];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ [m_delegate setIconTo:width by:height with:pixels];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setVisible(bool visible)
+{
+ if (visible)
+ [m_delegate showWindow];
+ else
+ [m_delegate hideWindow];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setMouseCursorVisible(bool visible)
+{
+ m_showCursor = visible;
+
+ // If the mouse is over the window, we apply the new setting
+ if ([m_delegate isMouseInside])
+ {
+ if (m_showCursor)
+ showMouseCursor();
+ else
+ hideMouseCursor();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setMouseCursorGrabbed(bool grabbed)
+{
+ [m_delegate setCursorGrabbed:grabbed];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setMouseCursor(const CursorImpl& cursor)
+{
+ [m_delegate setCursor:cursor.m_cursor];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::setKeyRepeatEnabled(bool enabled)
+{
+ if (enabled)
+ [m_delegate enableKeyRepeat];
+ else
+ [m_delegate disableKeyRepeat];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplCocoa::requestFocus()
+{
+ [m_delegate requestFocus];
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplCocoa::hasFocus() const
+{
+ return [m_delegate hasFocus];
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/WindowImplDelegateProtocol.h b/src/SFML/Window/OSX/WindowImplDelegateProtocol.h
new file mode 100644
index 0000000..d6cfa90
--- /dev/null
+++ b/src/SFML/Window/OSX/WindowImplDelegateProtocol.h
@@ -0,0 +1,234 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp> // for sf::Uint8
+#include <SFML/Window/WindowHandle.hpp>
+
+#import <AppKit/AppKit.h>
+
+namespace sf {
+ namespace priv {
+ class WindowImplCocoa;
+ }
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Interface of the delegate of the window implementation
+///
+/// We don't create an interface here because Obj-C doesn't allow
+/// multiple inheritance (SFViewController and SFWindowController
+/// don't have the same parent classes). Unfortunately this means
+/// we have to duplicate some code.
+///
+/// Everything is done via a class that implement this protocol.
+/// There are two of these classes:
+///
+/// SFViewController and SFWindowController
+///
+/// The requester is a WindowImplCocoa. It's used to send back
+/// event via these functions:
+///
+/// windowClosed, windowResized, windowLostFocus, windowGainedFocus
+///
+/// mouseDownAt, mouseUpAt, mouseMovedAt, mouseWheelScrolledAt,
+/// mouseMovedIn, mouseMovedOut
+///
+/// keyDown, keyUp, textEntered
+///
+/// Note: Joysticks are not bound to a view or window
+/// thus they're not managed by a class implementing this protocol.
+///
+////////////////////////////////////////////////////////////
+@protocol WindowImplDelegateProtocol
+
+////////////////////////////////////////////////////////////
+/// \brief Get the display scale factor
+///
+/// \return e.g. 1.0 for classic display, 2.0 for retina display
+///
+////////////////////////////////////////////////////////////
+-(CGFloat)displayScaleFactor;
+
+////////////////////////////////////////////////////////////
+/// \brief Set the WindowImpl who requested this delegate
+///
+////////////////////////////////////////////////////////////
+-(void)setRequesterTo:(sf::priv::WindowImplCocoa*)requester;
+
+////////////////////////////////////////////////////////////
+/// \brief Get the underlying OS specific handle
+///
+/// \return Return the main view or window.
+///
+////////////////////////////////////////////////////////////
+-(sf::WindowHandle)getSystemHandle;
+
+////////////////////////////////////////////////////////////
+/// \brief Determine where the mouse is
+///
+/// \return true when the mouse is inside the OpenGL view, false otherwise
+///
+////////////////////////////////////////////////////////////
+-(BOOL)isMouseInside;
+
+////////////////////////////////////////////////////////////
+/// \brief Grab or release the mouse cursor
+///
+/// \param grabbed YES to grab, NO to release
+///
+////////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed;
+
+////////////////////////////////////////////////////////////
+/// \brief Set the system cursor for the window area
+///
+////////////////////////////////////////////////////////////
+-(void)setCursor:(NSCursor*)cursor;
+
+////////////////////////////////////////////////////////////
+/// \brief Get window position
+///
+/// \return Top left corner of the window or view
+///
+////////////////////////////////////////////////////////////
+-(NSPoint)position;
+
+////////////////////////////////////////////////////////////
+/// \brief Move the window
+///
+/// Doesn't apply if the implementation is 'only' a view.
+///
+/// \param x x position in SFML coordinates
+/// \param y y position in SFML coordinates
+///
+////////////////////////////////////////////////////////////
+-(void)setWindowPositionToX:(int)x Y:(int)y;
+
+////////////////////////////////////////////////////////////
+/// \brief Get window/view's size
+///
+/// \return the size of the rendering area
+///
+////////////////////////////////////////////////////////////
+-(NSSize)size;
+
+////////////////////////////////////////////////////////////
+/// \brief Resize the window/view
+///
+/// \param width new width
+/// \param height new height
+///
+////////////////////////////////////////////////////////////
+-(void)resizeTo:(unsigned int)width by:(unsigned int)height;
+
+////////////////////////////////////////////////////////////
+/// \brief Set the window's title
+///
+/// Doesn't apply if the implementation is 'only' a view.
+///
+/// \param title new title
+///
+////////////////////////////////////////////////////////////
+-(void)changeTitle:(NSString*)title;
+
+////////////////////////////////////////////////////////////
+/// \brief Hide the window
+///
+/// Doesn't apply if the implementation is 'only' a view.
+///
+////////////////////////////////////////////////////////////
+-(void)hideWindow;
+
+////////////////////////////////////////////////////////////
+/// \brief Show the window
+///
+/// Doesn't apply if the implementation is 'only' a view.
+///
+////////////////////////////////////////////////////////////
+-(void)showWindow;
+
+////////////////////////////////////////////////////////////
+/// \brief Close the window
+///
+/// Doesn't apply if the implementation is 'only' a view.
+///
+////////////////////////////////////////////////////////////
+-(void)closeWindow;
+
+////////////////////////////////////////////////////////////
+/// \brief Request the current window to be made the active
+/// foreground window
+///
+////////////////////////////////////////////////////////////
+-(void)requestFocus;
+
+////////////////////////////////////////////////////////////
+/// \brief Check whether the window has the input focus
+///
+/// \return True if window has focus, false otherwise
+///
+////////////////////////////////////////////////////////////
+-(BOOL)hasFocus;
+
+////////////////////////////////////////////////////////////
+/// \brief Enable key repeat
+///
+////////////////////////////////////////////////////////////
+-(void)enableKeyRepeat;
+
+////////////////////////////////////////////////////////////
+/// \brief Disable key repeat
+///
+////////////////////////////////////////////////////////////
+-(void)disableKeyRepeat;
+
+////////////////////////////////////////////////////////////
+/// \brief Set an icon to the application
+///
+/// \param width icon's width
+/// \param height icon's height
+/// \param pixels icon's data
+///
+////////////////////////////////////////////////////////////
+-(void)setIconTo:(unsigned int)width by:(unsigned int)height with:(const sf::Uint8*)pixels;
+
+////////////////////////////////////////////////////////////
+/// \brief Fetch new event
+///
+////////////////////////////////////////////////////////////
+-(void)processEvent;
+
+////////////////////////////////////////////////////////////
+/// \brief Apply a given context to an OpenGL view
+///
+/// \param context OpenGL context to attach to the OpenGL view
+///
+////////////////////////////////////////////////////////////
+-(void)applyContext:(NSOpenGLContext*)context;
+
+@end
diff --git a/src/SFML/Window/OSX/cg_sf_conversion.hpp b/src/SFML/Window/OSX/cg_sf_conversion.hpp
new file mode 100644
index 0000000..c928dd9
--- /dev/null
+++ b/src/SFML/Window/OSX/cg_sf_conversion.hpp
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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_CG_SF_CONVERSION_HPP
+#define SFML_CG_SF_CONVERSION_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Get bpp of a video mode for OS 10.6 or later
+///
+/// With OS 10.6 and later, Quartz doesn't use dictionaries any more
+/// to represent video mode. Instead it uses a CGDisplayMode opaque type.
+///
+////////////////////////////////////////////////////////////
+size_t modeBitsPerPixel(CGDisplayModeRef mode);
+
+////////////////////////////////////////////////////////////
+/// \brief Get bpp for all OS X version
+///
+/// This function use only non-deprecated way to get the
+/// display bits per pixel information for a given display id.
+///
+////////////////////////////////////////////////////////////
+size_t displayBitsPerPixel(CGDirectDisplayID displayId);
+
+////////////////////////////////////////////////////////////
+/// \brief Convert a Quartz video mode into a sf::VideoMode object
+///
+////////////////////////////////////////////////////////////
+VideoMode convertCGModeToSFMode(CGDisplayModeRef cgmode);
+
+////////////////////////////////////////////////////////////
+/// \brief Convert a sf::VideoMode object into a Quartz video mode
+///
+////////////////////////////////////////////////////////////
+CGDisplayModeRef convertSFModeToCGMode(VideoMode sfmode);
+
+} // namespace priv
+} // namespace sf
+
+#endif
diff --git a/src/SFML/Window/OSX/cg_sf_conversion.mm b/src/SFML/Window/OSX/cg_sf_conversion.mm
new file mode 100644
index 0000000..5d9a53f
--- /dev/null
+++ b/src/SFML/Window/OSX/cg_sf_conversion.mm
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/cg_sf_conversion.hpp>
+#include <SFML/System/Err.hpp>
+
+#import <SFML/Window/OSX/Scaling.h>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+size_t modeBitsPerPixel(CGDisplayModeRef mode)
+{
+ size_t bpp = 0; // no match
+
+ // Compare encoding.
+ CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode);
+ if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ bpp = 32;
+ else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ bpp = 16;
+ else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ bpp = 8;
+
+ // Clean up memory.
+ CFRelease(pixEnc);
+
+ return bpp;
+}
+
+
+////////////////////////////////////////////////////////////
+size_t displayBitsPerPixel(CGDirectDisplayID displayId)
+{
+ // Get the display mode.
+ CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
+
+ // Get bpp for the mode.
+ const size_t bpp = modeBitsPerPixel(mode);
+
+ // Clean up Memory.
+ CGDisplayModeRelease(mode);
+
+ return bpp;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode convertCGModeToSFMode(CGDisplayModeRef cgmode)
+{
+ // The main documentation says the sizes returned by
+ // CGDisplayModeGetWidth and CGDisplayModeGetHeight
+ // are expressed in pixels. However, some additional
+ // documentation [1] states they actually return
+ // values in points starting with 10.8.
+ //
+ // We therefore needs to use the scaling factor to
+ // convert the dimensions properly.
+ //
+ // [1]: "APIs for Supporting High Resolution" > "Additions and Changes for OS X v10.8"
+ // https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/APIs/APIs.html#//apple_ref/doc/uid/TP40012302-CH5-SW27
+ VideoMode mode(CGDisplayModeGetWidth(cgmode), CGDisplayModeGetHeight(cgmode), modeBitsPerPixel(cgmode));
+ scaleOutWidthHeight(mode, nil);
+ return mode;
+}
+
+} // namespace priv
+} // namespace sf
+
diff --git a/src/SFML/Window/OSX/cpp_objc_conversion.h b/src/SFML/Window/OSX/cpp_objc_conversion.h
new file mode 100644
index 0000000..db0d572
--- /dev/null
+++ b/src/SFML/Window/OSX/cpp_objc_conversion.h
@@ -0,0 +1,44 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+#include <string>
+
+#import <Foundation/Foundation.h>
+
+////////////////////////////////////////////////////////////
+/// \brief Returns a NSString construct with +stringWithCString:encoding:
+///
+////////////////////////////////////////////////////////////
+NSString* stringToNSString(const std::string& string);
+
+////////////////////////////////////////////////////////////
+/// \brief Returns a NSString construct with +stringWithCString:encoding:
+///
+////////////////////////////////////////////////////////////
+NSString* sfStringToNSString(const sf::String& string);
diff --git a/src/SFML/Window/OSX/cpp_objc_conversion.mm b/src/SFML/Window/OSX/cpp_objc_conversion.mm
new file mode 100644
index 0000000..0ac4b50
--- /dev/null
+++ b/src/SFML/Window/OSX/cpp_objc_conversion.mm
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
+// 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Utf.hpp>
+
+#import <SFML/Window/OSX/cpp_objc_conversion.h>
+#import <Foundation/Foundation.h>
+
+////////////////////////////////////////////////////////////
+NSString* stringToNSString(const std::string& string)
+{
+ std::string utf8; utf8.reserve(string.size() + 1);
+ sf::Utf8::fromAnsi(string.begin(), string.end(), std::back_inserter(utf8));
+ NSString* str = [NSString stringWithCString:utf8.c_str() encoding:NSUTF8StringEncoding];
+
+ return str;
+}
+
+////////////////////////////////////////////////////////////
+NSString* sfStringToNSString(const sf::String& string)
+{
+ sf::Uint32 length = string.getSize() * sizeof(sf::Uint32);
+ const void* data = reinterpret_cast<const void*>(string.getData());
+
+ NSStringEncoding encoding;
+ if (NSHostByteOrder() == NS_LittleEndian)
+ encoding = NSUTF32LittleEndianStringEncoding;
+ else
+ encoding = NSUTF32BigEndianStringEncoding;
+
+ NSString* str = [[NSString alloc] initWithBytes:data length:length encoding:encoding];
+ return [str autorelease];
+}
diff --git a/src/SFML/Window/OpenBSD/JoystickImpl.cpp b/src/SFML/Window/OpenBSD/JoystickImpl.cpp
new file mode 100644
index 0000000..58dfc82
--- /dev/null
+++ b/src/SFML/Window/OpenBSD/JoystickImpl.cpp
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // To implement
+}
+
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // To implement
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ // To implement
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ // To implement
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ // To implement
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ // To implement
+ return JoystickCaps();
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::update()
+{
+ // To implement
+ return JoystickState();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/OpenBSD/JoystickImpl.hpp b/src/SFML/Window/OpenBSD/JoystickImpl.hpp
new file mode 100644
index 0000000..af7ef5c
--- /dev/null
+++ b/src/SFML/Window/OpenBSD/JoystickImpl.hpp
@@ -0,0 +1,117 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_JOYSTICKIMPLOPENBSD_HPP
+#define SFML_JOYSTICKIMPLOPENBSD_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief OpenBSD implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ int m_index; ///< Index of the joystick
+ Joystick::Identification m_identification; ///< Joystick identification
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLOPENBSD_HPP
diff --git a/src/SFML/Window/Sensor.cpp b/src/SFML/Window/Sensor.cpp
new file mode 100644
index 0000000..ae37412
--- /dev/null
+++ b/src/SFML/Window/Sensor.cpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Sensor.hpp>
+#include <SFML/Window/SensorManager.hpp>
+
+
+namespace sf
+{
+
+////////////////////////////////////////////////////////////
+bool Sensor::isAvailable(Type sensor)
+{
+ return priv::SensorManager::getInstance().isAvailable(sensor);
+}
+
+////////////////////////////////////////////////////////////
+void Sensor::setEnabled(Type sensor, bool enabled)
+{
+ return priv::SensorManager::getInstance().setEnabled(sensor, enabled);
+}
+
+////////////////////////////////////////////////////////////
+Vector3f Sensor::getValue(Type sensor)
+{
+ return priv::SensorManager::getInstance().getValue(sensor);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/SensorImpl.hpp b/src/SFML/Window/SensorImpl.hpp
new file mode 100644
index 0000000..a543472
--- /dev/null
+++ b/src/SFML/Window/SensorImpl.hpp
@@ -0,0 +1,57 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPL_HPP
+#define SFML_SENSORIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/Window/Sensor.hpp>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Window/Win32/SensorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+
+ #include <SFML/Window/Unix/SensorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_MACOS)
+
+ #include <SFML/Window/OSX/SensorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_IOS)
+
+ #include <SFML/Window/iOS/SensorImpl.hpp>
+
+#elif defined(SFML_SYSTEM_ANDROID)
+
+ #include <SFML/Window/Android/SensorImpl.hpp>
+
+#endif
+
+
+#endif // SFML_SENSORIMPL_HPP
diff --git a/src/SFML/Window/SensorManager.cpp b/src/SFML/Window/SensorManager.cpp
new file mode 100644
index 0000000..82665e3
--- /dev/null
+++ b/src/SFML/Window/SensorManager.cpp
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorManager.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+SensorManager& SensorManager::getInstance()
+{
+ static SensorManager instance;
+ return instance;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorManager::isAvailable(Sensor::Type sensor)
+{
+ return m_sensors[sensor].available;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorManager::setEnabled(Sensor::Type sensor, bool enabled)
+{
+ if (m_sensors[sensor].available)
+ {
+ m_sensors[sensor].enabled = enabled;
+ m_sensors[sensor].sensor.setEnabled(enabled);
+ }
+ else
+ {
+ err() << "Warning: trying to enable a sensor that is not available (call Sensor::isAvailable to check it)" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorManager::isEnabled(Sensor::Type sensor) const
+{
+ return m_sensors[sensor].enabled;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorManager::getValue(Sensor::Type sensor) const
+{
+ return m_sensors[sensor].value;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorManager::update()
+{
+ for (int i = 0; i < Sensor::Count; ++i)
+ {
+ // Only process available sensors
+ if (m_sensors[i].available)
+ m_sensors[i].value = m_sensors[i].sensor.update();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+SensorManager::SensorManager()
+{
+ // Global sensor initialization
+ SensorImpl::initialize();
+
+ // Per sensor initialization
+ for (int i = 0; i < Sensor::Count; ++i)
+ {
+ // Check which sensors are available
+ m_sensors[i].available = SensorImpl::isAvailable(static_cast<Sensor::Type>(i));
+
+ // Open the available sensors
+ if (m_sensors[i].available)
+ {
+ m_sensors[i].sensor.open(static_cast<Sensor::Type>(i));
+ m_sensors[i].sensor.setEnabled(false);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////
+SensorManager::~SensorManager()
+{
+ // Per sensor cleanup
+ for (int i = 0; i < Sensor::Count; ++i)
+ {
+ if (m_sensors[i].available)
+ m_sensors[i].sensor.close();
+ }
+
+ // Global sensor cleanup
+ SensorImpl::cleanup();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/SensorManager.hpp b/src/SFML/Window/SensorManager.hpp
new file mode 100644
index 0000000..2285ad3
--- /dev/null
+++ b/src/SFML/Window/SensorManager.hpp
@@ -0,0 +1,138 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORMANAGER_HPP
+#define SFML_SENSORMANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Sensor.hpp>
+#include <SFML/Window/SensorImpl.hpp>
+#include <SFML/System/NonCopyable.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Global sensor manager
+///
+////////////////////////////////////////////////////////////
+class SensorManager : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the global unique instance of the manager
+ ///
+ /// \return Unique instance of the sensor manager
+ ///
+ ////////////////////////////////////////////////////////////
+ static SensorManager& getInstance();
+
+ ////////////////////////////////////////////////////////////
+ /// \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
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable a sensor
+ ///
+ /// \param sensor Sensor to modify
+ /// \param enabled Whether it should be enabled or not
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(Sensor::Type sensor, bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is enabled
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is enabled, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isEnabled(Sensor::Type sensor) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current value of a sensor
+ ///
+ /// \param sensor Sensor to read
+ ///
+ /// \return Current value of the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f getValue(Sensor::Type sensor) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the state of all the sensors
+ ///
+ ////////////////////////////////////////////////////////////
+ void update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ SensorManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~SensorManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Sensor information and state
+ ///
+ ////////////////////////////////////////////////////////////
+ struct Item
+ {
+ bool available; ///< Is the sensor available on this device?
+ bool enabled; ///< Current enable state of the sensor
+ SensorImpl sensor; ///< Sensor implementation
+ Vector3f value; ///< The current sensor value
+ };
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Item m_sensors[Sensor::Count]; ///< Sensors information and state
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORMANAGER_HPP
diff --git a/src/SFML/Window/Touch.cpp b/src/SFML/Window/Touch.cpp
new file mode 100644
index 0000000..aa63c72
--- /dev/null
+++ b/src/SFML/Window/Touch.cpp
@@ -0,0 +1,54 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Touch.hpp>
+#include <SFML/Window/InputImpl.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+bool Touch::isDown(unsigned int finger)
+{
+ return priv::InputImpl::isTouchDown(finger);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i Touch::getPosition(unsigned int finger)
+{
+ return priv::InputImpl::getTouchPosition(finger);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i Touch::getPosition(unsigned int finger, const Window& relativeTo)
+{
+ return priv::InputImpl::getTouchPosition(finger, relativeTo);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/ClipboardImpl.cpp b/src/SFML/Window/Unix/ClipboardImpl.cpp
new file mode 100644
index 0000000..df2fd95
--- /dev/null
+++ b/src/SFML/Window/Unix/ClipboardImpl.cpp
@@ -0,0 +1,384 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/ClipboardImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/System/Clock.hpp>
+#include <SFML/System/Err.hpp>
+#include <X11/Xatom.h>
+#include <vector>
+
+
+namespace
+{
+ // Filter the events received by windows (only allow those matching a specific window)
+ Bool checkEvent(::Display*, XEvent* event, XPointer userData)
+ {
+ // Just check if the event matches the window
+ return event->xany.window == reinterpret_cast< ::Window >(userData);
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getString()
+{
+ return getInstance().getStringImpl();
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setString(const String& text)
+{
+ getInstance().setStringImpl(text);
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::processEvents()
+{
+ getInstance().processEventsImpl();
+}
+
+
+////////////////////////////////////////////////////////////
+ClipboardImpl::ClipboardImpl() :
+m_window (0),
+m_requestResponded(false)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+
+ // Get the atoms we need to make use of the clipboard
+ m_clipboard = getAtom("CLIPBOARD", false);
+ m_targets = getAtom("TARGETS", false);
+ m_text = getAtom("TEXT", false);
+ m_utf8String = getAtom("UTF8_STRING", true );
+ m_targetProperty = getAtom("SFML_CLIPBOARD_TARGET_PROPERTY", false);
+
+ // Create a hidden window that will broker our clipboard interactions with X
+ m_window = XCreateSimpleWindow(m_display, DefaultRootWindow(m_display), 0, 0, 1, 1, 0, 0, 0);
+
+ // Register the events we are interested in
+ XSelectInput(m_display, m_window, SelectionNotify | SelectionClear | SelectionRequest);
+}
+
+
+////////////////////////////////////////////////////////////
+ClipboardImpl::~ClipboardImpl()
+{
+ // Destroy the window
+ if (m_window)
+ {
+ XDestroyWindow(m_display, m_window);
+ XFlush(m_display);
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+ClipboardImpl& ClipboardImpl::getInstance()
+{
+ static ClipboardImpl instance;
+
+ return instance;
+}
+
+
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getStringImpl()
+{
+ // Check if anybody owns the current selection
+ if (XGetSelectionOwner(m_display, m_clipboard) == None)
+ {
+ m_clipboardContents.clear();
+
+ return m_clipboardContents;
+ }
+
+ // Process any already pending events
+ processEvents();
+
+ m_requestResponded = false;
+
+ // Request the current selection to be converted to UTF-8 (or STRING
+ // if UTF-8 is not available) and written to our window property
+ XConvertSelection(
+ m_display,
+ m_clipboard,
+ (m_utf8String != None) ? m_utf8String : XA_STRING,
+ m_targetProperty,
+ m_window,
+ CurrentTime
+ );
+
+ Clock clock;
+
+ // Wait for a response for up to 1000ms
+ while (!m_requestResponded && (clock.getElapsedTime().asMilliseconds() < 1000))
+ processEvents();
+
+ // If no response was received within the time period, clear our clipboard contents
+ if (!m_requestResponded)
+ m_clipboardContents.clear();
+
+ return m_clipboardContents;
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setStringImpl(const String& text)
+{
+ m_clipboardContents = text;
+
+ // Set our window as the current owner of the selection
+ XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
+
+ // Check if setting the selection owner was successful
+ if (XGetSelectionOwner(m_display, m_clipboard) != m_window)
+ err() << "Cannot set clipboard string: Unable to get ownership of X selection" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::processEventsImpl()
+{
+ XEvent event;
+
+ // Pick out the events that are interesting for this window
+ while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
+ m_events.push_back(event);
+
+ // Handle the events for this window that we just picked out
+ while (!m_events.empty())
+ {
+ event = m_events.front();
+ m_events.pop_front();
+ processEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::processEvent(XEvent& windowEvent)
+{
+ switch (windowEvent.type)
+ {
+ case SelectionClear:
+ {
+ // We don't have any resources we need to clean up
+ // when losing selection ownership so we don't do
+ // anything when we receive SelectionClear
+ // We will still respond to any future SelectionRequest
+ // events since doing so doesn't really do any harm
+ break;
+ }
+ case SelectionNotify:
+ {
+ // Notification that the current selection owner
+ // has responded to our request
+
+ XSelectionEvent& selectionEvent = *reinterpret_cast<XSelectionEvent*>(&windowEvent.xselection);
+
+ m_clipboardContents.clear();
+
+ // If retrieving the selection fails or conversion is unsuccessful
+ // we leave the contents of the clipboard empty since we don't
+ // own it and we don't know what it could currently be
+ if ((selectionEvent.property == None) || (selectionEvent.selection != m_clipboard))
+ break;
+
+ Atom type;
+ int format;
+ unsigned long items;
+ unsigned long remainingBytes;
+ unsigned char* data = 0;
+
+ // The selection owner should have wrote the selection
+ // data to the specified window property
+ int result = XGetWindowProperty(
+ m_display,
+ m_window,
+ m_targetProperty,
+ 0,
+ 0x7fffffff,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &items,
+ &remainingBytes,
+ &data
+ );
+
+ if (result == Success)
+ {
+ // We don't support INCR for now
+ // It is very unlikely that this will be returned
+ // for purely text data transfer anyway
+ if (type != getAtom("INCR", false))
+ {
+ // Only copy the data if the format is what we expect
+ if ((type == m_utf8String) && (format == 8))
+ {
+ m_clipboardContents = String::fromUtf8(data, data + items);
+ }
+ else if ((type == XA_STRING) && (format == 8))
+ {
+ // Convert from ANSI std::string to sf::String
+ m_clipboardContents = std::string(data, data + items);
+ }
+ }
+
+ XFree(data);
+
+ // The selection requestor must always delete the property themselves
+ XDeleteProperty(m_display, m_window, m_targetProperty);
+ }
+
+ m_requestResponded = true;
+
+ break;
+ }
+ case SelectionRequest:
+ {
+ // Respond to a request for our clipboard contents
+ XSelectionRequestEvent& selectionRequestEvent = *reinterpret_cast<XSelectionRequestEvent*>(&windowEvent.xselectionrequest);
+
+ // Our reply
+ XSelectionEvent selectionEvent;
+
+ selectionEvent.type = SelectionNotify;
+ selectionEvent.requestor = selectionRequestEvent.requestor;
+ selectionEvent.selection = selectionRequestEvent.selection;
+ selectionEvent.property = selectionRequestEvent.property;
+ selectionEvent.time = selectionRequestEvent.time;
+
+ if (selectionRequestEvent.selection == m_clipboard)
+ {
+ if (selectionRequestEvent.target == m_targets)
+ {
+ // Respond to a request for our valid conversion targets
+ std::vector<Atom> targets;
+
+ targets.push_back(m_targets);
+ targets.push_back(m_text);
+ targets.push_back(XA_STRING);
+
+ if (m_utf8String != None)
+ targets.push_back(m_utf8String);
+
+ XChangeProperty(
+ m_display,
+ selectionRequestEvent.requestor,
+ selectionRequestEvent.property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&targets[0]),
+ targets.size()
+ );
+
+ // Notify the requestor that they can read the targets from their window property
+ selectionEvent.target = m_targets;
+
+ XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent));
+
+ break;
+ }
+ else if ((selectionRequestEvent.target == XA_STRING) || ((m_utf8String == None) && (selectionRequestEvent.target == m_text)))
+ {
+ // Respond to a request for conversion to a Latin-1 string
+ std::string data = m_clipboardContents.toAnsiString();
+
+ XChangeProperty(
+ m_display,
+ selectionRequestEvent.requestor,
+ selectionRequestEvent.property,
+ XA_STRING,
+ 8,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(data.c_str()),
+ data.size()
+ );
+
+ // Notify the requestor that they can read the data from their window property
+ selectionEvent.target = XA_STRING;
+
+ XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent));
+
+ break;
+ }
+ else if ((m_utf8String != None) && ((selectionRequestEvent.target == m_utf8String) || (selectionRequestEvent.target == m_text)))
+ {
+ // Respond to a request for conversion to a UTF-8 string
+ // or an encoding of our choosing (we always choose UTF-8)
+ std::basic_string<Uint8> data = m_clipboardContents.toUtf8();
+
+ XChangeProperty(
+ m_display,
+ selectionRequestEvent.requestor,
+ selectionRequestEvent.property,
+ m_utf8String,
+ 8,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(data.c_str()),
+ data.size()
+ );
+
+ // Notify the requestor that they can read the data from their window property
+ selectionEvent.target = m_utf8String;
+
+ XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent));
+
+ break;
+ }
+ }
+
+ // Notify the requestor that we could not respond to their request
+ selectionEvent.target = selectionRequestEvent.target;
+ selectionEvent.property = None;
+
+ XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent));
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/ClipboardImpl.hpp b/src/SFML/Window/Unix/ClipboardImpl.hpp
new file mode 100644
index 0000000..48ec787
--- /dev/null
+++ b/src/SFML/Window/Unix/ClipboardImpl.hpp
@@ -0,0 +1,155 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPLX11_HPP
+#define SFML_CLIPBOARDIMPLX11_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+#include <X11/Xlib.h>
+#include <deque>
+
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class ClipboardImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \param text sf::String object containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process pending events for the hidden clipboard window
+ ///
+ /// This function has to be called as part of normal window
+ /// event processing in order for our application to respond
+ /// to selection requests from other applications.
+ ///
+ ////////////////////////////////////////////////////////////
+ static void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ClipboardImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~ClipboardImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get singleton instance
+ ///
+ /// \return Singleton instance
+ ///
+ ////////////////////////////////////////////////////////////
+ static ClipboardImpl& getInstance();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief getString implementation
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ String getStringImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief setString implementation
+ ///
+ /// \param text sf::String object containing the data to be sent to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ void setStringImpl(const String& text);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief processEvents implementation
+ ///
+ ////////////////////////////////////////////////////////////
+ void processEventsImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process an incoming event from the window
+ ///
+ /// \param windowEvent Event which has been received
+ ///
+ ////////////////////////////////////////////////////////////
+ void processEvent(XEvent& windowEvent);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Window m_window; ///< X identifier defining our window
+ ::Display* m_display; ///< Pointer to the display
+ Atom m_clipboard; ///< X Atom identifying the CLIPBOARD selection
+ Atom m_targets; ///< X Atom identifying TARGETS
+ Atom m_text; ///< X Atom identifying TEXT
+ Atom m_utf8String; ///< X Atom identifying UTF8_STRING
+ Atom m_targetProperty; ///< X Atom identifying our destination window property
+ String m_clipboardContents; ///< Our clipboard contents
+ std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window
+ bool m_requestResponded; ///< Holds whether our selection request has been responded to or not
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARDIMPLX11_HPP
diff --git a/src/SFML/Window/Unix/CursorImpl.cpp b/src/SFML/Window/Unix/CursorImpl.cpp
new file mode 100644
index 0000000..011a2b1
--- /dev/null
+++ b/src/SFML/Window/Unix/CursorImpl.cpp
@@ -0,0 +1,156 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/CursorImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <X11/cursorfont.h>
+#include <X11/Xutil.h>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+CursorImpl::CursorImpl() :
+m_display(OpenDisplay()),
+m_cursor(None)
+{
+ // That's it.
+}
+
+
+////////////////////////////////////////////////////////////
+CursorImpl::~CursorImpl()
+{
+ release();
+
+ CloseDisplay(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ release();
+
+ // Convert the image into a bitmap (monochrome!).
+ std::size_t bytes = (size.x + 7) / 8 * size.y;
+ std::vector<Uint8> mask(bytes, 0); // Defines which pixel is transparent.
+ std::vector<Uint8> data(bytes, 1); // Defines which pixel is white/black.
+
+ for (std::size_t j = 0; j < size.y; ++j)
+ {
+ for (std::size_t i = 0; i < size.x; ++i)
+ {
+ std::size_t pixelIndex = i + j * size.x;
+ std::size_t byteIndex = pixelIndex / 8;
+ std::size_t bitIndex = i % 8;
+
+ // Turn on pixel that are not transparent
+ Uint8 opacity = pixels[pixelIndex * 4 + 3] > 0 ? 1 : 0;
+ mask[byteIndex] |= opacity << bitIndex;
+
+ // Choose between black/background & white/foreground color for each pixel,
+ // based on the pixel color intensity: on average, if a channel is "active"
+ // at 25%, the bit is white.
+ int intensity = pixels[pixelIndex * 4 + 0] + pixels[pixelIndex * 4 + 1] + pixels[pixelIndex * 4 + 2];
+ Uint8 bit = intensity > 64 ? 1 : 0;
+ data[byteIndex] |= bit << bitIndex;
+ }
+ }
+
+ Pixmap maskPixmap = XCreateBitmapFromData(m_display, XDefaultRootWindow(m_display),
+ (char*)&mask[0], size.x, size.y);
+ Pixmap dataPixmap = XCreateBitmapFromData(m_display, XDefaultRootWindow(m_display),
+ (char*)&data[0], size.x, size.y);
+
+ // Define the foreground color as white and the background as black.
+ XColor fg, bg;
+ fg.red = fg.blue = fg.green = -1;
+ bg.red = bg.blue = bg.green = 0;
+
+ // Create the monochrome cursor.
+ m_cursor = XCreatePixmapCursor(m_display,
+ dataPixmap, maskPixmap,
+ &fg, &bg,
+ hotspot.x, hotspot.y);
+
+ // Free the resources
+ XFreePixmap(m_display, dataPixmap);
+ XFreePixmap(m_display, maskPixmap);
+
+ // We assume everything went fine...
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromSystem(Cursor::Type type)
+{
+ release();
+
+ unsigned int shape;
+ switch (type)
+ {
+ default: return false;
+
+ case Cursor::Arrow: shape = XC_arrow; break;
+ case Cursor::Wait: shape = XC_watch; break;
+ case Cursor::Text: shape = XC_xterm; break;
+ case Cursor::Hand: shape = XC_hand1; break;
+ case Cursor::SizeHorizontal: shape = XC_sb_h_double_arrow; break;
+ case Cursor::SizeVertical: shape = XC_sb_v_double_arrow; break;
+ case Cursor::SizeAll: shape = XC_fleur; break;
+ case Cursor::Cross: shape = XC_crosshair; break;
+ case Cursor::Help: shape = XC_question_arrow; break;
+ case Cursor::NotAllowed: shape = XC_X_cursor; break;
+ }
+
+ m_cursor = XCreateFontCursor(m_display, shape);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void CursorImpl::release()
+{
+ if (m_cursor != None)
+ {
+ XFreeCursor(m_display, m_cursor);
+ m_cursor = None;
+ }
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/Unix/CursorImpl.hpp b/src/SFML/Window/Unix/CursorImpl.hpp
new file mode 100644
index 0000000..9bd4052
--- /dev/null
+++ b/src/SFML/Window/Unix/CursorImpl.hpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSORIMPLUNIX_HPP
+#define SFML_CURSORIMPLUNIX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
+#include <X11/Xlib.h>
+
+namespace sf
+{
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of Cursor
+///
+////////////////////////////////////////////////////////////
+class CursorImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Refer to sf::Cursor::Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// Refer to sf::Cursor::~Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ ~CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// Refer to sf::Cursor::loadFromPixels().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Refer to sf::Cursor::loadFromSystem().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Cursor::Type type);
+
+private:
+
+ friend class WindowImplX11;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Release the cursor, if we have loaded one.
+ ///
+ ////////////////////////////////////////////////////////////
+ void release();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Display* m_display;
+ ::Cursor m_cursor;
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_CUSROSIMPLUNIX_HPP
diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp
new file mode 100644
index 0000000..351a128
--- /dev/null
+++ b/src/SFML/Window/Unix/Display.cpp
@@ -0,0 +1,110 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <X11/keysym.h>
+#include <cassert>
+#include <cstdlib>
+#include <map>
+
+
+namespace
+{
+ // The shared display and its reference counter
+ Display* sharedDisplay = NULL;
+ unsigned int referenceCount = 0;
+ sf::Mutex mutex;
+
+ typedef std::map<std::string, Atom> AtomMap;
+ AtomMap atoms;
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+Display* OpenDisplay()
+{
+ Lock lock(mutex);
+
+ if (referenceCount == 0)
+ {
+ sharedDisplay = XOpenDisplay(NULL);
+
+ // Opening display failed: The best we can do at the moment is to output a meaningful error message
+ // and cause an abnormal program termination
+ if (!sharedDisplay)
+ {
+ err() << "Failed to open X11 display; make sure the DISPLAY environment variable is set correctly" << std::endl;
+ std::abort();
+ }
+ }
+
+ referenceCount++;
+ return sharedDisplay;
+}
+
+
+////////////////////////////////////////////////////////////
+void CloseDisplay(Display* display)
+{
+ Lock lock(mutex);
+
+ assert(display == sharedDisplay);
+
+ referenceCount--;
+ if (referenceCount == 0)
+ XCloseDisplay(display);
+}
+
+
+////////////////////////////////////////////////////////////
+Atom getAtom(const std::string& name, bool onlyIfExists)
+{
+ AtomMap::const_iterator iter = atoms.find(name);
+
+ if (iter != atoms.end())
+ return iter->second;
+
+ Display* display = OpenDisplay();
+
+ Atom atom = XInternAtom(display, name.c_str(), onlyIfExists ? True : False);
+
+ CloseDisplay(display);
+
+ atoms[name] = atom;
+
+ return atom;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp
new file mode 100644
index 0000000..d2bb736
--- /dev/null
+++ b/src/SFML/Window/Unix/Display.hpp
@@ -0,0 +1,74 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SHAREDDISPLAY_HPP
+#define SFML_SHAREDDISPLAY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <X11/Xlib.h>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Get the shared Display
+///
+/// This function increments the reference count of the display,
+/// it must be matched with a call to CloseDisplay.
+///
+/// \return Pointer to the shared display
+///
+////////////////////////////////////////////////////////////
+Display* OpenDisplay();
+
+////////////////////////////////////////////////////////////
+/// \brief Release a reference to the shared display
+///
+/// \param display Display to release
+///
+////////////////////////////////////////////////////////////
+void CloseDisplay(Display* display);
+
+////////////////////////////////////////////////////////////
+/// \brief Get the atom with the specified name
+///
+/// \param name Name of the atom
+/// \param onlyIfExists Don't try to create the atom if it doesn't already exist
+///
+/// \return Atom if it exists or None (0) if it doesn't
+///
+////////////////////////////////////////////////////////////
+Atom getAtom(const std::string& name, bool onlyIfExists = false);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SHAREDDISPLAY_HPP
diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp
new file mode 100644
index 0000000..cd02236
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxContext.cpp
@@ -0,0 +1,780 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/WindowImplX11.hpp> // important to be included first (conflict with None)
+#include <SFML/Window/Unix/GlxContext.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Err.hpp>
+#include <vector>
+
+#if !defined(GLX_DEBUGGING) && defined(SFML_DEBUG)
+ // Enable this to print messages to err() everytime GLX produces errors
+ //#define GLX_DEBUGGING
+#endif
+
+namespace
+{
+ sf::Mutex glxErrorMutex;
+ bool glxErrorOccurred = false;
+
+ int HandleXError(::Display*, XErrorEvent*)
+ {
+ glxErrorOccurred = true;
+ return 0;
+ }
+
+ class GlxErrorHandler
+ {
+ public:
+
+ GlxErrorHandler(::Display* display) :
+ m_lock (glxErrorMutex),
+ m_display(display)
+ {
+ glxErrorOccurred = false;
+ m_previousHandler = XSetErrorHandler(HandleXError);
+ }
+
+ ~GlxErrorHandler()
+ {
+ XSync(m_display, False);
+ XSetErrorHandler(m_previousHandler);
+ }
+
+ private:
+ sf::Lock m_lock;
+ ::Display* m_display;
+ int (*m_previousHandler)(::Display*, XErrorEvent*);
+ };
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void ensureExtensionsInit(::Display* display, int screen)
+{
+ static bool initialized = false;
+ if (!initialized)
+ {
+ initialized = true;
+
+ // We don't check the return value since the extension
+ // flags are cleared even if loading fails
+ sfglx_LoadFunctions(display, screen);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared) :
+m_display (NULL),
+m_window (0),
+m_context (NULL),
+m_pbuffer (0),
+m_ownsWindow(false)
+{
+ // Save the creation settings
+ m_settings = ContextSettings();
+
+ // Open the connection with the X server
+ m_display = OpenDisplay();
+
+ // Make sure that extensions are initialized
+ ensureExtensionsInit(m_display, DefaultScreen(m_display));
+
+ // Create the rendering surface (window or pbuffer if supported)
+ createSurface(shared, 1, 1, VideoMode::getDesktopMode().bitsPerPixel);
+
+ // Create the context
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_display (NULL),
+m_window (0),
+m_context (NULL),
+m_pbuffer (0),
+m_ownsWindow(false)
+{
+ // Save the creation settings
+ m_settings = settings;
+
+ // Open the connection with the X server
+ m_display = OpenDisplay();
+
+ // Make sure that extensions are initialized
+ ensureExtensionsInit(m_display, DefaultScreen(m_display));
+
+ // Create the rendering surface from the owner window
+ createSurface(static_cast< ::Window>(owner->getSystemHandle()));
+
+ // Create the context
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
+m_display (NULL),
+m_window (0),
+m_context (NULL),
+m_pbuffer (0),
+m_ownsWindow(false)
+{
+ // Save the creation settings
+ m_settings = settings;
+
+ // Open the connection with the X server
+ m_display = OpenDisplay();
+
+ // Make sure that extensions are initialized
+ ensureExtensionsInit(m_display, DefaultScreen(m_display));
+
+ // Create the rendering surface (window or pbuffer if supported)
+ createSurface(shared, width, height, VideoMode::getDesktopMode().bitsPerPixel);
+
+ // Create the context
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::~GlxContext()
+{
+ // Notify unshared OpenGL resources of context destruction
+ cleanupUnsharedResources();
+
+ // Destroy the context
+ if (m_context)
+ {
+#if defined(GLX_DEBUGGING)
+ GlxErrorHandler handler(m_display);
+#endif
+
+ if (glXGetCurrentContext() == m_context)
+ glXMakeCurrent(m_display, None, NULL);
+ glXDestroyContext(m_display, m_context);
+
+#if defined(GLX_DEBUGGING)
+ if (glxErrorOccurred)
+ err() << "GLX error in GlxContext::~GlxContext()" << std::endl;
+#endif
+ }
+
+ if (m_pbuffer)
+ {
+ glXDestroyPbuffer(m_display, m_pbuffer);
+ }
+
+ // Destroy the window if we own it
+ if (m_window && m_ownsWindow)
+ {
+ XDestroyWindow(m_display, m_window);
+ XFlush(m_display);
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+GlFunctionPointer GlxContext::getFunction(const char* name)
+{
+ return reinterpret_cast<GlFunctionPointer>(glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(name)));
+}
+
+
+////////////////////////////////////////////////////////////
+bool GlxContext::makeCurrent(bool current)
+{
+ if (!m_context)
+ return false;
+
+#if defined(GLX_DEBUGGING)
+ GlxErrorHandler handler(m_display);
+#endif
+
+ bool result = false;
+
+ if (current)
+ {
+ if (m_pbuffer)
+ {
+ result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context);
+ }
+ else if (m_window)
+ {
+ result = glXMakeCurrent(m_display, m_window, m_context);
+ }
+ }
+ else
+ {
+ result = glXMakeCurrent(m_display, None, NULL);
+ }
+
+#if defined(GLX_DEBUGGING)
+ if (glxErrorOccurred)
+ err() << "GLX error in GlxContext::makeCurrent()" << std::endl;
+#endif
+
+ return result;
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::display()
+{
+#if defined(GLX_DEBUGGING)
+ GlxErrorHandler handler(m_display);
+#endif
+
+ if (m_pbuffer)
+ glXSwapBuffers(m_display, m_pbuffer);
+ else if (m_window)
+ glXSwapBuffers(m_display, m_window);
+
+#if defined(GLX_DEBUGGING)
+ if (glxErrorOccurred)
+ err() << "GLX error in GlxContext::display()" << std::endl;
+#endif
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::setVerticalSyncEnabled(bool enabled)
+{
+ int result = 0;
+
+ // Prioritize the EXT variant and fall back to MESA or SGI if needed
+ // We use the direct pointer to the MESA entry point instead of the alias
+ // because glx.h declares the entry point as an external function
+ // which would require us to link in an additional library
+ if (sfglx_ext_EXT_swap_control == sfglx_LOAD_SUCCEEDED)
+ {
+ glXSwapIntervalEXT(m_display, m_pbuffer ? m_pbuffer : m_window, enabled ? 1 : 0);
+ }
+ else if (sfglx_ext_MESA_swap_control == sfglx_LOAD_SUCCEEDED)
+ {
+ result = sf_ptrc_glXSwapIntervalMESA(enabled ? 1 : 0);
+ }
+ else if (sfglx_ext_SGI_swap_control == sfglx_LOAD_SUCCEEDED)
+ {
+ result = glXSwapIntervalSGI(enabled ? 1 : 0);
+ }
+ else
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ err() << "Setting vertical sync not supported" << std::endl;
+
+ warned = true;
+ }
+ }
+
+ if (result != 0)
+ err() << "Setting vertical sync failed" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings)
+{
+ // Make sure that extensions are initialized
+ ensureExtensionsInit(display, DefaultScreen(display));
+
+ // Retrieve all the visuals
+ int count;
+ XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count);
+ if (visuals)
+ {
+ // Evaluate all the returned visuals, and pick the best one
+ int bestScore = 0x7FFFFFFF;
+ XVisualInfo bestVisual = XVisualInfo();
+ for (int i = 0; i < count; ++i)
+ {
+ // Check mandatory attributes
+ int doubleBuffer;
+ glXGetConfig(display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
+ if (!doubleBuffer)
+ continue;
+
+ // Extract the components of the current visual
+ int red, green, blue, alpha, depth, stencil, multiSampling, samples, sRgb;
+ glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red);
+ glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green);
+ glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue);
+ glXGetConfig(display, &visuals[i], GLX_ALPHA_SIZE, &alpha);
+ glXGetConfig(display, &visuals[i], GLX_DEPTH_SIZE, &depth);
+ glXGetConfig(display, &visuals[i], GLX_STENCIL_SIZE, &stencil);
+
+ if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED)
+ {
+ glXGetConfig(display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
+ glXGetConfig(display, &visuals[i], GLX_SAMPLES_ARB, &samples);
+ }
+ else
+ {
+ multiSampling = 0;
+ samples = 0;
+ }
+
+ if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED))
+ {
+ glXGetConfig(display, &visuals[i], GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb);
+ }
+ else
+ {
+ sRgb = 0;
+ }
+
+ // TODO: Replace this with proper acceleration detection
+ bool accelerated = true;
+
+ // Evaluate the visual
+ int color = red + green + blue + alpha;
+ int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated, sRgb == True);
+
+ // If it's better than the current best, make it the new best
+ if (score < bestScore)
+ {
+ bestScore = score;
+ bestVisual = visuals[i];
+ }
+ }
+
+ // Free the array of visuals
+ XFree(visuals);
+
+ return bestVisual;
+ }
+ else
+ {
+ // Should never happen...
+ err() << "No GLX visual found. You should check your graphics driver" << std::endl;
+
+ return XVisualInfo();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::updateSettingsFromVisualInfo(XVisualInfo* visualInfo)
+{
+ // Update the creation settings from the chosen format
+ int depth, stencil, multiSampling, samples, sRgb;
+ glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth);
+ glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil);
+
+ if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED)
+ {
+ glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
+ glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples);
+ }
+ else
+ {
+ multiSampling = 0;
+ samples = 0;
+ }
+
+ if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED))
+ {
+ glXGetConfig(m_display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb);
+ }
+ else
+ {
+ sRgb = 0;
+ }
+
+ m_settings.depthBits = static_cast<unsigned int>(depth);
+ m_settings.stencilBits = static_cast<unsigned int>(stencil);
+ m_settings.antialiasingLevel = multiSampling ? samples : 0;
+ m_settings.sRgbCapable = (sRgb == True);
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::updateSettingsFromWindow()
+{
+ // Retrieve the attributes of the target window
+ XWindowAttributes windowAttributes;
+ if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0)
+ {
+ err() << "Failed to get the window attributes" << std::endl;
+ return;
+ }
+
+ // Get its visuals
+ XVisualInfo tpl;
+ tpl.screen = DefaultScreen(m_display);
+ tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
+ int nbVisuals = 0;
+ XVisualInfo* visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
+
+ if (!visualInfo)
+ return;
+
+ updateSettingsFromVisualInfo(visualInfo);
+
+ XFree(visualInfo);
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel)
+{
+ // Choose the visual according to the context settings
+ XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings);
+
+ // Check if the shared context already exists and pbuffers are supported
+ if (shared && (sfglx_ext_SGIX_pbuffer == sfglx_LOAD_SUCCEEDED))
+ {
+ // There are no GLX versions prior to 1.0
+ int major = 0;
+ int minor = 0;
+
+ glXQueryVersion(m_display, &major, &minor);
+
+ // Check if glXCreatePbuffer is available (requires GLX 1.3 or greater)
+ bool hasCreatePbuffer = ((major > 1) || (minor >= 3));
+
+ if (hasCreatePbuffer)
+ {
+ // Get a GLXFBConfig that matches the visual
+ GLXFBConfig* config = NULL;
+
+ // We don't supply attributes to match against, since
+ // the visual we are matching against was already
+ // deemed suitable in selectBestVisual()
+ int nbConfigs = 0;
+ GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), NULL, &nbConfigs);
+
+ for (int i = 0; configs && (i < nbConfigs); ++i)
+ {
+ XVisualInfo* visual = glXGetVisualFromFBConfig(m_display, configs[i]);
+
+ if (!visual)
+ continue;
+
+ if (visual->visualid == visualInfo.visualid)
+ {
+ config = &configs[i];
+ XFree(visual);
+ break;
+ }
+
+ XFree(visual);
+ }
+
+ if (config)
+ {
+ int attributes[] =
+ {
+ GLX_PBUFFER_WIDTH, static_cast<int>(width),
+ GLX_PBUFFER_HEIGHT, static_cast<int>(height),
+ 0, 0
+ };
+
+ m_pbuffer = glXCreatePbuffer(m_display, *config, attributes);
+
+ updateSettingsFromVisualInfo(&visualInfo);
+
+ XFree(configs);
+
+ return;
+ }
+
+ if (configs)
+ XFree(configs);
+ }
+ }
+
+ // If pbuffers are not available we use a hidden window as the off-screen surface to draw to
+ int screen = DefaultScreen(m_display);
+
+ // Define the window attributes
+ XSetWindowAttributes attributes;
+ attributes.colormap = XCreateColormap(m_display, RootWindow(m_display, screen), visualInfo.visual, AllocNone);
+
+ m_window = XCreateWindow(m_display,
+ RootWindow(m_display, screen),
+ 0, 0,
+ width, height,
+ 0,
+ DefaultDepth(m_display, screen),
+ InputOutput,
+ visualInfo.visual,
+ CWColormap,
+ &attributes);
+
+ m_ownsWindow = true;
+
+ updateSettingsFromWindow();
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::createSurface(::Window window)
+{
+ // A window already exists, so just use it
+ m_window = window;
+
+ updateSettingsFromWindow();
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::createContext(GlxContext* shared)
+{
+ // Get a working copy of the context settings
+ ContextSettings settings = m_settings;
+
+ XVisualInfo* visualInfo = NULL;
+
+ if (m_pbuffer)
+ {
+ unsigned int fbConfigId = 0;
+
+ glXQueryDrawable(m_display, m_pbuffer, GLX_FBCONFIG_ID, &fbConfigId);
+
+ int attributes[] =
+ {
+ GLX_FBCONFIG_ID, static_cast<int>(fbConfigId),
+ 0, 0
+ };
+
+ int count = 0;
+ GLXFBConfig* fbconfig = glXChooseFBConfig(m_display, DefaultScreen(m_display), attributes, &count);
+
+ if (count == 1)
+ visualInfo = glXGetVisualFromFBConfig(m_display, *fbconfig);
+
+ if (fbconfig)
+ XFree(fbconfig);
+ }
+ else
+ {
+ // Retrieve the attributes of the target window
+ XWindowAttributes windowAttributes;
+ if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0)
+ {
+ err() << "Failed to get the window attributes" << std::endl;
+ return;
+ }
+
+ // Get its visuals
+ XVisualInfo tpl;
+ tpl.screen = DefaultScreen(m_display);
+ tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
+ int nbVisuals = 0;
+ visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
+ }
+
+ if (!visualInfo)
+ {
+ err() << "Failed to get visual info" << std::endl;
+ return;
+ }
+
+ // Get the context to share display lists with
+ GLXContext toShare = shared ? shared->m_context : NULL;
+
+ // There are no GLX versions prior to 1.0
+ int major = 0;
+ int minor = 0;
+
+ if (!glXQueryVersion(m_display, &major, &minor))
+ err() << "Failed to query GLX version, limited to legacy context creation" << std::endl;
+
+ // Check if glXCreateContextAttribsARB is available (requires GLX 1.3 or greater)
+ bool hasCreateContextArb = (sfglx_ext_ARB_create_context == sfglx_LOAD_SUCCEEDED) && ((major > 1) || (minor >= 3));
+
+ // Create the OpenGL context -- first try using glXCreateContextAttribsARB
+ if (hasCreateContextArb)
+ {
+ // Get a GLXFBConfig that matches the window's visual, for glXCreateContextAttribsARB
+ GLXFBConfig* config = NULL;
+
+ // We don't supply attributes to match against, since
+ // the visual we are matching against was already
+ // deemed suitable in selectBestVisual()
+ int nbConfigs = 0;
+ GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), NULL, &nbConfigs);
+
+ for (int i = 0; configs && (i < nbConfigs); ++i)
+ {
+ XVisualInfo* visual = glXGetVisualFromFBConfig(m_display, configs[i]);
+
+ if (!visual)
+ continue;
+
+ if (visual->visualid == visualInfo->visualid)
+ {
+ config = &configs[i];
+ XFree(visual);
+ break;
+ }
+
+ XFree(visual);
+ }
+
+ if (!config)
+ err() << "Failed to get GLXFBConfig which corresponds to the window's visual" << std::endl;
+
+ while (config && !m_context && m_settings.majorVersion)
+ {
+ std::vector<int> attributes;
+
+ // Check if the user requested a specific context version (anything > 1.1)
+ if ((m_settings.majorVersion > 1) || ((m_settings.majorVersion == 1) && (m_settings.minorVersion > 1)))
+ {
+ attributes.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
+ attributes.push_back(m_settings.majorVersion);
+ attributes.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
+ attributes.push_back(m_settings.minorVersion);
+ }
+
+ // Check if setting the profile is supported
+ if (sfglx_ext_ARB_create_context_profile == sfglx_LOAD_SUCCEEDED)
+ {
+ int profile = (m_settings.attributeFlags & ContextSettings::Core) ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ int debug = (m_settings.attributeFlags & ContextSettings::Debug) ? GLX_CONTEXT_DEBUG_BIT_ARB : 0;
+
+ attributes.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
+ attributes.push_back(profile);
+ attributes.push_back(GLX_CONTEXT_FLAGS_ARB);
+ attributes.push_back(debug);
+ }
+ else
+ {
+ if ((m_settings.attributeFlags & ContextSettings::Core) || (m_settings.attributeFlags & ContextSettings::Debug))
+ err() << "Selecting a profile during context creation is not supported,"
+ << "disabling comptibility and debug" << std::endl;
+
+ m_settings.attributeFlags = ContextSettings::Default;
+ }
+
+ // Append the terminating 0
+ attributes.push_back(0);
+ attributes.push_back(0);
+
+ // RAII GLX error handler (we simply ignore errors here)
+ // On an error, glXCreateContextAttribsARB will return 0 anyway
+ GlxErrorHandler handler(m_display);
+
+ if (toShare)
+ {
+ if (!glXMakeCurrent(m_display, None, NULL))
+ {
+ err() << "Failed to deactivate shared context before sharing" << std::endl;
+ return;
+ }
+ }
+
+ // Create the context
+ m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]);
+
+ if (!m_context)
+ {
+ // If we couldn't create the context, first try disabling flags,
+ // then lower the version number and try again -- stop at 0.0
+ // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
+ if (m_settings.attributeFlags != ContextSettings::Default)
+ {
+ m_settings.attributeFlags = ContextSettings::Default;
+ }
+ else if (m_settings.minorVersion > 0)
+ {
+ // If the minor version is not 0, we decrease it and try again
+ m_settings.minorVersion--;
+
+ m_settings.attributeFlags = settings.attributeFlags;
+ }
+ else
+ {
+ // If the minor version is 0, we decrease the major version
+ m_settings.majorVersion--;
+ m_settings.minorVersion = 9;
+
+ m_settings.attributeFlags = settings.attributeFlags;
+ }
+ }
+ }
+
+ if (configs)
+ XFree(configs);
+ }
+
+ // If glXCreateContextAttribsARB failed, use glXCreateContext
+ if (!m_context)
+ {
+ // set the context version to 2.1 (arbitrary) and disable flags
+ m_settings.majorVersion = 2;
+ m_settings.minorVersion = 1;
+ m_settings.attributeFlags = ContextSettings::Default;
+
+#if defined(GLX_DEBUGGING)
+ GlxErrorHandler handler(m_display);
+#endif
+
+ if (toShare)
+ {
+ if (!glXMakeCurrent(m_display, None, NULL))
+ {
+ err() << "Failed to deactivate shared context before sharing" << std::endl;
+ return;
+ }
+ }
+
+ // Create the context, using the target window's visual
+ m_context = glXCreateContext(m_display, visualInfo, toShare, true);
+
+#if defined(GLX_DEBUGGING)
+ if (glxErrorOccurred)
+ err() << "GLX error in GlxContext::createContext()" << std::endl;
+#endif
+ }
+
+ if (!m_context)
+ err() << "Failed to create an OpenGL context for this window" << std::endl;
+
+ // Free the visual info
+ XFree(visualInfo);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp
new file mode 100644
index 0000000..e974c44
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxContext.hpp
@@ -0,0 +1,192 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_GLXCONTEXT_HPP
+#define SFML_GLXCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/Window/Unix/GlxExtensions.hpp>
+#include <X11/Xlib.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (GLX) implementation of OpenGL contexts
+///
+////////////////////////////////////////////////////////////
+class GlxContext : public GlContext
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new default context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~GlxContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \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 Activate the context as the current target for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Select the best GLX visual for a given set of settings
+ ///
+ /// \param display X display
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Requested context settings
+ ///
+ /// \return The best visual
+ ///
+ ////////////////////////////////////////////////////////////
+ static XVisualInfo selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the context visual settings from XVisualInfo
+ ///
+ /// \param visualInfo XVisualInfo to update settings from
+ ///
+ ////////////////////////////////////////////////////////////
+ void updateSettingsFromVisualInfo(XVisualInfo* visualInfo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the context visual settings from the window
+ ///
+ ////////////////////////////////////////////////////////////
+ void updateSettingsFromWindow();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context's drawing surface
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ void createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context's drawing surface from an existing window
+ ///
+ /// \param window Window ID of the owning window
+ ///
+ ////////////////////////////////////////////////////////////
+ void createSurface(::Window window);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(GlxContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Display* m_display; ///< Connection to the X server
+ ::Window m_window; ///< Window to which the context is attached
+ GLXContext m_context; ///< OpenGL context
+ GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created
+ bool m_ownsWindow; ///< Do we own the window associated to the context?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_GLXCONTEXT_HPP
diff --git a/src/SFML/Window/Unix/GlxExtensions.cpp b/src/SFML/Window/Unix/GlxExtensions.cpp
new file mode 100644
index 0000000..cfc35b2
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxExtensions.cpp
@@ -0,0 +1,218 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/GlxExtensions.hpp>
+#include <SFML/Window/Context.hpp>
+#include <cstdlib>
+#include <cstring>
+#include <cstddef>
+#include <string>
+
+static sf::GlFunctionPointer IntGetProcAddress(const char* name)
+{
+ return sf::Context::getFunction(name);
+}
+
+int sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED;
+int sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED;
+int sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED;
+int sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED;
+int sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED;
+int sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED;
+int sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED;
+int sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED;
+int sfglx_ext_ARB_create_context_profile = sfglx_LOAD_FAILED;
+
+void (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalEXT)(Display*, GLXDrawable, int) = NULL;
+
+static int Load_EXT_swap_control(void)
+{
+ int numFailed = 0;
+ sf_ptrc_glXSwapIntervalEXT = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, int)>(IntGetProcAddress("glXSwapIntervalEXT"));
+ if (!sf_ptrc_glXSwapIntervalEXT)
+ numFailed++;
+ return numFailed;
+}
+
+int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalMESA)(int) = NULL;
+
+static int Load_MESA_swap_control(void)
+{
+ int numFailed = 0;
+ sf_ptrc_glXSwapIntervalMESA = reinterpret_cast<int (CODEGEN_FUNCPTR*)(int)>(IntGetProcAddress("glXSwapIntervalMESA"));
+ if (!sf_ptrc_glXSwapIntervalMESA)
+ numFailed++;
+ return numFailed;
+}
+
+int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalSGI)(int) = NULL;
+
+static int Load_SGI_swap_control(void)
+{
+ int numFailed = 0;
+ sf_ptrc_glXSwapIntervalSGI = reinterpret_cast<int (CODEGEN_FUNCPTR *)(int)>(IntGetProcAddress("glXSwapIntervalSGI"));
+ if (!sf_ptrc_glXSwapIntervalSGI)
+ numFailed++;
+ return numFailed;
+}
+
+GLXPbufferSGIX (CODEGEN_FUNCPTR *sf_ptrc_glXCreateGLXPbufferSGIX)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*) = NULL;
+void (CODEGEN_FUNCPTR *sf_ptrc_glXDestroyGLXPbufferSGIX)(Display*, GLXPbufferSGIX) = NULL;
+void (CODEGEN_FUNCPTR *sf_ptrc_glXGetSelectedEventSGIX)(Display*, GLXDrawable, unsigned long*) = NULL;
+int (CODEGEN_FUNCPTR *sf_ptrc_glXQueryGLXPbufferSGIX)(Display*, GLXPbufferSGIX, int, unsigned int*) = NULL;
+void (CODEGEN_FUNCPTR *sf_ptrc_glXSelectEventSGIX)(Display*, GLXDrawable, unsigned long) = NULL;
+
+static int Load_SGIX_pbuffer(void)
+{
+ int numFailed = 0;
+ sf_ptrc_glXCreateGLXPbufferSGIX = reinterpret_cast<GLXPbufferSGIX (CODEGEN_FUNCPTR*)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*)>(IntGetProcAddress("glXCreateGLXPbufferSGIX"));
+ if (!sf_ptrc_glXCreateGLXPbufferSGIX)
+ numFailed++;
+ sf_ptrc_glXDestroyGLXPbufferSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXPbufferSGIX)>(IntGetProcAddress("glXDestroyGLXPbufferSGIX"));
+ if (!sf_ptrc_glXDestroyGLXPbufferSGIX)
+ numFailed++;
+ sf_ptrc_glXGetSelectedEventSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, unsigned long*)>(IntGetProcAddress("glXGetSelectedEventSGIX"));
+ if (!sf_ptrc_glXGetSelectedEventSGIX)
+ numFailed++;
+ sf_ptrc_glXQueryGLXPbufferSGIX = reinterpret_cast<int (CODEGEN_FUNCPTR*)(Display*, GLXPbufferSGIX, int, unsigned int*)>(IntGetProcAddress("glXQueryGLXPbufferSGIX"));
+ if (!sf_ptrc_glXQueryGLXPbufferSGIX)
+ numFailed++;
+ sf_ptrc_glXSelectEventSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, unsigned long)>(IntGetProcAddress("glXSelectEventSGIX"));
+ if (!sf_ptrc_glXSelectEventSGIX)
+ numFailed++;
+ return numFailed;
+}
+
+GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*) = NULL;
+
+static int Load_ARB_create_context(void)
+{
+ int numFailed = 0;
+ sf_ptrc_glXCreateContextAttribsARB = reinterpret_cast<GLXContext (CODEGEN_FUNCPTR*)(Display*, GLXFBConfig, GLXContext, Bool, const int*)>(IntGetProcAddress("glXCreateContextAttribsARB"));
+ if (!sf_ptrc_glXCreateContextAttribsARB)
+ numFailed++;
+ return numFailed;
+}
+
+typedef int (*PFN_LOADFUNCPOINTERS)(void);
+typedef struct sfglx_StrToExtMap_s
+{
+ const char* extensionName;
+ int* extensionVariable;
+ PFN_LOADFUNCPOINTERS LoadExtension;
+} sfglx_StrToExtMap;
+
+static sfglx_StrToExtMap ExtensionMap[9] = {
+ {"GLX_EXT_swap_control", &sfglx_ext_EXT_swap_control, Load_EXT_swap_control},
+ {"GLX_MESA_swap_control", &sfglx_ext_MESA_swap_control, Load_MESA_swap_control},
+ {"GLX_SGI_swap_control", &sfglx_ext_SGI_swap_control, Load_SGI_swap_control},
+ {"GLX_EXT_framebuffer_sRGB", &sfglx_ext_EXT_framebuffer_sRGB, NULL},
+ {"GLX_ARB_framebuffer_sRGB", &sfglx_ext_ARB_framebuffer_sRGB, NULL},
+ {"GLX_ARB_multisample", &sfglx_ext_ARB_multisample, NULL},
+ {"GLX_SGIX_pbuffer", &sfglx_ext_SGIX_pbuffer, Load_SGIX_pbuffer},
+ {"GLX_ARB_create_context", &sfglx_ext_ARB_create_context, Load_ARB_create_context},
+ {"GLX_ARB_create_context_profile", &sfglx_ext_ARB_create_context_profile, NULL}
+};
+
+static int g_extensionMapSize = 9;
+
+
+static sfglx_StrToExtMap* FindExtEntry(const char* extensionName)
+{
+ sfglx_StrToExtMap* currLoc = ExtensionMap;
+ for (int loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc)
+ {
+ if (std::strcmp(extensionName, currLoc->extensionName) == 0)
+ return currLoc;
+ }
+
+ return NULL;
+}
+
+
+static void ClearExtensionVars(void)
+{
+ sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED;
+ sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED;
+ sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED;
+ sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED;
+ sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED;
+ sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED;
+ sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED;
+ sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED;
+ sfglx_ext_ARB_create_context_profile = sfglx_LOAD_FAILED;
+}
+
+
+static void LoadExtByName(const char* extensionName)
+{
+ sfglx_StrToExtMap* entry = NULL;
+ entry = FindExtEntry(extensionName);
+ if (entry)
+ {
+ if (entry->LoadExtension)
+ {
+ int numFailed = entry->LoadExtension();
+ if (numFailed == 0)
+ {
+ *(entry->extensionVariable) = sfglx_LOAD_SUCCEEDED;
+ }
+ else
+ {
+ *(entry->extensionVariable) = sfglx_LOAD_SUCCEEDED + numFailed;
+ }
+ }
+ else
+ {
+ *(entry->extensionVariable) = sfglx_LOAD_SUCCEEDED;
+ }
+ }
+}
+
+
+static void ProcExtsFromExtString(const char* strExtList)
+{
+ do
+ {
+ const char* begin = strExtList;
+
+ while ((*strExtList != ' ') && *strExtList)
+ strExtList++;
+
+ LoadExtByName(std::string(begin, strExtList).c_str());
+ } while (*strExtList++);
+}
+
+
+int sfglx_LoadFunctions(Display* display, int screen)
+{
+ ClearExtensionVars();
+
+
+ ProcExtsFromExtString(reinterpret_cast<const char*>(glXQueryExtensionsString(display, screen)));
+ return sfglx_LOAD_SUCCEEDED;
+}
diff --git a/src/SFML/Window/Unix/GlxExtensions.hpp b/src/SFML/Window/Unix/GlxExtensions.hpp
new file mode 100644
index 0000000..fb2c7da
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxExtensions.hpp
@@ -0,0 +1,251 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP
+#define SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP
+
+#if defined(__glxext_h_) || defined(__glx_glxext_h_)
+#error Attempt to include glx_exts after including glxext.h
+#endif
+
+#define __glxext_h_
+#define __glx_glxext_h_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/glx.h>
+#ifdef CODEGEN_FUNCPTR
+#undef CODEGEN_FUNCPTR
+#endif // CODEGEN_FUNCPTR
+#define CODEGEN_FUNCPTR
+
+#ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+#define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+#define GLvoid void
+
+#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+#ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+#define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+#ifndef GLEXT_64_TYPES_DEFINED
+// This code block is duplicated in glext.h, so must be protected
+#define GLEXT_64_TYPES_DEFINED
+// Define int32_t, int64_t, and uint64_t types for UST/MSC
+// (as used in the GLX_OML_sync_control extension).
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__) || defined(__digital__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif // __arch64__
+#endif // __STDC__
+#elif defined( __VMS ) || defined(__sgi)
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+// Fallback if nothing above works
+#include <inttypes.h>
+#endif
+#endif
+ typedef struct __GLXFBConfigRec *GLXFBConfig;
+ typedef XID GLXContextID;
+ typedef struct __GLXcontextRec *GLXContext;
+ typedef XID GLXPixmap;
+ typedef XID GLXDrawable;
+ typedef XID GLXPbuffer;
+ typedef void (APIENTRY *__GLXextFuncPtr)(void);
+ typedef XID GLXVideoCaptureDeviceNV;
+ typedef unsigned int GLXVideoDeviceNV;
+ typedef XID GLXVideoSourceSGIX;
+ typedef struct __GLXFBConfigRec *GLXFBConfigSGIX;
+ typedef XID GLXPbufferSGIX;
+ typedef struct {
+ char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]
+ int networkId;
+} GLXHyperpipeNetworkSGIX;
+ typedef struct {
+ char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]
+ int channel;
+ unsigned int participationType;
+ int timeSlice;
+} GLXHyperpipeConfigSGIX;
+ typedef struct {
+ char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]
+ int srcXOrigin, srcYOrigin, srcWidth, srcHeight;
+ int destXOrigin, destYOrigin, destWidth, destHeight;
+} GLXPipeRect;
+ typedef struct {
+ char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]
+ int XOrigin, YOrigin, maxHeight, maxWidth;
+} GLXPipeRectLimits;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+extern int sfglx_ext_EXT_swap_control;
+extern int sfglx_ext_MESA_swap_control;
+extern int sfglx_ext_SGI_swap_control;
+extern int sfglx_ext_EXT_framebuffer_sRGB;
+extern int sfglx_ext_ARB_framebuffer_sRGB;
+extern int sfglx_ext_ARB_multisample;
+extern int sfglx_ext_SGIX_pbuffer;
+extern int sfglx_ext_ARB_create_context;
+extern int sfglx_ext_ARB_create_context_profile;
+
+#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
+#define GLX_SWAP_INTERVAL_EXT 0x20F1
+
+#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
+
+#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
+
+#define GLX_SAMPLES_ARB 100001
+#define GLX_SAMPLE_BUFFERS_ARB 100000
+
+#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080
+#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010
+#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004
+#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008
+#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000
+#define GLX_DAMAGED_SGIX 0x8020
+#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020
+#define GLX_EVENT_MASK_SGIX 0x801F
+#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001
+#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002
+#define GLX_HEIGHT_SGIX 0x801E
+#define GLX_LARGEST_PBUFFER_SGIX 0x801C
+#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017
+#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018
+#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016
+#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A
+#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019
+#define GLX_PBUFFER_BIT_SGIX 0x00000004
+#define GLX_PBUFFER_SGIX 0x8023
+#define GLX_PRESERVED_CONTENTS_SGIX 0x801B
+#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100
+#define GLX_SAVED_SGIX 0x8021
+#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040
+#define GLX_WIDTH_SGIX 0x801D
+#define GLX_WINDOW_SGIX 0x8022
+
+#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
+#define GLX_CONTEXT_FLAGS_ARB 0x2094
+#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
+
+#ifndef GLX_EXT_swap_control
+#define GLX_EXT_swap_control 1
+extern void (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalEXT)(Display *, GLXDrawable, int);
+#define glXSwapIntervalEXT sf_ptrc_glXSwapIntervalEXT
+#endif // GLX_EXT_swap_control
+
+// Declare entry point even if GLX header already provides glXSwapIntervalMESA
+// We won't make use of an alias here
+extern int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalMESA)(int);
+
+#ifndef GLX_SGI_swap_control
+#define GLX_SGI_swap_control 1
+extern int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalSGI)(int);
+#define glXSwapIntervalSGI sf_ptrc_glXSwapIntervalSGI
+#endif // GLX_SGI_swap_control
+
+#ifndef GLX_SGIX_pbuffer
+#define GLX_SGIX_pbuffer 1
+extern GLXPbufferSGIX (CODEGEN_FUNCPTR *sf_ptrc_glXCreateGLXPbufferSGIX)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*);
+#define glXCreateGLXPbufferSGIX sf_ptrc_glXCreateGLXPbufferSGIX
+extern void (CODEGEN_FUNCPTR *sf_ptrc_glXDestroyGLXPbufferSGIX)(Display*, GLXPbufferSGIX);
+#define glXDestroyGLXPbufferSGIX sf_ptrc_glXDestroyGLXPbufferSGIX
+extern void (CODEGEN_FUNCPTR *sf_ptrc_glXGetSelectedEventSGIX)(Display*, GLXDrawable, unsigned long*);
+#define glXGetSelectedEventSGIX sf_ptrc_glXGetSelectedEventSGIX
+extern int (CODEGEN_FUNCPTR *sf_ptrc_glXQueryGLXPbufferSGIX)(Display*, GLXPbufferSGIX, int, unsigned int*);
+#define glXQueryGLXPbufferSGIX sf_ptrc_glXQueryGLXPbufferSGIX
+extern void (CODEGEN_FUNCPTR *sf_ptrc_glXSelectEventSGIX)(Display*, GLXDrawable, unsigned long);
+#define glXSelectEventSGIX sf_ptrc_glXSelectEventSGIX
+#endif // GLX_SGIX_pbuffer
+
+#ifndef GLX_ARB_create_context
+#define GLX_ARB_create_context 1
+extern GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+#define glXCreateContextAttribsARB sf_ptrc_glXCreateContextAttribsARB
+#endif // GLX_ARB_create_context
+
+
+enum sfglx_LoadStatus
+{
+ sfglx_LOAD_FAILED = 0,
+ sfglx_LOAD_SUCCEEDED = 1
+};
+
+int sfglx_LoadFunctions(Display *display, int screen);
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP
diff --git a/src/SFML/Window/Unix/GlxExtensions.txt b/src/SFML/Window/Unix/GlxExtensions.txt
new file mode 100644
index 0000000..9c8a641
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxExtensions.txt
@@ -0,0 +1,14 @@
+// Created with:
+// https://bitbucket.org/KhronosGroup/glloadgen
+// Commit d143d66ac90d538ed06f806188714861b8e8e2f9
+// lua LoadGen.lua -style=pointer_c -spec=glX -indent=space -prefix=sf -extfile=GlxExtensions.txt GlxExtensions
+
+EXT_swap_control
+// MESA_swap_control
+SGI_swap_control
+EXT_framebuffer_sRGB
+ARB_framebuffer_sRGB
+GLX_ARB_multisample
+GLX_SGIX_pbuffer
+GLX_ARB_create_context
+GLX_ARB_create_context_profile
diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp
new file mode 100644
index 0000000..b404dd5
--- /dev/null
+++ b/src/SFML/Window/Unix/InputImpl.cpp
@@ -0,0 +1,329 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Window.hpp> // important to be included first (conflict with None)
+#include <SFML/Window/Unix/InputImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/System/Err.hpp>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ // Get the corresponding X11 keysym
+ KeySym keysym = 0;
+ switch (key)
+ {
+ case Keyboard::LShift: keysym = XK_Shift_L; break;
+ case Keyboard::RShift: keysym = XK_Shift_R; break;
+ case Keyboard::LControl: keysym = XK_Control_L; break;
+ case Keyboard::RControl: keysym = XK_Control_R; break;
+ case Keyboard::LAlt: keysym = XK_Alt_L; break;
+ case Keyboard::RAlt: keysym = XK_Alt_R; break;
+ case Keyboard::LSystem: keysym = XK_Super_L; break;
+ case Keyboard::RSystem: keysym = XK_Super_R; break;
+ case Keyboard::Menu: keysym = XK_Menu; break;
+ case Keyboard::Escape: keysym = XK_Escape; break;
+ case Keyboard::Semicolon: keysym = XK_semicolon; break;
+ case Keyboard::Slash: keysym = XK_slash; break;
+ case Keyboard::Equal: keysym = XK_equal; break;
+ case Keyboard::Hyphen: keysym = XK_minus; break;
+ case Keyboard::LBracket: keysym = XK_bracketleft; break;
+ case Keyboard::RBracket: keysym = XK_bracketright; break;
+ case Keyboard::Comma: keysym = XK_comma; break;
+ case Keyboard::Period: keysym = XK_period; break;
+ case Keyboard::Quote: keysym = XK_apostrophe; break;
+ case Keyboard::Backslash: keysym = XK_backslash; break;
+ case Keyboard::Tilde: keysym = XK_grave; break;
+ case Keyboard::Space: keysym = XK_space; break;
+ case Keyboard::Enter: keysym = XK_Return; break;
+ case Keyboard::Backspace: keysym = XK_BackSpace; break;
+ case Keyboard::Tab: keysym = XK_Tab; break;
+ case Keyboard::PageUp: keysym = XK_Prior; break;
+ case Keyboard::PageDown: keysym = XK_Next; break;
+ case Keyboard::End: keysym = XK_End; break;
+ case Keyboard::Home: keysym = XK_Home; break;
+ case Keyboard::Insert: keysym = XK_Insert; break;
+ case Keyboard::Delete: keysym = XK_Delete; break;
+ case Keyboard::Add: keysym = XK_KP_Add; break;
+ case Keyboard::Subtract: keysym = XK_KP_Subtract; break;
+ case Keyboard::Multiply: keysym = XK_KP_Multiply; break;
+ case Keyboard::Divide: keysym = XK_KP_Divide; break;
+ case Keyboard::Pause: keysym = XK_Pause; break;
+ case Keyboard::F1: keysym = XK_F1; break;
+ case Keyboard::F2: keysym = XK_F2; break;
+ case Keyboard::F3: keysym = XK_F3; break;
+ case Keyboard::F4: keysym = XK_F4; break;
+ case Keyboard::F5: keysym = XK_F5; break;
+ case Keyboard::F6: keysym = XK_F6; break;
+ case Keyboard::F7: keysym = XK_F7; break;
+ case Keyboard::F8: keysym = XK_F8; break;
+ case Keyboard::F9: keysym = XK_F9; break;
+ case Keyboard::F10: keysym = XK_F10; break;
+ case Keyboard::F11: keysym = XK_F11; break;
+ case Keyboard::F12: keysym = XK_F12; break;
+ case Keyboard::F13: keysym = XK_F13; break;
+ case Keyboard::F14: keysym = XK_F14; break;
+ case Keyboard::F15: keysym = XK_F15; break;
+ case Keyboard::Left: keysym = XK_Left; break;
+ case Keyboard::Right: keysym = XK_Right; break;
+ case Keyboard::Up: keysym = XK_Up; break;
+ case Keyboard::Down: keysym = XK_Down; break;
+ case Keyboard::Numpad0: keysym = XK_KP_Insert; break;
+ case Keyboard::Numpad1: keysym = XK_KP_End; break;
+ case Keyboard::Numpad2: keysym = XK_KP_Down; break;
+ case Keyboard::Numpad3: keysym = XK_KP_Page_Down; break;
+ case Keyboard::Numpad4: keysym = XK_KP_Left; break;
+ case Keyboard::Numpad5: keysym = XK_KP_Begin; break;
+ case Keyboard::Numpad6: keysym = XK_KP_Right; break;
+ case Keyboard::Numpad7: keysym = XK_KP_Home; break;
+ case Keyboard::Numpad8: keysym = XK_KP_Up; break;
+ case Keyboard::Numpad9: keysym = XK_KP_Page_Up; break;
+ case Keyboard::A: keysym = XK_a; break;
+ case Keyboard::B: keysym = XK_b; break;
+ case Keyboard::C: keysym = XK_c; break;
+ case Keyboard::D: keysym = XK_d; break;
+ case Keyboard::E: keysym = XK_e; break;
+ case Keyboard::F: keysym = XK_f; break;
+ case Keyboard::G: keysym = XK_g; break;
+ case Keyboard::H: keysym = XK_h; break;
+ case Keyboard::I: keysym = XK_i; break;
+ case Keyboard::J: keysym = XK_j; break;
+ case Keyboard::K: keysym = XK_k; break;
+ case Keyboard::L: keysym = XK_l; break;
+ case Keyboard::M: keysym = XK_m; break;
+ case Keyboard::N: keysym = XK_n; break;
+ case Keyboard::O: keysym = XK_o; break;
+ case Keyboard::P: keysym = XK_p; break;
+ case Keyboard::Q: keysym = XK_q; break;
+ case Keyboard::R: keysym = XK_r; break;
+ case Keyboard::S: keysym = XK_s; break;
+ case Keyboard::T: keysym = XK_t; break;
+ case Keyboard::U: keysym = XK_u; break;
+ case Keyboard::V: keysym = XK_v; break;
+ case Keyboard::W: keysym = XK_w; break;
+ case Keyboard::X: keysym = XK_x; break;
+ case Keyboard::Y: keysym = XK_y; break;
+ case Keyboard::Z: keysym = XK_z; break;
+ case Keyboard::Num0: keysym = XK_0; break;
+ case Keyboard::Num1: keysym = XK_1; break;
+ case Keyboard::Num2: keysym = XK_2; break;
+ case Keyboard::Num3: keysym = XK_3; break;
+ case Keyboard::Num4: keysym = XK_4; break;
+ case Keyboard::Num5: keysym = XK_5; break;
+ case Keyboard::Num6: keysym = XK_6; break;
+ case Keyboard::Num7: keysym = XK_7; break;
+ case Keyboard::Num8: keysym = XK_8; break;
+ case Keyboard::Num9: keysym = XK_9; break;
+ default: keysym = 0; break;
+ }
+
+ // Sanity checks
+ if (key < 0 || key >= sf::Keyboard::KeyCount)
+ return false;
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // Convert to keycode
+ KeyCode keycode = XKeysymToKeycode(display, keysym);
+ if (keycode != 0)
+ {
+ // Get the whole keyboard state
+ char keys[32];
+ XQueryKeymap(display, keys);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ // Check our keycode
+ return (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
+ }
+ else
+ {
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int wx, wy;
+ int gx, gy;
+
+ unsigned int buttons = 0;
+ XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ switch (button)
+ {
+ case Mouse::Left: return buttons & Button1Mask;
+ case Mouse::Right: return buttons & Button3Mask;
+ case Mouse::Middle: return buttons & Button2Mask;
+ case Mouse::XButton1: return false; // not supported by X
+ case Mouse::XButton2: return false; // not supported by X
+ default: return false;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int x, y;
+ unsigned int buttons;
+
+ int gx = 0;
+ int gy = 0;
+ XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return Vector2i(gx, gy);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int gx, gy;
+ unsigned int buttons;
+
+ int x = 0;
+ int y = 0;
+ XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return Vector2i(x, y);
+ }
+ else
+ {
+ return Vector2i();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y);
+ XFlush(display);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y);
+ XFlush(display);
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int /*finger*/)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*relativeTo*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/InputImpl.hpp b/src/SFML/Window/Unix/InputImpl.hpp
new file mode 100644
index 0000000..88dcc91
--- /dev/null
+++ b/src/SFML/Window/Unix/InputImpl.hpp
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_INPUTIMPLX11_HPP
+#define SFML_INPUTIMPLX11_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (X11) implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(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.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 isTouchDown(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 getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLX11_HPP
diff --git a/src/SFML/Window/Unix/JoystickImpl.cpp b/src/SFML/Window/Unix/JoystickImpl.cpp
new file mode 100644
index 0000000..56c7234
--- /dev/null
+++ b/src/SFML/Window/Unix/JoystickImpl.cpp
@@ -0,0 +1,708 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <linux/joystick.h>
+#include <libudev.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <vector>
+#include <string>
+#include <cstring>
+
+namespace
+{
+ udev* udevContext = 0;
+ udev_monitor* udevMonitor = 0;
+
+ struct JoystickRecord
+ {
+ std::string deviceNode;
+ std::string systemPath;
+ bool plugged;
+ };
+
+ typedef std::vector<JoystickRecord> JoystickList;
+ JoystickList joystickList;
+
+ bool isJoystick(udev_device* udevDevice)
+ {
+ // If anything goes wrong, we go safe and return true
+
+ // No device to check, assume not a joystick
+ if (!udevDevice)
+ return false;
+
+ const char* devnode = udev_device_get_devnode(udevDevice);
+
+ // We only consider devices with a device node
+ if (!devnode)
+ return false;
+
+ // SFML doesn't support evdev yet, so make sure we only handle /js nodes
+ if (!std::strstr(devnode, "/js"))
+ return false;
+
+ // Check if this device is a joystick
+ if (udev_device_get_property_value(udevDevice, "ID_INPUT_JOYSTICK"))
+ return true;
+
+ // Check if this device is something that isn't a joystick
+ // We do this because the absence of any ID_INPUT_ property doesn't
+ // necessarily mean that the device isn't a joystick, whereas the
+ // presence of any ID_INPUT_ property that isn't ID_INPUT_JOYSTICK does
+ if (udev_device_get_property_value(udevDevice, "ID_INPUT_ACCELEROMETER") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_KEY") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_KEYBOARD") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_MOUSE") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_TABLET") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_TOUCHPAD") ||
+ udev_device_get_property_value(udevDevice, "ID_INPUT_TOUCHSCREEN"))
+ return false;
+
+ // On some platforms (older udev), ID_INPUT_ properties are not present, instead
+ // the system makes use of the ID_CLASS property to identify the device class
+ const char* idClass = udev_device_get_property_value(udevDevice, "ID_CLASS");
+
+ if (idClass)
+ {
+ // Check if the device class matches joystick
+ if (std::strstr(idClass, "joystick"))
+ return true;
+
+ // Check if the device class matches something that isn't a joystick
+ // Rationale same as above
+ if (std::strstr(idClass, "accelerometer") ||
+ std::strstr(idClass, "key") ||
+ std::strstr(idClass, "keyboard") ||
+ std::strstr(idClass, "mouse") ||
+ std::strstr(idClass, "tablet") ||
+ std::strstr(idClass, "touchpad") ||
+ std::strstr(idClass, "touchscreen"))
+ return false;
+ }
+
+ // At this point, assume it is a joystick
+ return true;
+ }
+
+ void updatePluggedList(udev_device* udevDevice = NULL)
+ {
+ if (udevDevice)
+ {
+ const char* action = udev_device_get_action(udevDevice);
+
+ if (action)
+ {
+ if (isJoystick(udevDevice))
+ {
+ // Since isJoystick returned true, this has to succeed
+ const char* devnode = udev_device_get_devnode(udevDevice);
+
+ JoystickList::iterator record;
+
+ for (record = joystickList.begin(); record != joystickList.end(); ++record)
+ {
+ if (record->deviceNode == devnode)
+ {
+ if (std::strstr(action, "add"))
+ {
+ // The system path might have changed so update it
+ const char* syspath = udev_device_get_syspath(udevDevice);
+
+ record->plugged = true;
+ record->systemPath = syspath ? syspath : "";
+ break;
+ }
+ else if (std::strstr(action, "remove"))
+ {
+ record->plugged = false;
+ break;
+ }
+ }
+ }
+
+ if (record == joystickList.end())
+ {
+ if (std::strstr(action, "add"))
+ {
+ // If not mapped before and it got added, map it now
+ const char* syspath = udev_device_get_syspath(udevDevice);
+
+ JoystickRecord record;
+ record.deviceNode = devnode;
+ record.systemPath = syspath ? syspath : "";
+ record.plugged = true;
+
+ joystickList.push_back(record);
+ }
+ else if (std::strstr(action, "remove"))
+ {
+ // Not mapped during the initial scan, and removed (shouldn't happen)
+ sf::err() << "Trying to disconnect joystick that wasn't connected" << std::endl;
+ }
+ }
+ }
+
+ return;
+ }
+
+ // Do a full rescan if there was no action just to be sure
+ }
+
+ // Reset the plugged status of each mapping since we are doing a full rescan
+ for (JoystickList::iterator record = joystickList.begin(); record != joystickList.end(); ++record)
+ record->plugged = false;
+
+ udev_enumerate* udevEnumerator = udev_enumerate_new(udevContext);
+
+ if (!udevEnumerator)
+ {
+ sf::err() << "Error while creating udev enumerator" << std::endl;
+ return;
+ }
+
+ int result = 0;
+
+ result = udev_enumerate_add_match_subsystem(udevEnumerator, "input");
+
+ if (result < 0)
+ {
+ sf::err() << "Error while adding udev enumerator match" << std::endl;
+ return;
+ }
+
+ result = udev_enumerate_scan_devices(udevEnumerator);
+
+ if (result < 0)
+ {
+ sf::err() << "Error while enumerating udev devices" << std::endl;
+ return;
+ }
+
+ udev_list_entry* devices = udev_enumerate_get_list_entry(udevEnumerator);
+ udev_list_entry* device;
+
+ udev_list_entry_foreach(device, devices) {
+ const char* syspath = udev_list_entry_get_name(device);
+ udev_device* udevDevice = udev_device_new_from_syspath(udevContext, syspath);
+
+ if (udevDevice && isJoystick(udevDevice))
+ {
+ // Since isJoystick returned true, this has to succeed
+ const char* devnode = udev_device_get_devnode(udevDevice);
+
+ JoystickList::iterator record;
+
+ // Check if the device node has been mapped before
+ for (record = joystickList.begin(); record != joystickList.end(); ++record)
+ {
+ if (record->deviceNode == devnode)
+ {
+ record->plugged = true;
+ break;
+ }
+ }
+
+ // If not mapped before, map it now
+ if (record == joystickList.end())
+ {
+ JoystickRecord record;
+ record.deviceNode = devnode;
+ record.systemPath = syspath;
+ record.plugged = true;
+
+ joystickList.push_back(record);
+ }
+ }
+
+ udev_device_unref(udevDevice);
+ }
+
+ udev_enumerate_unref(udevEnumerator);
+ }
+
+ bool hasMonitorEvent()
+ {
+ // This will not fail since we make sure udevMonitor is valid
+ int monitorFd = udev_monitor_get_fd(udevMonitor);
+
+ fd_set descriptorSet;
+ FD_ZERO(&descriptorSet);
+ FD_SET(monitorFd, &descriptorSet);
+ timeval timeout = {0, 0};
+
+ return (select(monitorFd + 1, &descriptorSet, NULL, NULL, &timeout) > 0) &&
+ FD_ISSET(monitorFd, &descriptorSet);
+ }
+
+ // Get a property value from a udev device
+ const char* getUdevAttribute(udev_device* udevDevice, const std::string& attributeName)
+ {
+ return udev_device_get_property_value(udevDevice, attributeName.c_str());
+ }
+
+ // Get a system attribute from a USB device
+ const char* getUsbAttribute(udev_device* udevDevice, const std::string& attributeName)
+ {
+ udev_device* udevDeviceParent = udev_device_get_parent_with_subsystem_devtype(udevDevice, "usb", "usb_device");
+
+ if (!udevDeviceParent)
+ return NULL;
+
+ return udev_device_get_sysattr_value(udevDeviceParent, attributeName.c_str());
+ }
+
+ // Get a USB attribute for a joystick as an unsigned int
+ unsigned int getUsbAttributeUint(udev_device* udevDevice, const std::string& attributeName)
+ {
+ if (!udevDevice)
+ return 0;
+
+ const char* attribute = getUsbAttribute(udevDevice, attributeName);
+ unsigned int value = 0;
+
+ if (attribute)
+ value = static_cast<unsigned int>(std::strtoul(attribute, NULL, 16));
+
+ return value;
+ }
+
+ // Get a udev property value for a joystick as an unsigned int
+ unsigned int getUdevAttributeUint(udev_device* udevDevice, const std::string& attributeName)
+ {
+ if (!udevDevice)
+ return 0;
+
+ const char* attribute = getUdevAttribute(udevDevice, attributeName);
+ unsigned int value = 0;
+
+ if (attribute)
+ value = static_cast<unsigned int>(std::strtoul(attribute, NULL, 16));
+
+ return value;
+ }
+
+ // Get the joystick vendor id
+ unsigned int getJoystickVendorId(unsigned int index)
+ {
+ if (!udevContext)
+ {
+ sf::err() << "Failed to get vendor ID of joystick " << joystickList[index].deviceNode << std::endl;
+ return 0;
+ }
+
+ udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str());
+
+ if (!udevDevice)
+ {
+ sf::err() << "Failed to get vendor ID of joystick " << joystickList[index].deviceNode << std::endl;
+ return 0;
+ }
+
+ unsigned int id = 0;
+
+ // First try using udev
+ id = getUdevAttributeUint(udevDevice, "ID_VENDOR_ID");
+
+ if (id)
+ {
+ udev_device_unref(udevDevice);
+ return id;
+ }
+
+ // Fall back to using USB attribute
+ id = getUsbAttributeUint(udevDevice, "idVendor");
+
+ udev_device_unref(udevDevice);
+
+ if (id)
+ return id;
+
+ sf::err() << "Failed to get vendor ID of joystick " << joystickList[index].deviceNode << std::endl;
+
+ return 0;
+ }
+
+ // Get the joystick product id
+ unsigned int getJoystickProductId(unsigned int index)
+ {
+ if (!udevContext)
+ {
+ sf::err() << "Failed to get product ID of joystick " << joystickList[index].deviceNode << std::endl;
+ return 0;
+ }
+
+ udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str());
+
+ if (!udevDevice)
+ {
+ sf::err() << "Failed to get product ID of joystick " << joystickList[index].deviceNode << std::endl;
+ return 0;
+ }
+
+ unsigned int id = 0;
+
+ // First try using udev
+ id = getUdevAttributeUint(udevDevice, "ID_MODEL_ID");
+
+ if (id)
+ {
+ udev_device_unref(udevDevice);
+ return id;
+ }
+
+ // Fall back to using USB attribute
+ id = getUsbAttributeUint(udevDevice, "idProduct");
+
+ udev_device_unref(udevDevice);
+
+ if (id)
+ return id;
+
+ sf::err() << "Failed to get product ID of joystick " << joystickList[index].deviceNode << std::endl;
+
+ return 0;
+ }
+
+ // Get the joystick name
+ std::string getJoystickName(unsigned int index)
+ {
+ std::string devnode = joystickList[index].deviceNode;
+
+ // First try using ioctl with JSIOCGNAME
+ int fd = ::open(devnode.c_str(), O_RDONLY | O_NONBLOCK);
+
+ if (fd >= 0)
+ {
+ // Get the name
+ char name[128];
+ std::memset(name, 0, sizeof(name));
+
+ int result = ioctl(fd, JSIOCGNAME(sizeof(name)), name);
+
+ ::close(fd);
+
+ if (result >= 0)
+ return std::string(name);
+ }
+
+ // Fall back to manual USB chain walk via udev
+ if (udevContext)
+ {
+ udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str());
+
+ if (udevDevice)
+ {
+ const char* product = getUsbAttribute(udevDevice, "product");
+ udev_device_unref(udevDevice);
+
+ if (product)
+ return std::string(product);
+ }
+ }
+
+ sf::err() << "Unable to get name for joystick " << devnode << std::endl;
+
+ return std::string("Unknown Joystick");
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+JoystickImpl::JoystickImpl() :
+m_file(-1)
+{
+ std::fill(m_mapping, m_mapping + ABS_MAX + 1, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ udevContext = udev_new();
+
+ if (!udevContext)
+ {
+ sf::err() << "Failed to create udev context, joystick support not available" << std::endl;
+ return;
+ }
+
+ udevMonitor = udev_monitor_new_from_netlink(udevContext, "udev");
+
+ if (!udevMonitor)
+ {
+ err() << "Failed to create udev monitor, joystick connections and disconnections won't be notified" << std::endl;
+ }
+ else
+ {
+ int error = udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "input", NULL);
+
+ if (error < 0)
+ {
+ err() << "Failed to add udev monitor filter, joystick connections and disconnections won't be notified: " << error << std::endl;
+
+ udev_monitor_unref(udevMonitor);
+ udevMonitor = 0;
+ }
+ else
+ {
+ error = udev_monitor_enable_receiving(udevMonitor);
+
+ if (error < 0)
+ {
+ err() << "Failed to enable udev monitor, joystick connections and disconnections won't be notified: " << error << std::endl;
+
+ udev_monitor_unref(udevMonitor);
+ udevMonitor = 0;
+ }
+ }
+ }
+
+ // Do an initial scan
+ updatePluggedList();
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // Unreference the udev monitor to destroy it
+ if (udevMonitor)
+ {
+ udev_monitor_unref(udevMonitor);
+ udevMonitor = 0;
+ }
+
+ // Unreference the udev context to destroy it
+ if (udevContext)
+ {
+ udev_unref(udevContext);
+ udevContext = 0;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ // See if we can skip scanning if udev monitor is available
+ if (!udevMonitor)
+ {
+ // udev monitor is not available, perform a scan every query
+ updatePluggedList();
+ }
+ else if (hasMonitorEvent())
+ {
+ // Check if new joysticks were added/removed since last update
+ udev_device* udevDevice = udev_monitor_receive_device(udevMonitor);
+
+ // If we can get the specific device, we check that,
+ // otherwise just do a full scan if udevDevice == NULL
+ updatePluggedList(udevDevice);
+
+ if (udevDevice)
+ udev_device_unref(udevDevice);
+ }
+
+ if (index >= joystickList.size())
+ return false;
+
+ // Then check if the joystick is connected
+ return joystickList[index].plugged;
+}
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ if (index >= joystickList.size())
+ return false;
+
+ if (joystickList[index].plugged)
+ {
+ std::string devnode = joystickList[index].deviceNode;
+
+ // Open the joystick's file descriptor (read-only and non-blocking)
+ m_file = ::open(devnode.c_str(), O_RDONLY | O_NONBLOCK);
+ if (m_file >= 0)
+ {
+ // Retrieve the axes mapping
+ ioctl(m_file, JSIOCGAXMAP, m_mapping);
+
+ // Get info
+ m_identification.name = getJoystickName(index);
+
+ if (udevContext)
+ {
+ m_identification.vendorId = getJoystickVendorId(index);
+ m_identification.productId = getJoystickProductId(index);
+ }
+
+ // Reset the joystick state
+ m_state = JoystickState();
+
+ return true;
+ }
+ else
+ {
+ err() << "Failed to open joystick " << devnode << ": " << errno << std::endl;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ ::close(m_file);
+ m_file = -1;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ JoystickCaps caps;
+
+ if (m_file < 0)
+ return caps;
+
+ // Get the number of buttons
+ char buttonCount;
+ ioctl(m_file, JSIOCGBUTTONS, &buttonCount);
+ caps.buttonCount = buttonCount;
+ if (caps.buttonCount > Joystick::ButtonCount)
+ caps.buttonCount = Joystick::ButtonCount;
+
+ // Get the supported axes
+ char axesCount;
+ ioctl(m_file, JSIOCGAXES, &axesCount);
+ for (int i = 0; i < axesCount; ++i)
+ {
+ switch (m_mapping[i])
+ {
+ case ABS_X: caps.axes[Joystick::X] = true; break;
+ case ABS_Y: caps.axes[Joystick::Y] = true; break;
+ case ABS_Z:
+ case ABS_THROTTLE: caps.axes[Joystick::Z] = true; break;
+ case ABS_RZ:
+ case ABS_RUDDER: caps.axes[Joystick::R] = true; break;
+ case ABS_RX: caps.axes[Joystick::U] = true; break;
+ case ABS_RY: caps.axes[Joystick::V] = true; break;
+ case ABS_HAT0X: caps.axes[Joystick::PovX] = true; break;
+ case ABS_HAT0Y: caps.axes[Joystick::PovY] = true; break;
+ default: break;
+ }
+ }
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::JoystickImpl::update()
+{
+ if (m_file < 0)
+ {
+ m_state = JoystickState();
+ return m_state;
+ }
+
+ // pop events from the joystick file
+ js_event joyState;
+ int result = read(m_file, &joyState, sizeof(joyState));
+ while (result > 0)
+ {
+ switch (joyState.type & ~JS_EVENT_INIT)
+ {
+ // An axis was moved
+ case JS_EVENT_AXIS:
+ {
+ float value = joyState.value * 100.f / 32767.f;
+
+ if (joyState.number < ABS_MAX + 1)
+ {
+ switch (m_mapping[joyState.number])
+ {
+ case ABS_X: m_state.axes[Joystick::X] = value; break;
+ case ABS_Y: m_state.axes[Joystick::Y] = value; break;
+ case ABS_Z:
+ case ABS_THROTTLE: m_state.axes[Joystick::Z] = value; break;
+ case ABS_RZ:
+ case ABS_RUDDER: m_state.axes[Joystick::R] = value; break;
+ case ABS_RX: m_state.axes[Joystick::U] = value; break;
+ case ABS_RY: m_state.axes[Joystick::V] = value; break;
+ case ABS_HAT0X: m_state.axes[Joystick::PovX] = value; break;
+ case ABS_HAT0Y: m_state.axes[Joystick::PovY] = value; break;
+ default: break;
+ }
+ }
+ break;
+ }
+
+ // A button was pressed
+ case JS_EVENT_BUTTON:
+ {
+ if (joyState.number < Joystick::ButtonCount)
+ m_state.buttons[joyState.number] = (joyState.value != 0);
+ break;
+ }
+ }
+
+ result = read(m_file, &joyState, sizeof(joyState));
+ }
+
+ // Check the connection state of the joystick
+ // read() returns -1 and errno != EGAIN if it's no longer connected
+ // We need to check the result of read() as well, since errno could
+ // have been previously set by some other function call that failed
+ // result can be either negative or 0 at this point
+ // If result is 0, assume the joystick is still connected
+ // If result is negative, check errno and disconnect if it is not EAGAIN
+ m_state.connected = (!result || (errno == EAGAIN));
+
+ return m_state;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/JoystickImpl.hpp b/src/SFML/Window/Unix/JoystickImpl.hpp
new file mode 100644
index 0000000..f81e744
--- /dev/null
+++ b/src/SFML/Window/Unix/JoystickImpl.hpp
@@ -0,0 +1,131 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKIMPLLINUX_HPP
+#define SFML_JOYSTICKIMPLLINUX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <linux/input.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ int m_file; ///< File descriptor of the joystick
+ char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id)
+ JoystickState m_state; ///< Current state of the joystick
+ sf::Joystick::Identification m_identification; ///< Identification of the joystick
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLLINUX_HPP
diff --git a/src/SFML/Window/Unix/SensorImpl.cpp b/src/SFML/Window/Unix/SensorImpl.cpp
new file mode 100644
index 0000000..3496265
--- /dev/null
+++ b/src/SFML/Window/Unix/SensorImpl.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ // To be implemented
+ return Vector3f(0, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool /*enabled*/)
+{
+ // To be implemented
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/SensorImpl.hpp b/src/SFML/Window/Unix/SensorImpl.hpp
new file mode 100644
index 0000000..2667de3
--- /dev/null
+++ b/src/SFML/Window/Unix/SensorImpl.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPLUNIX_HPP
+#define SFML_SENSORIMPLUNIX_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLUNIX_HPP
diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp
new file mode 100644
index 0000000..288ef3e
--- /dev/null
+++ b/src/SFML/Window/Unix/VideoModeImpl.cpp
@@ -0,0 +1,190 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/System/Err.hpp>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#include <algorithm>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ std::vector<VideoMode> modes;
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+ if (display)
+ {
+ // Retrieve the default screen number
+ int screen = DefaultScreen(display);
+
+ // Check if the XRandR extension is present
+ int version;
+ if (XQueryExtension(display, "RANDR", &version, &version, &version))
+ {
+ // Get the current configuration
+ XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
+ if (config)
+ {
+ // Get the available screen sizes
+ int nbSizes;
+ XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
+ if (sizes && (nbSizes > 0))
+ {
+ // Get the list of supported depths
+ int nbDepths = 0;
+ int* depths = XListDepths(display, screen, &nbDepths);
+ if (depths && (nbDepths > 0))
+ {
+ // Combine depths and sizes to fill the array of supported modes
+ for (int i = 0; i < nbDepths; ++i)
+ {
+ for (int j = 0; j < nbSizes; ++j)
+ {
+ // Convert to VideoMode
+ VideoMode mode(sizes[j].width, sizes[j].height, depths[i]);
+
+ Rotation currentRotation;
+ XRRConfigRotations(config, &currentRotation);
+
+ if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
+ std::swap(mode.width, mode.height);
+
+ // Add it only if it is not already in the array
+ if (std::find(modes.begin(), modes.end(), mode) == modes.end())
+ modes.push_back(mode);
+ }
+ }
+
+ // Free the array of depths
+ XFree(depths);
+ }
+ }
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+ else
+ {
+ // Failed to get the screen configuration
+ err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
+ }
+ }
+ else
+ {
+ // XRandr extension is not supported: we cannot get the video modes
+ err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl;
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+ }
+ else
+ {
+ // We couldn't connect to the X server
+ err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl;
+ }
+
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ VideoMode desktopMode;
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+ if (display)
+ {
+ // Retrieve the default screen number
+ int screen = DefaultScreen(display);
+
+ // Check if the XRandR extension is present
+ int version;
+ if (XQueryExtension(display, "RANDR", &version, &version, &version))
+ {
+ // Get the current configuration
+ XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
+ if (config)
+ {
+ // Get the current video mode
+ Rotation currentRotation;
+ int currentMode = XRRConfigCurrentConfiguration(config, &currentRotation);
+
+ // Get the available screen sizes
+ int nbSizes;
+ XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
+ if (sizes && (nbSizes > 0))
+ {
+ desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen));
+
+ Rotation currentRotation;
+ XRRConfigRotations(config, &currentRotation);
+
+ if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
+ std::swap(desktopMode.width, desktopMode.height);
+ }
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+ else
+ {
+ // Failed to get the screen configuration
+ err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
+ }
+ }
+ else
+ {
+ // XRandr extension is not supported: we cannot get the video modes
+ err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl;
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+ }
+ else
+ {
+ // We couldn't connect to the X server
+ err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl;
+ }
+
+ return desktopMode;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
new file mode 100644
index 0000000..da69750
--- /dev/null
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -0,0 +1,2181 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/WindowImplX11.hpp>
+#include <SFML/Window/Unix/ClipboardImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/Window/Unix/InputImpl.hpp>
+#include <SFML/System/Utf.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <X11/Xlibint.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/Xrandr.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <cstring>
+
+#ifdef SFML_OPENGL_ES
+ #include <SFML/Window/EglContext.hpp>
+ typedef sf::priv::EglContext ContextType;
+#else
+ #include <SFML/Window/Unix/GlxContext.hpp>
+ typedef sf::priv::GlxContext ContextType;
+#endif
+
+////////////////////////////////////////////////////////////
+// Private data
+////////////////////////////////////////////////////////////
+namespace
+{
+ sf::priv::WindowImplX11* fullscreenWindow = NULL;
+ std::vector<sf::priv::WindowImplX11*> allWindows;
+ sf::Mutex allWindowsMutex;
+ sf::String windowManagerName;
+
+ sf::String wmAbsPosGood[] = { "Enlightenment", "FVWM", "i3" };
+
+ static const unsigned long eventMask = FocusChangeMask | ButtonPressMask |
+ ButtonReleaseMask | ButtonMotionMask |
+ PointerMotionMask | KeyPressMask |
+ KeyReleaseMask | StructureNotifyMask |
+ EnterWindowMask | LeaveWindowMask |
+ VisibilityChangeMask | PropertyChangeMask;
+
+ static const unsigned int maxTrialsCount = 5;
+
+ // Predicate we use to find key repeat events in processEvent
+ struct KeyRepeatFinder
+ {
+ KeyRepeatFinder(unsigned int keycode, Time time) : keycode(keycode), time(time) {}
+
+ // Predicate operator that checks event type, keycode and timestamp
+ bool operator()(const XEvent& event)
+ {
+ return ((event.type == KeyPress) && (event.xkey.keycode == keycode) && (event.xkey.time - time < 2));
+ }
+
+ unsigned int keycode;
+ Time time;
+ };
+
+ // Filter the events received by windows (only allow those matching a specific window)
+ Bool checkEvent(::Display*, XEvent* event, XPointer userData)
+ {
+ // Just check if the event matches the window
+ return event->xany.window == reinterpret_cast< ::Window >(userData);
+ }
+
+ // Find the name of the current executable
+ std::string findExecutableName()
+ {
+ // We use /proc/self/cmdline to get the command line
+ // the user used to invoke this instance of the application
+ int file = ::open("/proc/self/cmdline", O_RDONLY | O_NONBLOCK);
+
+ if (file < 0)
+ return "sfml";
+
+ std::vector<char> buffer(256, 0);
+ std::size_t offset = 0;
+ ssize_t result = 0;
+
+ while ((result = read(file, &buffer[offset], 256)) > 0)
+ {
+ buffer.resize(buffer.size() + result, 0);
+ offset += result;
+ }
+
+ ::close(file);
+
+ if (offset)
+ {
+ buffer[offset] = 0;
+
+ // Remove the path to keep the executable name only
+ return basename(&buffer[0]);
+ }
+
+ // Default fallback name
+ return "sfml";
+ }
+
+ // Check if Extended Window Manager Hints are supported
+ bool ewmhSupported()
+ {
+ static bool checked = false;
+ static bool ewmhSupported = false;
+
+ if (checked)
+ return ewmhSupported;
+
+ checked = true;
+
+ Atom netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true);
+ Atom netSupported = sf::priv::getAtom("_NET_SUPPORTED", true);
+
+ if (!netSupportingWmCheck || !netSupported)
+ return false;
+
+ ::Display* display = sf::priv::OpenDisplay();
+
+ Atom actualType;
+ int actualFormat;
+ unsigned long numItems;
+ unsigned long numBytes;
+ unsigned char* data;
+
+ int result = XGetWindowProperty(display,
+ DefaultRootWindow(display),
+ netSupportingWmCheck,
+ 0,
+ 1,
+ False,
+ XA_WINDOW,
+ &actualType,
+ &actualFormat,
+ &numItems,
+ &numBytes,
+ &data);
+
+ if (result != Success || actualType != XA_WINDOW || numItems != 1)
+ {
+ if (result == Success)
+ XFree(data);
+
+ sf::priv::CloseDisplay(display);
+ return false;
+ }
+
+ ::Window rootWindow = *reinterpret_cast< ::Window* >(data);
+
+ XFree(data);
+
+ if (!rootWindow)
+ {
+ sf::priv::CloseDisplay(display);
+ return false;
+ }
+
+ result = XGetWindowProperty(display,
+ rootWindow,
+ netSupportingWmCheck,
+ 0,
+ 1,
+ False,
+ XA_WINDOW,
+ &actualType,
+ &actualFormat,
+ &numItems,
+ &numBytes,
+ &data);
+
+ if (result != Success || actualType != XA_WINDOW || numItems != 1)
+ {
+ if (result == Success)
+ XFree(data);
+
+ sf::priv::CloseDisplay(display);
+ return false;
+ }
+
+ ::Window childWindow = *reinterpret_cast< ::Window* >(data);
+
+ XFree(data);
+
+ if (!childWindow)
+ {
+ sf::priv::CloseDisplay(display);
+ return false;
+ }
+
+ // Conforming window managers should return the same window for both queries
+ if (rootWindow != childWindow)
+ {
+ sf::priv::CloseDisplay(display);
+ return false;
+ }
+
+ ewmhSupported = true;
+
+ // We try to get the name of the window manager
+ // for window manager specific workarounds
+ Atom netWmName = sf::priv::getAtom("_NET_WM_NAME", true);
+
+ if (!netWmName)
+ {
+ sf::priv::CloseDisplay(display);
+ return true;
+ }
+
+ Atom utf8StringType = sf::priv::getAtom("UTF8_STRING");
+
+ if (!utf8StringType)
+ utf8StringType = XA_STRING;
+
+ result = XGetWindowProperty(display,
+ rootWindow,
+ netWmName,
+ 0,
+ 0x7fffffff,
+ False,
+ utf8StringType,
+ &actualType,
+ &actualFormat,
+ &numItems,
+ &numBytes,
+ &data);
+
+ if (actualType && numItems)
+ {
+ // It seems the wm name string reply is not necessarily
+ // null-terminated. The work around is to get its actual
+ // length to build a proper string
+ const char* begin = reinterpret_cast<const char*>(data);
+ const char* end = begin + numItems;
+ windowManagerName = sf::String::fromUtf8(begin, end);
+ }
+
+ if (result == Success)
+ XFree(data);
+
+ sf::priv::CloseDisplay(display);
+
+ return true;
+ }
+
+ // Get the parent window.
+ ::Window getParentWindow(::Display* disp, ::Window win)
+ {
+ ::Window root, parent;
+ ::Window* children = NULL;
+ unsigned int numChildren;
+
+ XQueryTree(disp, win, &root, &parent, &children, &numChildren);
+
+ // Children information is not used, so must be freed.
+ if (children != NULL)
+ XFree(children);
+
+ return parent;
+ }
+
+ // Get the Frame Extents from EWMH WMs that support it.
+ bool getEWMHFrameExtents(::Display* disp, ::Window win,
+ long& xFrameExtent, long& yFrameExtent)
+ {
+ if (!ewmhSupported())
+ return false;
+
+ Atom frameExtents = sf::priv::getAtom("_NET_FRAME_EXTENTS", true);
+
+ if (frameExtents == None)
+ return false;
+
+ bool gotFrameExtents = false;
+ Atom actualType;
+ int actualFormat;
+ unsigned long numItems;
+ unsigned long numBytesLeft;
+ unsigned char* data = NULL;
+
+ int result = XGetWindowProperty(disp,
+ win,
+ frameExtents,
+ 0,
+ 4,
+ False,
+ XA_CARDINAL,
+ &actualType,
+ &actualFormat,
+ &numItems,
+ &numBytesLeft,
+ &data);
+
+ if ((result == Success) && (actualType == XA_CARDINAL) &&
+ (actualFormat == 32) && (numItems == 4) && (numBytesLeft == 0) &&
+ (data != NULL))
+ {
+ gotFrameExtents = true;
+
+ long* extents = (long*) data;
+
+ xFrameExtent = extents[0]; // Left.
+ yFrameExtent = extents[2]; // Top.
+ }
+
+ // Always free data.
+ if (data != NULL)
+ XFree(data);
+
+ return gotFrameExtents;
+ }
+
+ // Check if the current WM is in the list of good WMs that provide
+ // a correct absolute position for the window when queried.
+ bool isWMAbsolutePositionGood()
+ {
+ // This can only work with EWMH, to get the name.
+ if (!ewmhSupported())
+ return false;
+
+ for (size_t i = 0; i < (sizeof(wmAbsPosGood) / sizeof(wmAbsPosGood[0])); i++)
+ {
+ if (wmAbsPosGood[i] == windowManagerName)
+ return true;
+ }
+
+ return false;
+ }
+
+ sf::Keyboard::Key keysymToSF(KeySym symbol)
+ {
+ switch (symbol)
+ {
+ case XK_Shift_L: return sf::Keyboard::LShift;
+ case XK_Shift_R: return sf::Keyboard::RShift;
+ case XK_Control_L: return sf::Keyboard::LControl;
+ case XK_Control_R: return sf::Keyboard::RControl;
+ case XK_Alt_L: return sf::Keyboard::LAlt;
+ case XK_Alt_R: return sf::Keyboard::RAlt;
+ case XK_Super_L: return sf::Keyboard::LSystem;
+ case XK_Super_R: return sf::Keyboard::RSystem;
+ case XK_Menu: return sf::Keyboard::Menu;
+ case XK_Escape: return sf::Keyboard::Escape;
+ case XK_semicolon: return sf::Keyboard::Semicolon;
+ case XK_slash: return sf::Keyboard::Slash;
+ case XK_equal: return sf::Keyboard::Equal;
+ case XK_minus: return sf::Keyboard::Hyphen;
+ case XK_bracketleft: return sf::Keyboard::LBracket;
+ case XK_bracketright: return sf::Keyboard::RBracket;
+ case XK_comma: return sf::Keyboard::Comma;
+ case XK_period: return sf::Keyboard::Period;
+ case XK_apostrophe: return sf::Keyboard::Quote;
+ case XK_backslash: return sf::Keyboard::Backslash;
+ case XK_grave: return sf::Keyboard::Tilde;
+ case XK_space: return sf::Keyboard::Space;
+ case XK_Return: return sf::Keyboard::Enter;
+ case XK_KP_Enter: return sf::Keyboard::Enter;
+ case XK_BackSpace: return sf::Keyboard::Backspace;
+ case XK_Tab: return sf::Keyboard::Tab;
+ case XK_Prior: return sf::Keyboard::PageUp;
+ case XK_Next: return sf::Keyboard::PageDown;
+ case XK_End: return sf::Keyboard::End;
+ case XK_Home: return sf::Keyboard::Home;
+ case XK_Insert: return sf::Keyboard::Insert;
+ case XK_Delete: return sf::Keyboard::Delete;
+ case XK_KP_Add: return sf::Keyboard::Add;
+ case XK_KP_Subtract: return sf::Keyboard::Subtract;
+ case XK_KP_Multiply: return sf::Keyboard::Multiply;
+ case XK_KP_Divide: return sf::Keyboard::Divide;
+ case XK_Pause: return sf::Keyboard::Pause;
+ case XK_F1: return sf::Keyboard::F1;
+ case XK_F2: return sf::Keyboard::F2;
+ case XK_F3: return sf::Keyboard::F3;
+ case XK_F4: return sf::Keyboard::F4;
+ case XK_F5: return sf::Keyboard::F5;
+ case XK_F6: return sf::Keyboard::F6;
+ case XK_F7: return sf::Keyboard::F7;
+ case XK_F8: return sf::Keyboard::F8;
+ case XK_F9: return sf::Keyboard::F9;
+ case XK_F10: return sf::Keyboard::F10;
+ case XK_F11: return sf::Keyboard::F11;
+ case XK_F12: return sf::Keyboard::F12;
+ case XK_F13: return sf::Keyboard::F13;
+ case XK_F14: return sf::Keyboard::F14;
+ case XK_F15: return sf::Keyboard::F15;
+ case XK_Left: return sf::Keyboard::Left;
+ case XK_Right: return sf::Keyboard::Right;
+ case XK_Up: return sf::Keyboard::Up;
+ case XK_Down: return sf::Keyboard::Down;
+ case XK_KP_Insert: return sf::Keyboard::Numpad0;
+ case XK_KP_End: return sf::Keyboard::Numpad1;
+ case XK_KP_Down: return sf::Keyboard::Numpad2;
+ case XK_KP_Page_Down: return sf::Keyboard::Numpad3;
+ case XK_KP_Left: return sf::Keyboard::Numpad4;
+ case XK_KP_Begin: return sf::Keyboard::Numpad5;
+ case XK_KP_Right: return sf::Keyboard::Numpad6;
+ case XK_KP_Home: return sf::Keyboard::Numpad7;
+ case XK_KP_Up: return sf::Keyboard::Numpad8;
+ case XK_KP_Page_Up: return sf::Keyboard::Numpad9;
+ case XK_a: return sf::Keyboard::A;
+ case XK_b: return sf::Keyboard::B;
+ case XK_c: return sf::Keyboard::C;
+ case XK_d: return sf::Keyboard::D;
+ case XK_e: return sf::Keyboard::E;
+ case XK_f: return sf::Keyboard::F;
+ case XK_g: return sf::Keyboard::G;
+ case XK_h: return sf::Keyboard::H;
+ case XK_i: return sf::Keyboard::I;
+ case XK_j: return sf::Keyboard::J;
+ case XK_k: return sf::Keyboard::K;
+ case XK_l: return sf::Keyboard::L;
+ case XK_m: return sf::Keyboard::M;
+ case XK_n: return sf::Keyboard::N;
+ case XK_o: return sf::Keyboard::O;
+ case XK_p: return sf::Keyboard::P;
+ case XK_q: return sf::Keyboard::Q;
+ case XK_r: return sf::Keyboard::R;
+ case XK_s: return sf::Keyboard::S;
+ case XK_t: return sf::Keyboard::T;
+ case XK_u: return sf::Keyboard::U;
+ case XK_v: return sf::Keyboard::V;
+ case XK_w: return sf::Keyboard::W;
+ case XK_x: return sf::Keyboard::X;
+ case XK_y: return sf::Keyboard::Y;
+ case XK_z: return sf::Keyboard::Z;
+ case XK_0: return sf::Keyboard::Num0;
+ case XK_1: return sf::Keyboard::Num1;
+ case XK_2: return sf::Keyboard::Num2;
+ case XK_3: return sf::Keyboard::Num3;
+ case XK_4: return sf::Keyboard::Num4;
+ case XK_5: return sf::Keyboard::Num5;
+ case XK_6: return sf::Keyboard::Num6;
+ case XK_7: return sf::Keyboard::Num7;
+ case XK_8: return sf::Keyboard::Num8;
+ case XK_9: return sf::Keyboard::Num9;
+ }
+
+ return sf::Keyboard::Unknown;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+WindowImplX11::WindowImplX11(WindowHandle handle) :
+m_window (0),
+m_screen (0),
+m_inputMethod (NULL),
+m_inputContext (NULL),
+m_isExternal (true),
+m_oldVideoMode (0),
+m_oldRRCrtc (0),
+m_hiddenCursor (0),
+m_lastCursor (None),
+m_keyRepeat (true),
+m_previousSize (-1, -1),
+m_useSizeHints (false),
+m_fullscreen (false),
+m_cursorGrabbed (false),
+m_windowMapped (false),
+m_iconPixmap (0),
+m_iconMaskPixmap (0),
+m_lastInputTime (0)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+
+ // Make sure to check for EWMH support before we do anything
+ ewmhSupported();
+
+ m_screen = DefaultScreen(m_display);
+
+ // Save the window handle
+ m_window = handle;
+
+ if (m_window)
+ {
+ // Make sure the window is listening to all the required events
+ XSetWindowAttributes attributes;
+ attributes.event_mask = eventMask;
+
+ XChangeWindowAttributes(m_display, m_window, CWEventMask, &attributes);
+
+ // Set the WM protocols
+ setProtocols();
+
+ // Do some common initializations
+ initialize();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) :
+m_window (0),
+m_screen (0),
+m_inputMethod (NULL),
+m_inputContext (NULL),
+m_isExternal (false),
+m_oldVideoMode (0),
+m_oldRRCrtc (0),
+m_hiddenCursor (0),
+m_lastCursor (None),
+m_keyRepeat (true),
+m_previousSize (-1, -1),
+m_useSizeHints (false),
+m_fullscreen ((style & Style::Fullscreen) != 0),
+m_cursorGrabbed (m_fullscreen),
+m_windowMapped (false),
+m_iconPixmap (0),
+m_iconMaskPixmap (0),
+m_lastInputTime (0)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+
+ // Make sure to check for EWMH support before we do anything
+ ewmhSupported();
+
+ m_screen = DefaultScreen(m_display);
+
+ // Compute position and size
+ Vector2i windowPosition;
+ if(m_fullscreen)
+ {
+ windowPosition = getPrimaryMonitorPosition();
+ }
+ else
+ {
+ windowPosition.x = (DisplayWidth(m_display, m_screen) - mode.width) / 2;
+ windowPosition.y = (DisplayWidth(m_display, m_screen) - mode.height) / 2;
+ }
+
+ int width = mode.width;
+ int height = mode.height;
+
+ // Choose the visual according to the context settings
+ XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings);
+
+ // Define the window attributes
+ XSetWindowAttributes attributes;
+ attributes.colormap = XCreateColormap(m_display, DefaultRootWindow(m_display), visualInfo.visual, AllocNone);
+ attributes.event_mask = eventMask;
+ attributes.override_redirect = (m_fullscreen && !ewmhSupported()) ? True : False;
+
+ m_window = XCreateWindow(m_display,
+ DefaultRootWindow(m_display),
+ windowPosition.x, windowPosition.y,
+ width, height,
+ 0,
+ visualInfo.depth,
+ InputOutput,
+ visualInfo.visual,
+ CWEventMask | CWOverrideRedirect | CWColormap,
+ &attributes);
+
+ if (!m_window)
+ {
+ err() << "Failed to create window" << std::endl;
+ return;
+ }
+
+ // Set the WM protocols
+ setProtocols();
+
+ // Set the WM initial state to the normal state
+ XWMHints* hints = XAllocWMHints();
+ hints->flags = StateHint;
+ hints->initial_state = NormalState;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+
+ // If not in fullscreen, set the window's style (tell the window manager to
+ // change our window's decorations and functions according to the requested style)
+ if (!m_fullscreen)
+ {
+ Atom WMHintsAtom = getAtom("_MOTIF_WM_HINTS", false);
+ if (WMHintsAtom)
+ {
+ static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0;
+ static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1;
+
+ //static const unsigned long MWM_DECOR_ALL = 1 << 0;
+ static const unsigned long MWM_DECOR_BORDER = 1 << 1;
+ static const unsigned long MWM_DECOR_RESIZEH = 1 << 2;
+ static const unsigned long MWM_DECOR_TITLE = 1 << 3;
+ static const unsigned long MWM_DECOR_MENU = 1 << 4;
+ static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5;
+ static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6;
+
+ //static const unsigned long MWM_FUNC_ALL = 1 << 0;
+ static const unsigned long MWM_FUNC_RESIZE = 1 << 1;
+ static const unsigned long MWM_FUNC_MOVE = 1 << 2;
+ static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3;
+ static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4;
+ static const unsigned long MWM_FUNC_CLOSE = 1 << 5;
+
+ struct WMHints
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long state;
+ };
+
+ WMHints hints;
+ std::memset(&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
+ hints.decorations = 0;
+ hints.functions = 0;
+
+ if (style & Style::Titlebar)
+ {
+ hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
+ hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
+ }
+ if (style & Style::Resize)
+ {
+ hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH;
+ hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
+ }
+ if (style & Style::Close)
+ {
+ hints.decorations |= 0;
+ hints.functions |= MWM_FUNC_CLOSE;
+ }
+
+ XChangeProperty(m_display,
+ m_window,
+ WMHintsAtom,
+ WMHintsAtom,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&hints),
+ 5);
+ }
+ }
+
+ // This is a hack to force some windows managers to disable resizing
+ if (!(style & Style::Resize))
+ {
+ m_useSizeHints = true;
+ XSizeHints* sizeHints = XAllocSizeHints();
+ sizeHints->flags = PMinSize | PMaxSize | USPosition;
+ sizeHints->min_width = sizeHints->max_width = width;
+ sizeHints->min_height = sizeHints->max_height = height;
+ sizeHints->x = windowPosition.x;
+ sizeHints->y = windowPosition.y;
+ XSetWMNormalHints(m_display, m_window, sizeHints);
+ XFree(sizeHints);
+ }
+
+ // Set the window's WM class (this can be used by window managers)
+ XClassHint* hint = XAllocClassHint();
+
+ // The instance name should be something unique to this invocation
+ // of the application but is rarely if ever used these days.
+ // For simplicity, we retrieve it via the base executable name.
+ std::string executableName = findExecutableName();
+ std::vector<char> windowInstance(executableName.size() + 1, 0);
+ std::copy(executableName.begin(), executableName.end(), windowInstance.begin());
+ hint->res_name = &windowInstance[0];
+
+ // The class name identifies a class of windows that
+ // "are of the same type". We simply use the initial window name as
+ // the class name.
+ std::string ansiTitle = title.toAnsiString();
+ std::vector<char> windowClass(ansiTitle.size() + 1, 0);
+ std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin());
+ hint->res_class = &windowClass[0];
+
+ XSetClassHint(m_display, m_window, hint);
+
+ XFree(hint);
+
+ // Set the window's name
+ setTitle(title);
+
+ // Do some common initializations
+ initialize();
+
+ // Set fullscreen video mode and switch to fullscreen if necessary
+ if (m_fullscreen)
+ {
+ // Disable hint for min and max size,
+ // otherwise some windows managers will not remove window decorations
+ XSizeHints *sizeHints = XAllocSizeHints();
+ long flags = 0;
+ XGetWMNormalHints(m_display, m_window, sizeHints, &flags);
+ sizeHints->flags &= ~(PMinSize | PMaxSize);
+ XSetWMNormalHints(m_display, m_window, sizeHints);
+ XFree(sizeHints);
+
+ setVideoMode(mode);
+ switchToFullscreen();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplX11::~WindowImplX11()
+{
+ // Cleanup graphical resources
+ cleanup();
+
+ // Destroy icon pixmap
+ if (m_iconPixmap)
+ XFreePixmap(m_display, m_iconPixmap);
+
+ // Destroy icon mask pixmap
+ if (m_iconMaskPixmap)
+ XFreePixmap(m_display, m_iconMaskPixmap);
+
+ // Destroy the cursor
+ if (m_hiddenCursor)
+ XFreeCursor(m_display, m_hiddenCursor);
+
+ // Destroy the input context
+ if (m_inputContext)
+ XDestroyIC(m_inputContext);
+
+ // Destroy the window
+ if (m_window && !m_isExternal)
+ {
+ XDestroyWindow(m_display, m_window);
+ XFlush(m_display);
+ }
+
+ // Close the input method
+ if (m_inputMethod)
+ XCloseIM(m_inputMethod);
+
+ // Close the connection with the X server
+ CloseDisplay(m_display);
+
+ // Remove this window from the global list of windows (required for focus request)
+ Lock lock(allWindowsMutex);
+ allWindows.erase(std::find(allWindows.begin(), allWindows.end(), this));
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplX11::getSystemHandle() const
+{
+ return m_window;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::processEvents()
+{
+ XEvent event;
+
+ // Pick out the events that are interesting for this window
+ while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
+ m_events.push_back(event);
+
+ // Handle the events for this window that we just picked out
+ while (!m_events.empty())
+ {
+ event = m_events.front();
+ m_events.pop_front();
+ processEvent(event);
+ }
+
+ // Process clipboard window events
+ priv::ClipboardImpl::processEvents();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplX11::getPosition() const
+{
+ // Get absolute position of our window relative to root window. This
+ // takes into account all information that X11 has, including X11
+ // border widths and any decorations. It corresponds to where the
+ // window actually is, but not necessarily to where we told it to
+ // go using setPosition() and XMoveWindow(). To have the two match
+ // as expected, we may have to subtract decorations and borders.
+ ::Window child;
+ int xAbsRelToRoot, yAbsRelToRoot;
+
+ XTranslateCoordinates(m_display, m_window, DefaultRootWindow(m_display),
+ 0, 0, &xAbsRelToRoot, &yAbsRelToRoot, &child);
+
+ // CASE 1: some rare WMs actually put the window exactly where we tell
+ // it to, even with decorations and such, which get shifted back.
+ // In these rare cases, we can use the absolute value directly.
+ if (isWMAbsolutePositionGood())
+ return Vector2i(xAbsRelToRoot, yAbsRelToRoot);
+
+ // CASE 2: most modern WMs support EWMH and can define _NET_FRAME_EXTENTS
+ // with the exact frame size to subtract, so if present, we prefer it and
+ // query it first. According to spec, this already includes any borders.
+ long xFrameExtent, yFrameExtent;
+
+ if (getEWMHFrameExtents(m_display, m_window, xFrameExtent, yFrameExtent))
+ {
+ // Get final X/Y coordinates: subtract EWMH frame extents from
+ // absolute window position.
+ return Vector2i((xAbsRelToRoot - xFrameExtent), (yAbsRelToRoot - yFrameExtent));
+ }
+
+ // CASE 3: EWMH frame extents were not available, use geometry.
+ // We climb back up to the window before the root and use its
+ // geometry information to extract X/Y position. This because
+ // re-parenting WMs may re-parent the window multiple times, so
+ // we'd have to climb up to the furthest ancestor and sum the
+ // relative differences and borders anyway; and doing that to
+ // subtract those values from the absolute coordinates of the
+ // window is equivalent to going up the tree and asking the
+ // furthest ancestor what it's relative distance to the root is.
+ // So we use that approach because it's simpler.
+ // This approach assumes that any window between the root and
+ // our window is part of decorations/borders in some way. This
+ // seems to hold true for most reasonable WM implementations.
+ ::Window ancestor = m_window;
+ ::Window root = DefaultRootWindow(m_display);
+
+ while (getParentWindow(m_display, ancestor) != root)
+ {
+ // Next window up (parent window).
+ ancestor = getParentWindow(m_display, ancestor);
+ }
+
+ // Get final X/Y coordinates: take the relative position to
+ // the root of the furthest ancestor window.
+ int xRelToRoot, yRelToRoot;
+ unsigned int width, height, borderWidth, depth;
+
+ XGetGeometry(m_display, ancestor, &root, &xRelToRoot, &yRelToRoot,
+ &width, &height, &borderWidth, &depth);
+
+ return Vector2i(xRelToRoot, yRelToRoot);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setPosition(const Vector2i& position)
+{
+ XMoveWindow(m_display, m_window, position.x, position.y);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplX11::getSize() const
+{
+ XWindowAttributes attributes;
+ XGetWindowAttributes(m_display, m_window, &attributes);
+ return Vector2u(attributes.width, attributes.height);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setSize(const Vector2u& size)
+{
+ // If resizing is disable for the window we have to update the size hints (required by some window managers).
+ if (m_useSizeHints)
+ {
+ XSizeHints* sizeHints = XAllocSizeHints();
+ sizeHints->flags = PMinSize | PMaxSize;
+ sizeHints->min_width = sizeHints->max_width = size.x;
+ sizeHints->min_height = sizeHints->max_height = size.y;
+ XSetWMNormalHints(m_display, m_window, sizeHints);
+ XFree(sizeHints);
+ }
+
+ XResizeWindow(m_display, m_window, size.x, size.y);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setTitle(const String& title)
+{
+ // Bare X11 has no Unicode window title support.
+ // There is however an option to tell the window manager your Unicode title via hints.
+
+ // Convert to UTF-8 encoding.
+ std::basic_string<Uint8> utf8Title;
+ Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));
+
+ Atom useUtf8 = getAtom("UTF8_STRING", false);
+
+ // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title.
+ Atom wmName = getAtom("_NET_WM_NAME", false);
+ XChangeProperty(m_display, m_window, wmName, useUtf8, 8,
+ PropModeReplace, utf8Title.c_str(), utf8Title.size());
+
+ // Set the _NET_WM_ICON_NAME atom, which specifies a UTF-8 encoded window title.
+ Atom wmIconName = getAtom("_NET_WM_ICON_NAME", false);
+ XChangeProperty(m_display, m_window, wmIconName, useUtf8, 8,
+ PropModeReplace, utf8Title.c_str(), utf8Title.size());
+
+ // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME.
+ #ifdef X_HAVE_UTF8_STRING
+ Xutf8SetWMProperties(m_display,
+ m_window,
+ title.toAnsiString().c_str(),
+ title.toAnsiString().c_str(),
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ #else
+ XmbSetWMProperties(m_display,
+ m_window,
+ title.toAnsiString().c_str(),
+ title.toAnsiString().c_str(),
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ #endif
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ // X11 wants BGRA pixels: swap red and blue channels
+ // Note: this memory will be freed by XDestroyImage
+ Uint8* iconPixels = static_cast<Uint8*>(std::malloc(width * height * 4));
+ for (std::size_t i = 0; i < width * height; ++i)
+ {
+ iconPixels[i * 4 + 0] = pixels[i * 4 + 2];
+ iconPixels[i * 4 + 1] = pixels[i * 4 + 1];
+ iconPixels[i * 4 + 2] = pixels[i * 4 + 0];
+ iconPixels[i * 4 + 3] = pixels[i * 4 + 3];
+ }
+
+ // Create the icon pixmap
+ Visual* defVisual = DefaultVisual(m_display, m_screen);
+ unsigned int defDepth = DefaultDepth(m_display, m_screen);
+ XImage* iconImage = XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, (char*)iconPixels, width, height, 32, 0);
+ if (!iconImage)
+ {
+ err() << "Failed to set the window's icon" << std::endl;
+ return;
+ }
+
+ if (m_iconPixmap)
+ XFreePixmap(m_display, m_iconPixmap);
+
+ if (m_iconMaskPixmap)
+ XFreePixmap(m_display, m_iconMaskPixmap);
+
+ m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth);
+ XGCValues values;
+ GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values);
+ XPutImage(m_display, m_iconPixmap, iconGC, iconImage, 0, 0, 0, 0, width, height);
+ XFreeGC(m_display, iconGC);
+ XDestroyImage(iconImage);
+
+ // Create the mask pixmap (must have 1 bit depth)
+ std::size_t pitch = (width + 7) / 8;
+ std::vector<Uint8> maskPixels(pitch * height, 0);
+ for (std::size_t j = 0; j < height; ++j)
+ {
+ for (std::size_t i = 0; i < pitch; ++i)
+ {
+ for (std::size_t k = 0; k < 8; ++k)
+ {
+ if (i * 8 + k < width)
+ {
+ Uint8 opacity = (pixels[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0;
+ maskPixels[i + j * pitch] |= (opacity << k);
+ }
+ }
+ }
+ }
+ m_iconMaskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1);
+
+ // Send our new icon to the window through the WMHints
+ XWMHints* hints = XAllocWMHints();
+ hints->flags = IconPixmapHint | IconMaskHint;
+ hints->icon_pixmap = m_iconPixmap;
+ hints->icon_mask = m_iconMaskPixmap;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+
+ // ICCCM wants BGRA pixels: swap red and blue channels
+ // ICCCM also wants the first 2 unsigned 32-bit values to be width and height
+ std::vector<unsigned long> icccmIconPixels(2 + width * height, 0);
+ unsigned long* ptr = &icccmIconPixels[0];
+
+ *ptr++ = width;
+ *ptr++ = height;
+
+ for (std::size_t i = 0; i < width * height; ++i)
+ {
+ *ptr++ = (pixels[i * 4 + 2] << 0 ) |
+ (pixels[i * 4 + 1] << 8 ) |
+ (pixels[i * 4 + 0] << 16) |
+ (pixels[i * 4 + 3] << 24);
+ }
+
+ Atom netWmIcon = getAtom("_NET_WM_ICON");
+
+ XChangeProperty(m_display,
+ m_window,
+ netWmIcon,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&icccmIconPixels[0]),
+ 2 + width * height);
+
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setVisible(bool visible)
+{
+ if (visible)
+ {
+ XMapWindow(m_display, m_window);
+
+ if(m_fullscreen)
+ switchToFullscreen();
+
+ XFlush(m_display);
+
+ // Before continuing, make sure the WM has
+ // internally marked the window as viewable
+ while (!m_windowMapped && !m_isExternal)
+ processEvents();
+ }
+ else
+ {
+ XUnmapWindow(m_display, m_window);
+
+ XFlush(m_display);
+
+ // Before continuing, make sure the WM has
+ // internally marked the window as unviewable
+ while (m_windowMapped && !m_isExternal)
+ processEvents();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setMouseCursorVisible(bool visible)
+{
+ XDefineCursor(m_display, m_window, visible ? m_lastCursor : m_hiddenCursor);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setMouseCursor(const CursorImpl& cursor)
+{
+ m_lastCursor = cursor.m_cursor;
+ XDefineCursor(m_display, m_window, m_lastCursor);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setMouseCursorGrabbed(bool grabbed)
+{
+ // This has no effect in fullscreen mode
+ if (m_fullscreen || (m_cursorGrabbed == grabbed))
+ return;
+
+ if (grabbed)
+ {
+ // Try multiple times to grab the cursor
+ for (unsigned int trial = 0; trial < maxTrialsCount; ++trial)
+ {
+ int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
+
+ if (result == GrabSuccess)
+ {
+ m_cursorGrabbed = true;
+ break;
+ }
+
+ // The cursor grab failed, trying again after a small sleep
+ sf::sleep(sf::milliseconds(50));
+ }
+
+ if (!m_cursorGrabbed)
+ err() << "Failed to grab mouse cursor" << std::endl;
+ }
+ else
+ {
+ XUngrabPointer(m_display, CurrentTime);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setKeyRepeatEnabled(bool enabled)
+{
+ m_keyRepeat = enabled;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::requestFocus()
+{
+ // Focus is only stolen among SFML windows, not between applications
+ // Check the global list of windows to find out whether an SFML window has the focus
+ // Note: can't handle console and other non-SFML windows belonging to the application.
+ bool sfmlWindowFocused = false;
+
+ {
+ Lock lock(allWindowsMutex);
+ for (std::vector<WindowImplX11*>::iterator itr = allWindows.begin(); itr != allWindows.end(); ++itr)
+ {
+ if ((*itr)->hasFocus())
+ {
+ sfmlWindowFocused = true;
+ break;
+ }
+ }
+ }
+
+ // Check if window is viewable (not on other desktop, ...)
+ // TODO: Check also if minimized
+ XWindowAttributes attributes;
+ if (XGetWindowAttributes(m_display, m_window, &attributes) == 0)
+ {
+ sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl;
+ return; // error getting attribute
+ }
+
+ bool windowViewable = (attributes.map_state == IsViewable);
+
+ if (sfmlWindowFocused && windowViewable)
+ {
+ // Another SFML window of this application has the focus and the current window is viewable:
+ // steal focus (i.e. bring window to the front and give it input focus)
+ grabFocus();
+ }
+ else
+ {
+ // Otherwise: display urgency hint (flashing application logo)
+ // Ensure WM hints exist, allocate if necessary
+ XWMHints* hints = XGetWMHints(m_display, m_window);
+ if (hints == NULL)
+ hints = XAllocWMHints();
+
+ // Add urgency (notification) flag to hints
+ hints->flags |= XUrgencyHint;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplX11::hasFocus() const
+{
+ ::Window focusedWindow = 0;
+ int revertToReturn = 0;
+ XGetInputFocus(m_display, &focusedWindow, &revertToReturn);
+
+ return (m_window == focusedWindow);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::grabFocus()
+{
+ Atom netActiveWindow = None;
+
+ if (ewmhSupported())
+ netActiveWindow = getAtom("_NET_ACTIVE_WINDOW");
+
+ // Only try to grab focus if the window is mapped
+ XWindowAttributes attr;
+
+ XGetWindowAttributes(m_display, m_window, &attr);
+
+ if (attr.map_state == IsUnmapped)
+ return;
+
+ if (netActiveWindow)
+ {
+ XEvent event;
+ std::memset(&event, 0, sizeof(event));
+
+ event.type = ClientMessage;
+ event.xclient.window = m_window;
+ event.xclient.format = 32;
+ event.xclient.message_type = netActiveWindow;
+ event.xclient.data.l[0] = 1; // Normal application
+ event.xclient.data.l[1] = m_lastInputTime;
+ event.xclient.data.l[2] = 0; // We don't know the currently active window
+
+ int result = XSendEvent(m_display,
+ DefaultRootWindow(m_display),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &event);
+
+ XFlush(m_display);
+
+ if (!result)
+ err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl;
+ }
+ else
+ {
+ XRaiseWindow(m_display, m_window);
+ XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
+ XFlush(m_display);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setVideoMode(const VideoMode& mode)
+{
+ // Skip mode switching if the new mode is equal to the desktop mode
+ if (mode == VideoMode::getDesktopMode())
+ return;
+
+ // Check if the XRandR extension is present
+ int xRandRMajor, xRandRMinor;
+ if (!checkXRandR(xRandRMajor, xRandRMinor))
+ {
+ // XRandR extension is not supported: we cannot use fullscreen mode
+ err() << "Fullscreen is not supported, switching to window mode" << std::endl;
+ return;
+ }
+
+ // Get root window
+ ::Window rootWindow = RootWindow(m_display, m_screen);
+
+ // Get the screen resources
+ XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow);
+ if (!res)
+ {
+ err() << "Failed to get the current screen resources for fullscreen mode, switching to window mode" << std::endl;
+ return;
+ }
+
+ RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor);
+
+ // Get output info from output
+ XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output);
+ if (!outputInfo || outputInfo->connection == RR_Disconnected)
+ {
+ XRRFreeScreenResources(res);
+
+ // If outputInfo->connection == RR_Disconnected, free output info
+ if (outputInfo)
+ XRRFreeOutputInfo(outputInfo);
+
+ err() << "Failed to get output info for fullscreen mode, switching to window mode" << std::endl;
+ return;
+ }
+
+ // Retreive current RRMode, screen position and rotation
+ XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc);
+ if (!crtcInfo)
+ {
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(outputInfo);
+ err() << "Failed to get crtc info for fullscreen mode, switching to window mode" << std::endl;
+ return;
+ }
+
+ // Find RRMode to set
+ bool modeFound = false;
+ RRMode xRandMode;
+
+ for (int i = 0; (i < res->nmode) && !modeFound; i++)
+ {
+ if (crtcInfo->rotation == RR_Rotate_90 || crtcInfo->rotation == RR_Rotate_270)
+ std::swap(res->modes[i].height, res->modes[i].width);
+
+ // Check if screen size match
+ if (res->modes[i].width == static_cast<int>(mode.width) &&
+ res->modes[i].height == static_cast<int>(mode.height))
+ {
+ xRandMode = res->modes[i].id;
+ modeFound = true;
+ }
+ }
+
+ if (!modeFound)
+ {
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(outputInfo);
+ err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl;
+ return;
+ }
+
+ // Save the current video mode before we switch to fullscreen
+ m_oldVideoMode = crtcInfo->mode;
+ m_oldRRCrtc = outputInfo->crtc;
+
+ // Switch to fullscreen mode
+ XRRSetCrtcConfig(m_display,
+ res,
+ outputInfo->crtc,
+ CurrentTime,
+ crtcInfo->x,
+ crtcInfo->y,
+ xRandMode,
+ crtcInfo->rotation,
+ &output,
+ 1);
+
+ // Set "this" as the current fullscreen window
+ fullscreenWindow = this;
+
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeCrtcInfo(crtcInfo);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::resetVideoMode()
+{
+ if (fullscreenWindow == this)
+ {
+ // Try to set old configuration
+ // Check if the XRandR extension
+ int xRandRMajor, xRandRMinor;
+ if (checkXRandR(xRandRMajor, xRandRMinor))
+ {
+ XRRScreenResources* res = XRRGetScreenResources(m_display, DefaultRootWindow(m_display));
+ if (!res)
+ {
+ err() << "Failed to get the current screen resources to reset the video mode" << std::endl;
+ return;
+ }
+
+ // Retreive current screen position and rotation
+ XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, m_oldRRCrtc);
+ if (!crtcInfo)
+ {
+ XRRFreeScreenResources(res);
+ err() << "Failed to get crtc info to reset the video mode" << std::endl;
+ return;
+ }
+
+ RROutput output;
+
+ // if version >= 1.3 get the primary screen else take the first screen
+ if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
+ {
+ output = XRRGetOutputPrimary(m_display, DefaultRootWindow(m_display));
+
+ // Check if returned output is valid, otherwise use the first screen
+ if (output == None)
+ output = res->outputs[0];
+ }
+ else{
+ output = res->outputs[0];
+ }
+
+ XRRSetCrtcConfig(m_display,
+ res,
+ m_oldRRCrtc,
+ CurrentTime,
+ crtcInfo->x,
+ crtcInfo->y,
+ m_oldVideoMode,
+ crtcInfo->rotation,
+ &output,
+ 1);
+
+ XRRFreeCrtcInfo(crtcInfo);
+ XRRFreeScreenResources(res);
+ }
+
+ // Reset the fullscreen window
+ fullscreenWindow = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::switchToFullscreen()
+{
+ grabFocus();
+
+ if (ewmhSupported())
+ {
+ Atom netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR");
+
+ if (netWmBypassCompositor)
+ {
+ static const unsigned long bypassCompositor = 1;
+
+ XChangeProperty(m_display,
+ m_window,
+ netWmBypassCompositor,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&bypassCompositor),
+ 1);
+ }
+
+ Atom netWmState = getAtom("_NET_WM_STATE", true);
+ Atom netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true);
+
+ if (!netWmState || !netWmStateFullscreen)
+ {
+ err() << "Setting fullscreen failed. Could not get required atoms" << std::endl;
+ return;
+ }
+
+ XEvent event;
+ std::memset(&event, 0, sizeof(event));
+
+ event.type = ClientMessage;
+ event.xclient.window = m_window;
+ event.xclient.format = 32;
+ event.xclient.message_type = netWmState;
+ event.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD
+ event.xclient.data.l[1] = netWmStateFullscreen;
+ event.xclient.data.l[2] = 0; // No second property
+ event.xclient.data.l[3] = 1; // Normal window
+
+ int result = XSendEvent(m_display,
+ DefaultRootWindow(m_display),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &event);
+
+ if (!result)
+ err() << "Setting fullscreen failed, could not send \"_NET_WM_STATE\" event" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setProtocols()
+{
+ Atom wmProtocols = getAtom("WM_PROTOCOLS");
+ Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW");
+
+ if (!wmProtocols)
+ {
+ err() << "Failed to request WM_PROTOCOLS atom." << std::endl;
+ return;
+ }
+
+ std::vector<Atom> atoms;
+
+ if (wmDeleteWindow)
+ {
+ atoms.push_back(wmDeleteWindow);
+ }
+ else
+ {
+ err() << "Failed to request WM_DELETE_WINDOW atom." << std::endl;
+ }
+
+ Atom netWmPing = None;
+ Atom netWmPid = None;
+
+ if (ewmhSupported())
+ {
+ netWmPing = getAtom("_NET_WM_PING", true);
+ netWmPid = getAtom("_NET_WM_PID", true);
+ }
+
+ if (netWmPing && netWmPid)
+ {
+ const long pid = getpid();
+
+ XChangeProperty(m_display,
+ m_window,
+ netWmPid,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&pid),
+ 1);
+
+ atoms.push_back(netWmPing);
+ }
+
+ if (!atoms.empty())
+ {
+ XChangeProperty(m_display,
+ m_window,
+ wmProtocols,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&atoms[0]),
+ atoms.size());
+ }
+ else
+ {
+ err() << "Didn't set any window protocols" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::initialize()
+{
+ // Create the input context
+ m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
+
+ if (m_inputMethod)
+ {
+ m_inputContext = XCreateIC(m_inputMethod,
+ XNClientWindow,
+ m_window,
+ XNFocusWindow,
+ m_window,
+ XNInputStyle,
+ XIMPreeditNothing | XIMStatusNothing,
+ reinterpret_cast<void*>(NULL));
+ }
+ else
+ {
+ m_inputContext = NULL;
+ }
+
+ if (!m_inputContext)
+ err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl;
+
+ Atom wmWindowType = getAtom("_NET_WM_WINDOW_TYPE", false);
+ Atom wmWindowTypeNormal = getAtom("_NET_WM_WINDOW_TYPE_NORMAL", false);
+
+ if (wmWindowType && wmWindowTypeNormal)
+ {
+ XChangeProperty(m_display,
+ m_window,
+ wmWindowType,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&wmWindowTypeNormal),
+ 1);
+ }
+
+ // Show the window
+ setVisible(true);
+
+ // Raise the window and grab input focus
+ grabFocus();
+
+ // Create the hidden cursor
+ createHiddenCursor();
+
+ // Flush the commands queue
+ XFlush(m_display);
+
+ // Add this window to the global list of windows (required for focus request)
+ Lock lock(allWindowsMutex);
+ allWindows.push_back(this);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::updateLastInputTime(::Time time)
+{
+ if (time && (time != m_lastInputTime))
+ {
+ Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true);
+
+ if (netWmUserTime)
+ {
+ XChangeProperty(m_display,
+ m_window,
+ netWmUserTime,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&time),
+ 1);
+ }
+
+ m_lastInputTime = time;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::createHiddenCursor()
+{
+ // Create the cursor's pixmap (1x1 pixels)
+ Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1);
+ GC graphicsContext = XCreateGC(m_display, cursorPixmap, 0, NULL);
+ XDrawPoint(m_display, cursorPixmap, graphicsContext, 0, 0);
+ XFreeGC(m_display, graphicsContext);
+
+ // Create the cursor, using the pixmap as both the shape and the mask of the cursor
+ XColor color;
+ color.flags = DoRed | DoGreen | DoBlue;
+ color.red = color.blue = color.green = 0;
+ m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0);
+
+ // We don't need the pixmap any longer, free it
+ XFreePixmap(m_display, cursorPixmap);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::cleanup()
+{
+ // Restore the previous video mode (in case we were running in fullscreen)
+ resetVideoMode();
+
+ // Unhide the mouse cursor (in case it was hidden)
+ setMouseCursorVisible(true);
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplX11::processEvent(XEvent& windowEvent)
+{
+ // This function implements a workaround to properly discard
+ // repeated key events when necessary. The problem is that the
+ // system's key events policy doesn't match SFML's one: X server will generate
+ // both repeated KeyPress and KeyRelease events when maintaining a key down, while
+ // SFML only wants repeated KeyPress events. Thus, we have to:
+ // - Discard duplicated KeyRelease events when KeyRepeatEnabled is true
+ // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
+
+ // Detect repeated key events
+ if (windowEvent.type == KeyRelease)
+ {
+ // Find the next KeyPress event with matching keycode and time
+ std::deque<XEvent>::iterator iter = std::find_if(
+ m_events.begin(),
+ m_events.end(),
+ KeyRepeatFinder(windowEvent.xkey.keycode, windowEvent.xkey.time)
+ );
+
+ if (iter != m_events.end())
+ {
+ // If we don't want repeated events, remove the next KeyPress from the queue
+ if (!m_keyRepeat)
+ m_events.erase(iter);
+
+ // This KeyRelease is a repeated event and we don't want it
+ return false;
+ }
+ }
+
+ // Convert the X11 event to a sf::Event
+ switch (windowEvent.type)
+ {
+ // Destroy event
+ case DestroyNotify:
+ {
+ // The window is about to be destroyed: we must cleanup resources
+ cleanup();
+ break;
+ }
+
+ // Gain focus event
+ case FocusIn:
+ {
+ // Update the input context
+ if (m_inputContext)
+ XSetICFocus(m_inputContext);
+
+ // Grab cursor
+ if (m_cursorGrabbed)
+ {
+ // Try multiple times to grab the cursor
+ for (unsigned int trial = 0; trial < maxTrialsCount; ++trial)
+ {
+ int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
+
+ if (result == GrabSuccess)
+ {
+ m_cursorGrabbed = true;
+ break;
+ }
+
+ // The cursor grab failed, trying again after a small sleep
+ sf::sleep(sf::milliseconds(50));
+ }
+
+ if (!m_cursorGrabbed)
+ err() << "Failed to grab mouse cursor" << std::endl;
+ }
+
+ Event event;
+ event.type = Event::GainedFocus;
+ pushEvent(event);
+
+ // If the window has been previously marked urgent (notification) as a result of a focus request, undo that
+ XWMHints* hints = XGetWMHints(m_display, m_window);
+ if (hints != NULL)
+ {
+ // Remove urgency (notification) flag from hints
+ hints->flags &= ~XUrgencyHint;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+ }
+
+ break;
+ }
+
+ // Lost focus event
+ case FocusOut:
+ {
+ // Update the input context
+ if (m_inputContext)
+ XUnsetICFocus(m_inputContext);
+
+ // Release cursor
+ if (m_cursorGrabbed)
+ XUngrabPointer(m_display, CurrentTime);
+
+ Event event;
+ event.type = Event::LostFocus;
+ pushEvent(event);
+ break;
+ }
+
+ // Resize event
+ case ConfigureNotify:
+ {
+ // ConfigureNotify can be triggered for other reasons, check if the size has actually changed
+ if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y))
+ {
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = windowEvent.xconfigure.width;
+ event.size.height = windowEvent.xconfigure.height;
+ pushEvent(event);
+
+ m_previousSize.x = windowEvent.xconfigure.width;
+ m_previousSize.y = windowEvent.xconfigure.height;
+ }
+ break;
+ }
+
+ // Close event
+ case ClientMessage:
+ {
+ static Atom wmProtocols = getAtom("WM_PROTOCOLS");
+
+ // Handle window manager protocol messages we support
+ if (windowEvent.xclient.message_type == wmProtocols)
+ {
+ static Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW");
+ static Atom netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : None;
+
+ if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(wmDeleteWindow))
+ {
+ // Handle the WM_DELETE_WINDOW message
+ Event event;
+ event.type = Event::Closed;
+ pushEvent(event);
+ }
+ else if (netWmPing && (windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(netWmPing))
+ {
+ // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive
+ windowEvent.xclient.window = DefaultRootWindow(m_display);
+
+ XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent);
+ }
+ }
+ break;
+ }
+
+ // Key down event
+ case KeyPress:
+ {
+ Keyboard::Key key = Keyboard::Unknown;
+
+ // Try each KeySym index (modifier group) until we get a match
+ for (int i = 0; i < 4; ++i)
+ {
+ // Get the SFML keyboard code from the keysym of the key that has been pressed
+ key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i));
+
+ if (key != Keyboard::Unknown)
+ break;
+ }
+
+ // Fill the event parameters
+ // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
+ Event event;
+ event.type = Event::KeyPressed;
+ event.key.code = key;
+ event.key.alt = windowEvent.xkey.state & Mod1Mask;
+ event.key.control = windowEvent.xkey.state & ControlMask;
+ event.key.shift = windowEvent.xkey.state & ShiftMask;
+ event.key.system = windowEvent.xkey.state & Mod4Mask;
+ pushEvent(event);
+
+ // Generate a TextEntered event
+ if (!XFilterEvent(&windowEvent, None))
+ {
+ #ifdef X_HAVE_UTF8_STRING
+ if (m_inputContext)
+ {
+ Status status;
+ Uint8 keyBuffer[16];
+
+ int length = Xutf8LookupString(
+ m_inputContext,
+ &windowEvent.xkey,
+ reinterpret_cast<char*>(keyBuffer),
+ sizeof(keyBuffer),
+ NULL,
+ &status
+ );
+
+ if (length > 0)
+ {
+ Uint32 unicode = 0;
+ Utf8::decode(keyBuffer, keyBuffer + length, unicode, 0);
+ if (unicode != 0)
+ {
+ Event textEvent;
+ textEvent.type = Event::TextEntered;
+ textEvent.text.unicode = unicode;
+ pushEvent(textEvent);
+ }
+ }
+ }
+ else
+ #endif
+ {
+ static XComposeStatus status;
+ char keyBuffer[16];
+ if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
+ {
+ Event textEvent;
+ textEvent.type = Event::TextEntered;
+ textEvent.text.unicode = static_cast<Uint32>(keyBuffer[0]);
+ pushEvent(textEvent);
+ }
+ }
+ }
+
+ updateLastInputTime(windowEvent.xkey.time);
+
+ break;
+ }
+
+ // Key up event
+ case KeyRelease:
+ {
+ Keyboard::Key key = Keyboard::Unknown;
+
+ // Try each KeySym index (modifier group) until we get a match
+ for (int i = 0; i < 4; ++i)
+ {
+ // Get the SFML keyboard code from the keysym of the key that has been released
+ key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i));
+
+ if (key != Keyboard::Unknown)
+ break;
+ }
+
+ // Fill the event parameters
+ Event event;
+ event.type = Event::KeyReleased;
+ event.key.code = key;
+ event.key.alt = windowEvent.xkey.state & Mod1Mask;
+ event.key.control = windowEvent.xkey.state & ControlMask;
+ event.key.shift = windowEvent.xkey.state & ShiftMask;
+ event.key.system = windowEvent.xkey.state & Mod4Mask;
+ pushEvent(event);
+
+ break;
+ }
+
+ // Mouse button pressed
+ case ButtonPress:
+ {
+ // XXX: Why button 8 and 9?
+ // Because 4 and 5 are the vertical wheel and 6 and 7 are horizontal wheel ;)
+ unsigned int button = windowEvent.xbutton.button;
+ if ((button == Button1) ||
+ (button == Button2) ||
+ (button == Button3) ||
+ (button == 8) ||
+ (button == 9))
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.x = windowEvent.xbutton.x;
+ event.mouseButton.y = windowEvent.xbutton.y;
+ switch(button)
+ {
+ case Button1: event.mouseButton.button = Mouse::Left; break;
+ case Button2: event.mouseButton.button = Mouse::Middle; break;
+ case Button3: event.mouseButton.button = Mouse::Right; break;
+ case 8: event.mouseButton.button = Mouse::XButton1; break;
+ case 9: event.mouseButton.button = Mouse::XButton2; break;
+ }
+ pushEvent(event);
+ }
+
+ updateLastInputTime(windowEvent.xbutton.time);
+
+ break;
+ }
+
+ // Mouse button released
+ case ButtonRelease:
+ {
+ unsigned int button = windowEvent.xbutton.button;
+ if ((button == Button1) ||
+ (button == Button2) ||
+ (button == Button3) ||
+ (button == 8) ||
+ (button == 9))
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.x = windowEvent.xbutton.x;
+ event.mouseButton.y = windowEvent.xbutton.y;
+ switch(button)
+ {
+ case Button1: event.mouseButton.button = Mouse::Left; break;
+ case Button2: event.mouseButton.button = Mouse::Middle; break;
+ case Button3: event.mouseButton.button = Mouse::Right; break;
+ case 8: event.mouseButton.button = Mouse::XButton1; break;
+ case 9: event.mouseButton.button = Mouse::XButton2; break;
+ }
+ pushEvent(event);
+ }
+ else if ((button == Button4) || (button == Button5))
+ {
+ Event event;
+
+ event.type = Event::MouseWheelMoved;
+ event.mouseWheel.delta = (button == Button4) ? 1 : -1;
+ event.mouseWheel.x = windowEvent.xbutton.x;
+ event.mouseWheel.y = windowEvent.xbutton.y;
+ pushEvent(event);
+
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::VerticalWheel;
+ event.mouseWheelScroll.delta = (button == Button4) ? 1 : -1;
+ event.mouseWheelScroll.x = windowEvent.xbutton.x;
+ event.mouseWheelScroll.y = windowEvent.xbutton.y;
+ pushEvent(event);
+ }
+ else if ((button == 6) || (button == 7))
+ {
+ Event event;
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::HorizontalWheel;
+ event.mouseWheelScroll.delta = (button == 6) ? 1 : -1;
+ event.mouseWheelScroll.x = windowEvent.xbutton.x;
+ event.mouseWheelScroll.y = windowEvent.xbutton.y;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse moved
+ case MotionNotify:
+ {
+ Event event;
+ event.type = Event::MouseMoved;
+ event.mouseMove.x = windowEvent.xmotion.x;
+ event.mouseMove.y = windowEvent.xmotion.y;
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse entered
+ case EnterNotify:
+ {
+ if (windowEvent.xcrossing.mode == NotifyNormal)
+ {
+ Event event;
+ event.type = Event::MouseEntered;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse left
+ case LeaveNotify:
+ {
+ if (windowEvent.xcrossing.mode == NotifyNormal)
+ {
+ Event event;
+ event.type = Event::MouseLeft;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Window unmapped
+ case UnmapNotify:
+ {
+ if (windowEvent.xunmap.window == m_window)
+ m_windowMapped = false;
+
+ break;
+ }
+
+ // Window visibility change
+ case VisibilityNotify:
+ {
+ // We prefer using VisibilityNotify over MapNotify because
+ // some window managers like awesome don't internally flag a
+ // window as viewable even after it is mapped but before it
+ // is visible leading to certain function calls failing with
+ // an unviewable error if called before VisibilityNotify arrives
+
+ // Empirical testing on most widely used window managers shows
+ // that mapping a window will always lead to a VisibilityNotify
+ // event that is not VisibilityFullyObscured
+ if (windowEvent.xvisibility.window == m_window)
+ {
+ if (windowEvent.xvisibility.state != VisibilityFullyObscured)
+ m_windowMapped = true;
+ }
+
+ break;
+ }
+
+ // Window property change
+ case PropertyNotify:
+ {
+ if (!m_lastInputTime)
+ m_lastInputTime = windowEvent.xproperty.time;
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplX11::checkXRandR(int& xRandRMajor, int& xRandRMinor)
+{
+ // Check if the XRandR extension is present
+ int version;
+ if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
+ {
+ err() << "XRandR extension is not supported" << std::endl;
+ return false;
+ }
+
+ // Check XRandR version, 1.2 required
+ if (!XRRQueryVersion(m_display, &xRandRMajor, &xRandRMinor) || xRandRMajor < 1 || (xRandRMajor == 1 && xRandRMinor < 2 ))
+ {
+ err() << "XRandR is too old" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+RROutput WindowImplX11::getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor)
+{
+ // if xRandR version >= 1.3 get the primary screen else take the first screen
+ if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
+ {
+ RROutput output = XRRGetOutputPrimary(m_display, rootWindow);
+
+ // Check if returned output is valid, otherwise use the first screen
+ if (output == None)
+ return res->outputs[0];
+ else
+ return output;
+ }
+
+ // xRandr version can't get the primary screen, use the first screen
+ return res->outputs[0];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplX11::getPrimaryMonitorPosition()
+{
+ Vector2i monitorPosition;
+
+ // Get root window
+ ::Window rootWindow = RootWindow(m_display, m_screen);
+
+ // Get the screen resources
+ XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow);
+ if (!res)
+ {
+ err() << "Failed to get the current screen resources for.primary monitor position" << std::endl;
+ return monitorPosition;
+ }
+
+ // Get xRandr version
+ int xRandRMajor, xRandRMinor;
+ if (!checkXRandR(xRandRMajor, xRandRMinor))
+ xRandRMajor = xRandRMinor = 0;
+
+ RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor);
+
+ // Get output info from output
+ XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output);
+ if (!outputInfo || outputInfo->connection == RR_Disconnected)
+ {
+ XRRFreeScreenResources(res);
+
+ // If outputInfo->connection == RR_Disconnected, free output info
+ if (outputInfo)
+ XRRFreeOutputInfo(outputInfo);
+
+ err() << "Failed to get output info for.primary monitor position" << std::endl;
+ return monitorPosition;
+ }
+
+ // Retreive current RRMode, screen position and rotation
+ XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc);
+ if (!crtcInfo)
+ {
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(outputInfo);
+ err() << "Failed to get crtc info for.primary monitor position" << std::endl;
+ return monitorPosition;
+ }
+
+ monitorPosition.x = crtcInfo->x;
+ monitorPosition.y = crtcInfo->y;
+
+ XRRFreeCrtcInfo(crtcInfo);
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeScreenResources(res);
+
+ return monitorPosition;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp
new file mode 100644
index 0000000..a025a1a
--- /dev/null
+++ b/src/SFML/Window/Unix/WindowImplX11.hpp
@@ -0,0 +1,330 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_WINDOWIMPLX11_HPP
+#define SFML_WINDOWIMPLX11_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
+#include <X11/Xlib.h>
+#include <deque>
+#include <X11/extensions/Xrandr.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (X11) implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplX11 : public WindowImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplX11(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style (resizable, fixed, or fullscren)
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplX11();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Grab or release the mouse cursor
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the WM to make the current window active
+ ///
+ ////////////////////////////////////////////////////////////
+ void grabFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set fullscreen video mode
+ ///
+ /// \param Mode video mode to switch to
+ ///
+ ////////////////////////////////////////////////////////////
+ void setVideoMode(const VideoMode& mode);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Reset to desktop video mode
+ ///
+ ////////////////////////////////////////////////////////////
+ void resetVideoMode();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Switch to fullscreen mode
+ ///
+ ////////////////////////////////////////////////////////////
+ void switchToFullscreen();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the WM protocols we support
+ ///
+ ////////////////////////////////////////////////////////////
+ void setProtocols();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the last time we received user input
+ ///
+ /// \param time Last time we received user input
+ ///
+ ////////////////////////////////////////////////////////////
+ void updateLastInputTime(::Time time);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Do some common initializations after the window has been created
+ ///
+ ////////////////////////////////////////////////////////////
+ void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a transparent mouse cursor
+ ///
+ ////////////////////////////////////////////////////////////
+ void createHiddenCursor();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Cleanup graphical resources attached to the window
+ ///
+ ////////////////////////////////////////////////////////////
+ void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process an incoming event from the window
+ ///
+ /// \param windowEvent Event which has been received
+ ///
+ /// \return True if the event was processed, false if it was discarded
+ ///
+ ////////////////////////////////////////////////////////////
+ bool processEvent(XEvent& windowEvent);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a valid version of XRandR extension is present
+ ///
+ /// \param xRandRMajor XRandR major version
+ /// \param xRandRMinor XRandR minor version
+ ///
+ /// \return True if a valid XRandR version found, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ bool checkXRandR(int& xRandRMajor, int& xRandRMinor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the RROutput of the primary monitor
+ ///
+ /// \param rootWindow the root window
+ /// \param res screen resources
+ /// \param xRandRMajor XRandR major version
+ /// \param xRandRMinor XRandR minor version
+ ///
+ /// \return RROutput of the primary monitor
+ ///
+ ////////////////////////////////////////////////////////////
+ RROutput getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get coordinates of the primary monitor
+ ///
+ /// \return Position of the primary monitor
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector2i getPrimaryMonitorPosition();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Window m_window; ///< X identifier defining our window
+ ::Display* m_display; ///< Pointer to the display
+ int m_screen; ///< Screen identifier
+ XIM m_inputMethod; ///< Input method linked to the X display
+ XIC m_inputContext; ///< Input context used to get unicode input in our window
+ std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window
+ bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
+ int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
+ RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen
+ ::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
+ ::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
+ bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
+ Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
+ bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
+ bool m_fullscreen; ///< Is the window in fullscreen?
+ bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
+ bool m_windowMapped; ///< Has the window been mapped by the window manager?
+ Pixmap m_iconPixmap; ///< The current icon pixmap if in use
+ Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use
+ ::Time m_lastInputTime; ///< Last time we received user input
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPLX11_HPP
diff --git a/src/SFML/Window/VideoMode.cpp b/src/SFML/Window/VideoMode.cpp
new file mode 100644
index 0000000..12c3801
--- /dev/null
+++ b/src/SFML/Window/VideoMode.cpp
@@ -0,0 +1,146 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <algorithm>
+#include <functional>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+VideoMode::VideoMode() :
+width (0),
+height (0),
+bitsPerPixel(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode::VideoMode(unsigned int modeWidth, unsigned int modeHeight, unsigned int modeBitsPerPixel) :
+width (modeWidth),
+height (modeHeight),
+bitsPerPixel(modeBitsPerPixel)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoMode::getDesktopMode()
+{
+ // Directly forward to the OS-specific implementation
+ return priv::VideoModeImpl::getDesktopMode();
+}
+
+
+////////////////////////////////////////////////////////////
+const std::vector<VideoMode>& VideoMode::getFullscreenModes()
+{
+ static std::vector<VideoMode> modes;
+
+ // Populate the array on first call
+ if (modes.empty())
+ {
+ modes = priv::VideoModeImpl::getFullscreenModes();
+ std::sort(modes.begin(), modes.end(), std::greater<VideoMode>());
+ }
+
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+bool VideoMode::isValid() const
+{
+ const std::vector<VideoMode>& modes = getFullscreenModes();
+
+ return std::find(modes.begin(), modes.end(), *this) != modes.end();
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator ==(const VideoMode& left, const VideoMode& right)
+{
+ return (left.width == right.width) &&
+ (left.height == right.height) &&
+ (left.bitsPerPixel == right.bitsPerPixel);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator !=(const VideoMode& left, const VideoMode& right)
+{
+ return !(left == right);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <(const VideoMode& left, const VideoMode& right)
+{
+ if (left.bitsPerPixel == right.bitsPerPixel)
+ {
+ if (left.width == right.width)
+ {
+ return left.height < right.height;
+ }
+ else
+ {
+ return left.width < right.width;
+ }
+ }
+ else
+ {
+ return left.bitsPerPixel < right.bitsPerPixel;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >(const VideoMode& left, const VideoMode& right)
+{
+ return right < left;
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator <=(const VideoMode& left, const VideoMode& right)
+{
+ return !(right < left);
+}
+
+
+////////////////////////////////////////////////////////////
+bool operator >=(const VideoMode& left, const VideoMode& right)
+{
+ return !(left < right);
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/VideoModeImpl.hpp b/src/SFML/Window/VideoModeImpl.hpp
new file mode 100644
index 0000000..7371472
--- /dev/null
+++ b/src/SFML/Window/VideoModeImpl.hpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_VIDEOMODEIMPL_HPP
+#define SFML_VIDEOMODEIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoMode.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief OS-specific implementation of video modes functions
+///
+////////////////////////////////////////////////////////////
+class VideoModeImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the list of all the supported fullscreen video modes
+ ///
+ /// \return Array filled with the fullscreen video modes
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::vector<VideoMode> getFullscreenModes();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current desktop video mode
+ ///
+ /// \return Current desktop video mode
+ ///
+ ////////////////////////////////////////////////////////////
+ static VideoMode getDesktopMode();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_VIDEOMODEIMPL_HPP
diff --git a/src/SFML/Window/Win32/ClipboardImpl.cpp b/src/SFML/Window/Win32/ClipboardImpl.cpp
new file mode 100644
index 0000000..13fd06f
--- /dev/null
+++ b/src/SFML/Window/Win32/ClipboardImpl.cpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Win32/ClipboardImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <iostream>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getString()
+{
+ String text;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
+ {
+ std::cerr << "Failed to get the clipboard data in Unicode format." << std::endl;
+ return text;
+ }
+
+ if (!OpenClipboard(NULL))
+ {
+ std::cerr << "Failed to open the Win32 clipboard." << std::endl;
+ return text;
+ }
+
+ HANDLE clipboard_handle = GetClipboardData(CF_UNICODETEXT);
+
+ if (!clipboard_handle)
+ {
+ std::cerr << "Failed to get Win32 handle for clipboard content." << std::endl;
+ CloseClipboard();
+ return text;
+ }
+
+ text = String(static_cast<wchar_t*>(GlobalLock(clipboard_handle)));
+ GlobalUnlock(clipboard_handle);
+
+ CloseClipboard();
+ return text;
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setString(const String& text)
+{
+ if (!OpenClipboard(NULL))
+ {
+ std::cerr << "Failed to open the Win32 clipboard." << std::endl;
+ return;
+ }
+
+ if (!EmptyClipboard())
+ {
+ std::cerr << "Failed to empty the Win32 clipboard." << std::endl;
+ return;
+ }
+
+ // Create a Win32-compatible string
+ size_t string_size = (text.getSize() + 1) * sizeof(WCHAR);
+ HANDLE string_handle = GlobalAlloc(GMEM_MOVEABLE, string_size);
+
+ if (string_handle)
+ {
+ memcpy(GlobalLock(string_handle), text.toWideString().data(), string_size);
+ GlobalUnlock(string_handle);
+ SetClipboardData(CF_UNICODETEXT, string_handle);
+ }
+
+ CloseClipboard();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/ClipboardImpl.hpp b/src/SFML/Window/Win32/ClipboardImpl.hpp
new file mode 100644
index 0000000..c42ec5e
--- /dev/null
+++ b/src/SFML/Window/Win32/ClipboardImpl.hpp
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPLWIN32_HPP
+#define SFML_CLIPBOARDIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class ClipboardImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \param text sf::String object containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARDIMPLWIN32_HPP
diff --git a/src/SFML/Window/Win32/CursorImpl.cpp b/src/SFML/Window/Win32/CursorImpl.cpp
new file mode 100755
index 0000000..d1913d6
--- /dev/null
+++ b/src/SFML/Window/Win32/CursorImpl.cpp
@@ -0,0 +1,188 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Win32/CursorImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <cstring>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+CursorImpl::CursorImpl() :
+m_cursor(NULL)
+{
+ // That's it.
+}
+
+
+////////////////////////////////////////////////////////////
+CursorImpl::~CursorImpl()
+{
+ release();
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ release();
+
+ // Create the bitmap that will hold our color data
+ BITMAPV5HEADER bitmapHeader;
+ std::memset(&bitmapHeader, 0, sizeof(BITMAPV5HEADER));
+
+ bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
+ bitmapHeader.bV5Width = size.x;
+ bitmapHeader.bV5Height = -static_cast<int>(size.y); // Negative indicates origin is in upper-left corner
+ bitmapHeader.bV5Planes = 1;
+ bitmapHeader.bV5BitCount = 32;
+ bitmapHeader.bV5Compression = BI_BITFIELDS;
+ bitmapHeader.bV5RedMask = 0x00ff0000;
+ bitmapHeader.bV5GreenMask = 0x0000ff00;
+ bitmapHeader.bV5BlueMask = 0x000000ff;
+ bitmapHeader.bV5AlphaMask = 0xff000000;
+
+ Uint32* bitmapData = NULL;
+
+ HDC screenDC = GetDC(NULL);
+ HBITMAP color = CreateDIBSection(
+ screenDC,
+ reinterpret_cast<const BITMAPINFO*>(&bitmapHeader),
+ DIB_RGB_COLORS,
+ reinterpret_cast<void**>(&bitmapData),
+ NULL,
+ 0
+ );
+ ReleaseDC(NULL, screenDC);
+
+ if (!color)
+ {
+ err() << "Failed to create cursor color bitmap" << std::endl;
+ return false;
+ }
+
+ // Fill our bitmap with the cursor color data
+ // We'll have to swap the red and blue channels here
+ Uint32* bitmapOffset = bitmapData;
+ for (std::size_t remaining = size.x * size.y; remaining > 0; --remaining, pixels += 4)
+ {
+ *bitmapOffset++ = (pixels[3] << 24) | (pixels[0] << 16) | (pixels[1] << 8) | pixels[2];
+ }
+
+ // Create a dummy mask bitmap (it won't be used)
+ HBITMAP mask = CreateBitmap(size.x, size.y, 1, 1, NULL);
+
+ if (!mask)
+ {
+ DeleteObject(color);
+ err() << "Failed to create cursor mask bitmap" << std::endl;
+ return false;
+ }
+
+ // Create the structure that describes our cursor
+ ICONINFO cursorInfo;
+ std::memset(&cursorInfo, 0, sizeof(ICONINFO));
+
+ cursorInfo.fIcon = FALSE; // This is a cursor and not an icon
+ cursorInfo.xHotspot = hotspot.x;
+ cursorInfo.yHotspot = hotspot.y;
+ cursorInfo.hbmColor = color;
+ cursorInfo.hbmMask = mask;
+
+ // Create the cursor
+ m_cursor = reinterpret_cast<HCURSOR>(CreateIconIndirect(&cursorInfo));
+
+ // The data has been copied into the cursor, so get rid of these
+ DeleteObject(color);
+ DeleteObject(mask);
+
+ if (m_cursor)
+ {
+ return true;
+ }
+ else
+ {
+ err() << "Failed to create cursor from bitmaps" << std::endl;
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromSystem(Cursor::Type type)
+{
+ release();
+
+ LPCTSTR shape;
+ switch (type)
+ {
+ case Cursor::Arrow: shape = IDC_ARROW; break;
+ case Cursor::ArrowWait: shape = IDC_APPSTARTING; break;
+ case Cursor::Wait: shape = IDC_WAIT; break;
+ case Cursor::Text: shape = IDC_IBEAM; break;
+ case Cursor::Hand: shape = IDC_HAND; break;
+ case Cursor::SizeHorizontal: shape = IDC_SIZEWE; break;
+ case Cursor::SizeVertical: shape = IDC_SIZENS; break;
+ case Cursor::SizeTopLeftBottomRight: shape = IDC_SIZENWSE; break;
+ case Cursor::SizeBottomLeftTopRight: shape = IDC_SIZENESW; break;
+ case Cursor::SizeAll: shape = IDC_SIZEALL; break;
+ case Cursor::Cross: shape = IDC_CROSS; break;
+ case Cursor::Help: shape = IDC_HELP; break;
+ case Cursor::NotAllowed: shape = IDC_NO; break;
+ }
+
+ // Create a copy of the shared system cursor that we can destroy later
+ m_cursor = CopyCursor(LoadCursor(NULL, shape));
+
+ if (m_cursor)
+ {
+ return true;
+ }
+ else
+ {
+ err() << "Could not create copy of a system cursor" << std::endl;
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void CursorImpl::release()
+{
+ if (m_cursor) {
+ DestroyCursor(m_cursor);
+ m_cursor = NULL;
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/Win32/CursorImpl.hpp b/src/SFML/Window/Win32/CursorImpl.hpp
new file mode 100755
index 0000000..602f223
--- /dev/null
+++ b/src/SFML/Window/Win32/CursorImpl.hpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSORIMPLWIN32_HPP
+#define SFML_CURSORIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+
+#include <windows.h>
+
+namespace sf
+{
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Win32 implementation of Cursor
+///
+////////////////////////////////////////////////////////////
+class CursorImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Refer to sf::Cursor::Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// Refer to sf::Cursor::~Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ ~CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// Refer to sf::Cursor::loadFromPixels().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Refer to sf::Cursor::loadFromSystem().
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Cursor::Type type);
+
+private:
+
+ friend class WindowImplWin32;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Release the cursor, if we have loaded one.
+ ///
+ ////////////////////////////////////////////////////////////
+ void release();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ HCURSOR m_cursor;
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_CUSROSIMPLWIN32_HPP
+
diff --git a/src/SFML/Window/Win32/InputImpl.cpp b/src/SFML/Window/Win32/InputImpl.cpp
new file mode 100644
index 0000000..0482740
--- /dev/null
+++ b/src/SFML/Window/Win32/InputImpl.cpp
@@ -0,0 +1,256 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#ifdef _WIN32_WINDOWS
+ #undef _WIN32_WINDOWS
+#endif
+#ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+#endif
+#define _WIN32_WINDOWS 0x0501
+#define _WIN32_WINNT 0x0501
+#include <SFML/Window/Window.hpp>
+#include <SFML/Window/Win32/InputImpl.hpp>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ int vkey = 0;
+ switch (key)
+ {
+ default: vkey = 0; break;
+ case Keyboard::A: vkey = 'A'; break;
+ case Keyboard::B: vkey = 'B'; break;
+ case Keyboard::C: vkey = 'C'; break;
+ case Keyboard::D: vkey = 'D'; break;
+ case Keyboard::E: vkey = 'E'; break;
+ case Keyboard::F: vkey = 'F'; break;
+ case Keyboard::G: vkey = 'G'; break;
+ case Keyboard::H: vkey = 'H'; break;
+ case Keyboard::I: vkey = 'I'; break;
+ case Keyboard::J: vkey = 'J'; break;
+ case Keyboard::K: vkey = 'K'; break;
+ case Keyboard::L: vkey = 'L'; break;
+ case Keyboard::M: vkey = 'M'; break;
+ case Keyboard::N: vkey = 'N'; break;
+ case Keyboard::O: vkey = 'O'; break;
+ case Keyboard::P: vkey = 'P'; break;
+ case Keyboard::Q: vkey = 'Q'; break;
+ case Keyboard::R: vkey = 'R'; break;
+ case Keyboard::S: vkey = 'S'; break;
+ case Keyboard::T: vkey = 'T'; break;
+ case Keyboard::U: vkey = 'U'; break;
+ case Keyboard::V: vkey = 'V'; break;
+ case Keyboard::W: vkey = 'W'; break;
+ case Keyboard::X: vkey = 'X'; break;
+ case Keyboard::Y: vkey = 'Y'; break;
+ case Keyboard::Z: vkey = 'Z'; break;
+ case Keyboard::Num0: vkey = '0'; break;
+ case Keyboard::Num1: vkey = '1'; break;
+ case Keyboard::Num2: vkey = '2'; break;
+ case Keyboard::Num3: vkey = '3'; break;
+ case Keyboard::Num4: vkey = '4'; break;
+ case Keyboard::Num5: vkey = '5'; break;
+ case Keyboard::Num6: vkey = '6'; break;
+ case Keyboard::Num7: vkey = '7'; break;
+ case Keyboard::Num8: vkey = '8'; break;
+ case Keyboard::Num9: vkey = '9'; break;
+ case Keyboard::Escape: vkey = VK_ESCAPE; break;
+ case Keyboard::LControl: vkey = VK_LCONTROL; break;
+ case Keyboard::LShift: vkey = VK_LSHIFT; break;
+ case Keyboard::LAlt: vkey = VK_LMENU; break;
+ case Keyboard::LSystem: vkey = VK_LWIN; break;
+ case Keyboard::RControl: vkey = VK_RCONTROL; break;
+ case Keyboard::RShift: vkey = VK_RSHIFT; break;
+ case Keyboard::RAlt: vkey = VK_RMENU; break;
+ case Keyboard::RSystem: vkey = VK_RWIN; break;
+ case Keyboard::Menu: vkey = VK_APPS; break;
+ case Keyboard::LBracket: vkey = VK_OEM_4; break;
+ case Keyboard::RBracket: vkey = VK_OEM_6; break;
+ case Keyboard::Semicolon: vkey = VK_OEM_1; break;
+ case Keyboard::Comma: vkey = VK_OEM_COMMA; break;
+ case Keyboard::Period: vkey = VK_OEM_PERIOD; break;
+ case Keyboard::Quote: vkey = VK_OEM_7; break;
+ case Keyboard::Slash: vkey = VK_OEM_2; break;
+ case Keyboard::Backslash: vkey = VK_OEM_5; break;
+ case Keyboard::Tilde: vkey = VK_OEM_3; break;
+ case Keyboard::Equal: vkey = VK_OEM_PLUS; break;
+ case Keyboard::Hyphen: vkey = VK_OEM_MINUS; break;
+ case Keyboard::Space: vkey = VK_SPACE; break;
+ case Keyboard::Enter: vkey = VK_RETURN; break;
+ case Keyboard::Backspace: vkey = VK_BACK; break;
+ case Keyboard::Tab: vkey = VK_TAB; break;
+ case Keyboard::PageUp: vkey = VK_PRIOR; break;
+ case Keyboard::PageDown: vkey = VK_NEXT; break;
+ case Keyboard::End: vkey = VK_END; break;
+ case Keyboard::Home: vkey = VK_HOME; break;
+ case Keyboard::Insert: vkey = VK_INSERT; break;
+ case Keyboard::Delete: vkey = VK_DELETE; break;
+ case Keyboard::Add: vkey = VK_ADD; break;
+ case Keyboard::Subtract: vkey = VK_SUBTRACT; break;
+ case Keyboard::Multiply: vkey = VK_MULTIPLY; break;
+ case Keyboard::Divide: vkey = VK_DIVIDE; break;
+ case Keyboard::Left: vkey = VK_LEFT; break;
+ case Keyboard::Right: vkey = VK_RIGHT; break;
+ case Keyboard::Up: vkey = VK_UP; break;
+ case Keyboard::Down: vkey = VK_DOWN; break;
+ case Keyboard::Numpad0: vkey = VK_NUMPAD0; break;
+ case Keyboard::Numpad1: vkey = VK_NUMPAD1; break;
+ case Keyboard::Numpad2: vkey = VK_NUMPAD2; break;
+ case Keyboard::Numpad3: vkey = VK_NUMPAD3; break;
+ case Keyboard::Numpad4: vkey = VK_NUMPAD4; break;
+ case Keyboard::Numpad5: vkey = VK_NUMPAD5; break;
+ case Keyboard::Numpad6: vkey = VK_NUMPAD6; break;
+ case Keyboard::Numpad7: vkey = VK_NUMPAD7; break;
+ case Keyboard::Numpad8: vkey = VK_NUMPAD8; break;
+ case Keyboard::Numpad9: vkey = VK_NUMPAD9; break;
+ case Keyboard::F1: vkey = VK_F1; break;
+ case Keyboard::F2: vkey = VK_F2; break;
+ case Keyboard::F3: vkey = VK_F3; break;
+ case Keyboard::F4: vkey = VK_F4; break;
+ case Keyboard::F5: vkey = VK_F5; break;
+ case Keyboard::F6: vkey = VK_F6; break;
+ case Keyboard::F7: vkey = VK_F7; break;
+ case Keyboard::F8: vkey = VK_F8; break;
+ case Keyboard::F9: vkey = VK_F9; break;
+ case Keyboard::F10: vkey = VK_F10; break;
+ case Keyboard::F11: vkey = VK_F11; break;
+ case Keyboard::F12: vkey = VK_F12; break;
+ case Keyboard::F13: vkey = VK_F13; break;
+ case Keyboard::F14: vkey = VK_F14; break;
+ case Keyboard::F15: vkey = VK_F15; break;
+ case Keyboard::Pause: vkey = VK_PAUSE; break;
+ }
+
+ return (GetAsyncKeyState(vkey) & 0x8000) != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ int vkey = 0;
+ switch (button)
+ {
+ case Mouse::Left: vkey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON; break;
+ case Mouse::Right: vkey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON; break;
+ case Mouse::Middle: vkey = VK_MBUTTON; break;
+ case Mouse::XButton1: vkey = VK_XBUTTON1; break;
+ case Mouse::XButton2: vkey = VK_XBUTTON2; break;
+ default: vkey = 0; break;
+ }
+
+ return (GetAsyncKeyState(vkey) & 0x8000) != 0;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ POINT point;
+ GetCursorPos(&point);
+ return Vector2i(point.x, point.y);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ POINT point;
+ GetCursorPos(&point);
+ ScreenToClient(handle, &point);
+ return Vector2i(point.x, point.y);
+ }
+ else
+ {
+ return Vector2i();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ SetCursorPos(position.x, position.y);
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ POINT point = {position.x, position.y};
+ ClientToScreen(handle, &point);
+ SetCursorPos(point.x, point.y);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int /*finger*/)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*relativeTo*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/InputImpl.hpp b/src/SFML/Window/Win32/InputImpl.hpp
new file mode 100644
index 0000000..17ac482
--- /dev/null
+++ b/src/SFML/Window/Win32/InputImpl.hpp
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_INPUTIMPLWIN32_HPP
+#define SFML_INPUTIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(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.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 isTouchDown(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 getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLWIN32_HPP
diff --git a/src/SFML/Window/Win32/JoystickImpl.cpp b/src/SFML/Window/Win32/JoystickImpl.cpp
new file mode 100644
index 0000000..1b98d9d
--- /dev/null
+++ b/src/SFML/Window/Win32/JoystickImpl.cpp
@@ -0,0 +1,920 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/Clock.hpp>
+#include <SFML/System/Err.hpp>
+#include <windows.h>
+#include <tchar.h>
+#include <regstr.h>
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+#include <sstream>
+#include <string>
+#include <vector>
+
+
+
+////////////////////////////////////////////////////////////
+// DirectInput
+////////////////////////////////////////////////////////////
+
+
+#ifndef DIDFT_OPTIONAL
+#define DIDFT_OPTIONAL 0x80000000
+#endif
+
+
+namespace
+{
+ namespace guids
+ {
+ const GUID IID_IDirectInput8W = {0xbf798031, 0x483a, 0x4da2, {0xaa, 0x99, 0x5d, 0x64, 0xed, 0x36, 0x97, 0x00}};
+
+ const GUID GUID_XAxis = {0xa36d02e0, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ const GUID GUID_YAxis = {0xa36d02e1, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ const GUID GUID_ZAxis = {0xa36d02e2, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ const GUID GUID_RzAxis = {0xa36d02e3, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ const GUID GUID_Slider = {0xa36d02e4, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+
+ const GUID GUID_POV = {0xa36d02f2, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+
+ const GUID GUID_RxAxis = {0xa36d02f4, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ const GUID GUID_RyAxis = {0xa36d02f5, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
+ }
+
+ HMODULE dinput8dll = NULL;
+ IDirectInput8W* directInput = NULL;
+
+ struct JoystickRecord
+ {
+ GUID guid;
+ unsigned int index;
+ bool plugged;
+ };
+
+ typedef std::vector<JoystickRecord> JoystickList;
+ JoystickList joystickList;
+}
+
+
+////////////////////////////////////////////////////////////
+// Legacy joystick API
+////////////////////////////////////////////////////////////
+namespace
+{
+ struct ConnectionCache
+ {
+ ConnectionCache() : connected(false) {}
+ bool connected;
+ sf::Clock timer;
+ };
+ const sf::Time connectionRefreshDelay = sf::milliseconds(500);
+
+ ConnectionCache connectionCache[sf::Joystick::Count];
+
+ // If true, will only update when WM_DEVICECHANGE message is received
+ bool lazyUpdates = false;
+
+ // Get a system error string from an error code
+ std::string getErrorString(DWORD error)
+ {
+ PTCHAR buffer;
+
+ if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, reinterpret_cast<PTCHAR>(&buffer), 0, NULL) == 0)
+ return "Unknown error.";
+
+ sf::String message = buffer;
+ LocalFree(buffer);
+ return message.toAnsiString();
+ }
+
+ // Get the joystick's name
+ sf::String getDeviceName(unsigned int index, JOYCAPS caps)
+ {
+ // Give the joystick a default name
+ sf::String joystickDescription = "Unknown Joystick";
+
+ LONG result;
+ HKEY rootKey;
+ HKEY currentKey;
+ std::basic_string<TCHAR> subkey;
+
+ subkey = REGSTR_PATH_JOYCONFIG;
+ subkey += TEXT('\\');
+ subkey += caps.szRegKey;
+ subkey += TEXT('\\');
+ subkey += REGSTR_KEY_JOYCURR;
+
+ rootKey = HKEY_CURRENT_USER;
+ result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, &currentKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ rootKey = HKEY_LOCAL_MACHINE;
+ result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, &currentKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ sf::err() << "Unable to open registry for joystick at index " << index << ": " << getErrorString(result) << std::endl;
+ return joystickDescription;
+ }
+ }
+
+ std::basic_ostringstream<TCHAR> indexString;
+ indexString << index + 1;
+
+ subkey = TEXT("Joystick");
+ subkey += indexString.str();
+ subkey += REGSTR_VAL_JOYOEMNAME;
+
+ TCHAR keyData[256];
+ DWORD keyDataSize = sizeof(keyData);
+
+ result = RegQueryValueEx(currentKey, subkey.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(keyData), &keyDataSize);
+ RegCloseKey(currentKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ sf::err() << "Unable to query registry key for joystick at index " << index << ": " << getErrorString(result) << std::endl;
+ return joystickDescription;
+ }
+
+ subkey = REGSTR_PATH_JOYOEM;
+ subkey += TEXT('\\');
+ subkey.append(keyData, keyDataSize / sizeof(TCHAR));
+
+ result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, &currentKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ sf::err() << "Unable to open registry key for joystick at index " << index << ": " << getErrorString(result) << std::endl;
+ return joystickDescription;
+ }
+
+ keyDataSize = sizeof(keyData);
+
+ result = RegQueryValueEx(currentKey, REGSTR_VAL_JOYOEMNAME, NULL, NULL, reinterpret_cast<LPBYTE>(keyData), &keyDataSize);
+ RegCloseKey(currentKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ sf::err() << "Unable to query name for joystick at index " << index << ": " << getErrorString(result) << std::endl;
+ return joystickDescription;
+ }
+
+ keyData[255] = TEXT('\0'); // Ensure null terminator in case the data is too long.
+ joystickDescription = keyData;
+
+ return joystickDescription;
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // Try to initialize DirectInput
+ initializeDInput();
+
+ if (!directInput)
+ err() << "DirectInput not available, falling back to Windows joystick API" << std::endl;
+
+ // Perform the initial scan and populate the connection cache
+ updateConnections();
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // Clean up DirectInput
+ cleanupDInput();
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ if (directInput)
+ return isConnectedDInput(index);
+
+ ConnectionCache& cache = connectionCache[index];
+ if (!lazyUpdates && cache.timer.getElapsedTime() > connectionRefreshDelay)
+ {
+ JOYINFOEX joyInfo;
+ joyInfo.dwSize = sizeof(joyInfo);
+ joyInfo.dwFlags = 0;
+ cache.connected = joyGetPosEx(JOYSTICKID1 + index, &joyInfo) == JOYERR_NOERROR;
+
+ cache.timer.restart();
+ }
+ return cache.connected;
+}
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::setLazyUpdates(bool status)
+{
+ lazyUpdates = status;
+}
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::updateConnections()
+{
+ if (directInput)
+ return updateConnectionsDInput();
+
+ for (unsigned int i = 0; i < Joystick::Count; ++i)
+ {
+ JOYINFOEX joyInfo;
+ joyInfo.dwSize = sizeof(joyInfo);
+ joyInfo.dwFlags = 0;
+ ConnectionCache& cache = connectionCache[i];
+ cache.connected = joyGetPosEx(JOYSTICKID1 + i, &joyInfo) == JOYERR_NOERROR;
+
+ cache.timer.restart();
+ }
+}
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ if (directInput)
+ return openDInput(index);
+
+ // No explicit "open" action is required
+ m_index = JOYSTICKID1 + index;
+
+ // Store the joystick capabilities
+ bool success = joyGetDevCaps(m_index, &m_caps, sizeof(m_caps)) == JOYERR_NOERROR;
+
+ if (success)
+ {
+ m_identification.name = getDeviceName(m_index, m_caps);
+ m_identification.productId = m_caps.wPid;
+ m_identification.vendorId = m_caps.wMid;
+ }
+
+ return success;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ if (directInput)
+ closeDInput();
+}
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ if (directInput)
+ return getCapabilitiesDInput();
+
+ JoystickCaps caps;
+
+ caps.buttonCount = m_caps.wNumButtons;
+ if (caps.buttonCount > Joystick::ButtonCount)
+ caps.buttonCount = Joystick::ButtonCount;
+
+ caps.axes[Joystick::X] = true;
+ caps.axes[Joystick::Y] = true;
+ caps.axes[Joystick::Z] = (m_caps.wCaps & JOYCAPS_HASZ) != 0;
+ caps.axes[Joystick::R] = (m_caps.wCaps & JOYCAPS_HASR) != 0;
+ caps.axes[Joystick::U] = (m_caps.wCaps & JOYCAPS_HASU) != 0;
+ caps.axes[Joystick::V] = (m_caps.wCaps & JOYCAPS_HASV) != 0;
+ caps.axes[Joystick::PovX] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
+ caps.axes[Joystick::PovY] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::update()
+{
+ if (directInput)
+ return updateDInput();
+
+ JoystickState state;
+
+ // Get the current joystick state
+ JOYINFOEX pos;
+ pos.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU | JOY_RETURNV | JOY_RETURNBUTTONS;
+ pos.dwFlags |= (m_caps.wCaps & JOYCAPS_POVCTS) ? JOY_RETURNPOVCTS : JOY_RETURNPOV;
+ pos.dwSize = sizeof(JOYINFOEX);
+ if (joyGetPosEx(m_index, &pos) == JOYERR_NOERROR)
+ {
+ // The joystick is connected
+ state.connected = true;
+
+ // Axes
+ state.axes[Joystick::X] = (pos.dwXpos - (m_caps.wXmax + m_caps.wXmin) / 2.f) * 200.f / (m_caps.wXmax - m_caps.wXmin);
+ state.axes[Joystick::Y] = (pos.dwYpos - (m_caps.wYmax + m_caps.wYmin) / 2.f) * 200.f / (m_caps.wYmax - m_caps.wYmin);
+ state.axes[Joystick::Z] = (pos.dwZpos - (m_caps.wZmax + m_caps.wZmin) / 2.f) * 200.f / (m_caps.wZmax - m_caps.wZmin);
+ state.axes[Joystick::R] = (pos.dwRpos - (m_caps.wRmax + m_caps.wRmin) / 2.f) * 200.f / (m_caps.wRmax - m_caps.wRmin);
+ state.axes[Joystick::U] = (pos.dwUpos - (m_caps.wUmax + m_caps.wUmin) / 2.f) * 200.f / (m_caps.wUmax - m_caps.wUmin);
+ state.axes[Joystick::V] = (pos.dwVpos - (m_caps.wVmax + m_caps.wVmin) / 2.f) * 200.f / (m_caps.wVmax - m_caps.wVmin);
+
+ // Special case for POV, it is given as an angle
+ if (pos.dwPOV != 0xFFFF)
+ {
+ float angle = pos.dwPOV / 18000.f * 3.141592654f;
+ state.axes[Joystick::PovX] = std::sin(angle) * 100;
+ state.axes[Joystick::PovY] = std::cos(angle) * 100;
+ }
+ else
+ {
+ state.axes[Joystick::PovX] = 0;
+ state.axes[Joystick::PovY] = 0;
+ }
+
+ // Buttons
+ for (unsigned int i = 0; i < Joystick::ButtonCount; ++i)
+ state.buttons[i] = (pos.dwButtons & (1 << i)) != 0;
+ }
+
+ return state;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::initializeDInput()
+{
+ // Try to load dinput8.dll
+ dinput8dll = LoadLibraryA("dinput8.dll");
+
+ if (dinput8dll)
+ {
+ // Try to get the address of the DirectInput8Create entry point
+ typedef HRESULT(WINAPI *DirectInput8CreateFunc)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
+ DirectInput8CreateFunc directInput8Create = reinterpret_cast<DirectInput8CreateFunc>(GetProcAddress(dinput8dll, "DirectInput8Create"));
+
+ if (directInput8Create)
+ {
+ // Try to acquire a DirectInput 8.x interface
+ HRESULT result = directInput8Create(GetModuleHandleW(NULL), 0x0800, guids::IID_IDirectInput8W, reinterpret_cast<void**>(&directInput), NULL);
+
+ if (result)
+ {
+ // De-initialize everything
+ directInput = NULL;
+ FreeLibrary(dinput8dll);
+ dinput8dll = NULL;
+
+ err() << "Failed to initialize DirectInput: " << result << std::endl;
+ }
+ }
+ else
+ {
+ // Unload dinput8.dll
+ FreeLibrary(dinput8dll);
+ dinput8dll = NULL;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanupDInput()
+{
+ // Release the DirectInput interface
+ if (directInput)
+ {
+ directInput->Release();
+ directInput = NULL;
+ }
+
+ // Unload dinput8.dll
+ if (dinput8dll)
+ FreeLibrary(dinput8dll);
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnectedDInput(unsigned int index)
+{
+ // Check if a joystick with the given index is in the connected list
+ for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end(); ++i)
+ {
+ if (i->index == index)
+ return true;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::updateConnectionsDInput()
+{
+ // Clear plugged flags so we can determine which devices were added/removed
+ for (std::size_t i = 0; i < joystickList.size(); ++i)
+ joystickList[i].plugged = false;
+
+ // Enumerate devices
+ HRESULT result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, &JoystickImpl::deviceEnumerationCallback, NULL, DIEDFL_ATTACHEDONLY);
+
+ // Remove devices that were not connected during the enumeration
+ for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end();)
+ {
+ if (!i->plugged)
+ i = joystickList.erase(i);
+ else
+ ++i;
+ }
+
+ if (result)
+ {
+ err() << "Failed to enumerate DirectInput devices: " << result << std::endl;
+
+ return;
+ }
+
+ // Assign unused joystick indices to devices that were newly connected
+ for (unsigned int i = 0; i < Joystick::Count; ++i)
+ {
+ for (std::vector<JoystickRecord>::iterator j = joystickList.begin(); j != joystickList.end(); ++j)
+ {
+ if (j->index == i)
+ break;
+
+ if (j->index == Joystick::Count)
+ {
+ j->index = i;
+ break;
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::openDInput(unsigned int index)
+{
+ // Initialize DirectInput members
+ m_device = NULL;
+
+ for (int i = 0; i < Joystick::AxisCount; ++i)
+ m_axes[i] = -1;
+
+ for (int i = 0; i < Joystick::ButtonCount; ++i)
+ m_buttons[i] = -1;
+
+ std::memset(&m_deviceCaps, 0, sizeof(DIDEVCAPS));
+ m_deviceCaps.dwSize = sizeof(DIDEVCAPS);
+
+ // Search for a joystick with the given index in the connected list
+ for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end(); ++i)
+ {
+ if (i->index == index)
+ {
+ // Create device
+ HRESULT result = directInput->CreateDevice(i->guid, &m_device, NULL);
+
+ if (result)
+ {
+ err() << "Failed to create DirectInput device: " << result << std::endl;
+
+ return false;
+ }
+
+ static bool formatInitialized = false;
+ static DIDATAFORMAT format;
+
+ if (!formatInitialized)
+ {
+ const DWORD axisType = DIDFT_AXIS | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
+ const DWORD povType = DIDFT_POV | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
+ const DWORD buttonType = DIDFT_BUTTON | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
+
+ static DIOBJECTDATAFORMAT data[8 + 4 + sf::Joystick::ButtonCount];
+
+ data[0].pguid = &guids::GUID_XAxis;
+ data[0].dwOfs = DIJOFS_X;
+
+ data[1].pguid = &guids::GUID_YAxis;
+ data[1].dwOfs = DIJOFS_Y;
+
+ data[2].pguid = &guids::GUID_ZAxis;
+ data[2].dwOfs = DIJOFS_Z;
+
+ data[3].pguid = &guids::GUID_RxAxis;
+ data[3].dwOfs = DIJOFS_RX;
+
+ data[4].pguid = &guids::GUID_RyAxis;
+ data[4].dwOfs = DIJOFS_RY;
+
+ data[5].pguid = &guids::GUID_RzAxis;
+ data[5].dwOfs = DIJOFS_RZ;
+
+ data[6].pguid = &guids::GUID_Slider;
+ data[6].dwOfs = DIJOFS_SLIDER(0);
+
+ data[7].pguid = &guids::GUID_Slider;
+ data[7].dwOfs = DIJOFS_SLIDER(1);
+
+ for (int i = 0; i < 8; ++i)
+ {
+ data[i].dwType = axisType;
+ data[i].dwFlags = DIDOI_ASPECTPOSITION;
+ }
+
+ for (int i = 0; i < 4; ++i)
+ {
+ data[8 + i].pguid = &guids::GUID_POV;
+ data[8 + i].dwOfs = static_cast<DWORD>(DIJOFS_POV(i));
+ data[8 + i].dwType = povType;
+ data[8 + i].dwFlags = 0;
+ }
+
+ for (int i = 0; i < sf::Joystick::ButtonCount; ++i)
+ {
+ data[8 + 4 + i].pguid = NULL;
+ data[8 + 4 + i].dwOfs = static_cast<DWORD>(DIJOFS_BUTTON(i));
+ data[8 + 4 + i].dwType = buttonType;
+ data[8 + 4 + i].dwFlags = 0;
+ }
+
+ format.dwSize = sizeof(DIDATAFORMAT);
+ format.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
+ format.dwFlags = DIDFT_ABSAXIS;
+ format.dwDataSize = sizeof(DIJOYSTATE);
+ format.dwNumObjs = 8 + 4 + sf::Joystick::ButtonCount;
+ format.rgodf = data;
+
+ formatInitialized = true;
+ }
+
+ // Set device data format
+ result = m_device->SetDataFormat(&format);
+
+ if (result)
+ {
+ err() << "Failed to set DirectInput device data format: " << result << std::endl;
+
+ m_device->Release();
+ m_device = NULL;
+
+ return false;
+ }
+
+ // Get device capabilities
+ result = m_device->GetCapabilities(&m_deviceCaps);
+
+ if (result)
+ {
+ err() << "Failed to get DirectInput device capabilities: " << result << std::endl;
+
+ m_device->Release();
+ m_device = NULL;
+
+ return false;
+ }
+
+ // Set axis mode to absolute
+ DIPROPDWORD property;
+ std::memset(&property, 0, sizeof(property));
+ property.diph.dwSize = sizeof(property);
+ property.diph.dwHeaderSize = sizeof(property.diph);
+ property.diph.dwHow = DIPH_DEVICE;
+ property.dwData = DIPROPAXISMODE_ABS;
+
+ result = m_device->SetProperty(DIPROP_AXISMODE, &property.diph);
+
+ if (result)
+ {
+ err() << "Failed to set DirectInput device axis mode: " << result << std::endl;
+
+ m_device->Release();
+ m_device = NULL;
+
+ return false;
+ }
+
+ // Enumerate device objects (axes/povs/buttons)
+ result = m_device->EnumObjects(&JoystickImpl::deviceObjectEnumerationCallback, this, DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
+
+ if (result)
+ {
+ err() << "Failed to enumerate DirectInput device objects: " << result << std::endl;
+
+ m_device->Release();
+ m_device = NULL;
+
+ return false;
+ }
+
+ // Get friendly product name of the device
+ DIPROPSTRING stringProperty;
+ std::memset(&stringProperty, 0, sizeof(stringProperty));
+ stringProperty.diph.dwSize = sizeof(stringProperty);
+ stringProperty.diph.dwHeaderSize = sizeof(stringProperty.diph);
+ stringProperty.diph.dwHow = DIPH_DEVICE;
+ stringProperty.diph.dwObj = 0;
+
+ if (!m_device->GetProperty(DIPROP_PRODUCTNAME, &stringProperty.diph))
+ {
+ m_identification.name = stringProperty.wsz;
+ }
+
+ // Get vendor and produce id of the device
+ std::memset(&property, 0, sizeof(property));
+ property.diph.dwSize = sizeof(property);
+ property.diph.dwHeaderSize = sizeof(property.diph);
+ property.diph.dwHow = DIPH_DEVICE;
+
+ if (!m_device->GetProperty(DIPROP_VIDPID, &property.diph))
+ {
+ m_identification.productId = HIWORD(property.dwData);
+ m_identification.vendorId = LOWORD(property.dwData);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::closeDInput()
+{
+ if (m_device)
+ {
+ // Release the device
+ m_device->Release();
+ m_device = NULL;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilitiesDInput() const
+{
+ JoystickCaps caps;
+
+ // Count how many buttons have valid offsets
+ caps.buttonCount = 0;
+
+ for (int i = 0; i < Joystick::ButtonCount; ++i)
+ {
+ if (m_buttons[i] != -1)
+ ++caps.buttonCount;
+ }
+
+ // Check which axes have valid offsets
+ for (int i = 0; i < Joystick::AxisCount; ++i)
+ caps.axes[i] = (m_axes[i] != -1);
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::updateDInput()
+{
+ JoystickState state;
+
+ if (m_device)
+ {
+ // Poll the device
+ m_device->Poll();
+
+ DIJOYSTATE joystate;
+
+ // Try to get the device state
+ HRESULT result = m_device->GetDeviceState(sizeof(joystate), &joystate);
+
+ // If we have not acquired or have lost the device, attempt to (re-)acquire it and get the device state again
+ if ((result == DIERR_NOTACQUIRED) || (result == DIERR_INPUTLOST))
+ {
+ m_device->Acquire();
+ m_device->Poll();
+ result = m_device->GetDeviceState(sizeof(joystate), &joystate);
+ }
+
+ // If we still can't get the device state, assume it has been disconnected
+ if ((result == DIERR_NOTACQUIRED) || (result == DIERR_INPUTLOST))
+ {
+ m_device->Release();
+ m_device = NULL;
+
+ return state;
+ }
+
+ if (result)
+ {
+ err() << "Failed to get DirectInput device state: " << result << std::endl;
+
+ return state;
+ }
+
+ // Get the current state of each axis
+ for (int i = 0; i < Joystick::AxisCount; ++i)
+ {
+ if (m_axes[i] != -1)
+ {
+ if (i == Joystick::PovX)
+ {
+ unsigned short value = LOWORD(*reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[i]));
+
+ if (value != 0xFFFF)
+ {
+ float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
+
+ state.axes[i] = std::sin(angle) * 100.f;
+ }
+ else
+ {
+ state.axes[i] = 0;
+ }
+ }
+ else if (i == Joystick::PovY)
+ {
+ unsigned short value = LOWORD(*reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[i]));
+
+ if (value != 0xFFFF)
+ {
+ float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
+
+ state.axes[i] = std::cos(angle) * 100.f;
+ }
+ else
+ {
+ state.axes[i] = 0.f;
+ }
+ }
+ else
+ {
+ state.axes[i] = (static_cast<float>(*reinterpret_cast<const LONG*>(reinterpret_cast<const char*>(&joystate) + m_axes[i])) + 0.5f) * 100.f / 32767.5f;
+ }
+ }
+ else
+ {
+ state.axes[i] = 0.f;
+ }
+ }
+
+ // Get the current state of each button
+ for (int i = 0; i < Joystick::ButtonCount; ++i)
+ {
+ if (m_buttons[i] != -1)
+ {
+ BYTE value = *reinterpret_cast<const BYTE*>(reinterpret_cast<const char*>(&joystate) + m_buttons[i]);
+
+ state.buttons[i] = ((value & 0x80) != 0);
+ }
+ else
+ {
+ state.buttons[i] = false;
+ }
+ }
+
+ state.connected = true;
+ }
+
+ return state;
+}
+
+
+////////////////////////////////////////////////////////////
+BOOL CALLBACK JoystickImpl::deviceEnumerationCallback(const DIDEVICEINSTANCE* deviceInstance, void*)
+{
+ for (std::size_t i = 0; i < joystickList.size(); ++i)
+ {
+ if (joystickList[i].guid == deviceInstance->guidInstance)
+ {
+ joystickList[i].plugged = true;
+
+ return DIENUM_CONTINUE;
+ }
+ }
+
+ JoystickRecord record = { deviceInstance->guidInstance, sf::Joystick::Count, true };
+ joystickList.push_back(record);
+
+ return DIENUM_CONTINUE;
+}
+
+
+////////////////////////////////////////////////////////////
+BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECTINSTANCE* deviceObjectInstance, void* userData)
+{
+ sf::priv::JoystickImpl& joystick = *reinterpret_cast<sf::priv::JoystickImpl*>(userData);
+
+ if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_AXIS)
+ {
+ // Axes
+ if (deviceObjectInstance->guidType == guids::GUID_XAxis)
+ joystick.m_axes[Joystick::X] = DIJOFS_X;
+ else if (deviceObjectInstance->guidType == guids::GUID_YAxis)
+ joystick.m_axes[Joystick::Y] = DIJOFS_Y;
+ else if (deviceObjectInstance->guidType == guids::GUID_ZAxis)
+ joystick.m_axes[Joystick::Z] = DIJOFS_Z;
+ else if (deviceObjectInstance->guidType == guids::GUID_RzAxis)
+ joystick.m_axes[Joystick::R] = DIJOFS_RZ;
+ else if (deviceObjectInstance->guidType == guids::GUID_RxAxis)
+ joystick.m_axes[Joystick::U] = DIJOFS_RX;
+ else if (deviceObjectInstance->guidType == guids::GUID_RyAxis)
+ joystick.m_axes[Joystick::V] = DIJOFS_RY;
+ else if (deviceObjectInstance->guidType == guids::GUID_Slider)
+ {
+ if(joystick.m_axes[Joystick::U] == -1)
+ joystick.m_axes[Joystick::U] = DIJOFS_SLIDER(0);
+ else
+ joystick.m_axes[Joystick::V] = DIJOFS_SLIDER(1);
+ }
+ else
+ return DIENUM_CONTINUE;
+
+ // Set the axis' value range to that of a signed short: [-32768, 32767]
+ DIPROPRANGE propertyRange;
+
+ std::memset(&propertyRange, 0, sizeof(propertyRange));
+ propertyRange.diph.dwSize = sizeof(propertyRange);
+ propertyRange.diph.dwHeaderSize = sizeof(propertyRange.diph);
+ propertyRange.diph.dwObj = deviceObjectInstance->dwType;
+ propertyRange.diph.dwHow = DIPH_BYID;
+ propertyRange.lMin = -32768;
+ propertyRange.lMax = 32767;
+
+ HRESULT result = joystick.m_device->SetProperty(DIPROP_RANGE, &propertyRange.diph);
+
+ if (result)
+ err() << "Failed to set DirectInput device axis property range: " << result << std::endl;
+
+ return DIENUM_CONTINUE;
+ }
+ else if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_POV)
+ {
+ // POVs
+ if (deviceObjectInstance->guidType == guids::GUID_POV)
+ {
+ if (joystick.m_axes[Joystick::PovX] == -1)
+ {
+ joystick.m_axes[Joystick::PovX] = DIJOFS_POV(0);
+ joystick.m_axes[Joystick::PovY] = DIJOFS_POV(0);
+ }
+ }
+
+ return DIENUM_CONTINUE;
+ }
+ else if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_BUTTON)
+ {
+ // Buttons
+ for (int i = 0; i < Joystick::ButtonCount; ++i)
+ {
+ if (joystick.m_buttons[i] == -1)
+ {
+ joystick.m_buttons[i] = DIJOFS_BUTTON(i);
+ break;
+ }
+ }
+
+ return DIENUM_CONTINUE;
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/JoystickImpl.hpp b/src/SFML/Window/Win32/JoystickImpl.hpp
new file mode 100644
index 0000000..8affc27
--- /dev/null
+++ b/src/SFML/Window/Win32/JoystickImpl.hpp
@@ -0,0 +1,237 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKIMPLWIN32_HPP
+#define SFML_JOYSTICKIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#ifdef _WIN32_WINDOWS
+ #undef _WIN32_WINDOWS
+#endif
+#ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+#endif
+#define _WIN32_WINDOWS 0x0501
+#define _WIN32_WINNT 0x0501
+#define DIRECTINPUT_VERSION 0x0800
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <windows.h>
+#include <mmsystem.h>
+#include <dinput.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable lazy enumeration updates
+ ///
+ /// \param status Whether to rely on windows triggering enumeration updates
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setLazyUpdates(bool status);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the connection status of all joysticks
+ ///
+ ////////////////////////////////////////////////////////////
+ static void updateConnections();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module (DInput)
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initializeDInput();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module (DInput)
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanupDInput();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected (DInput)
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnectedDInput(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the connection status of all joysticks (DInput)
+ ///
+ ////////////////////////////////////////////////////////////
+ static void updateConnectionsDInput();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick (DInput)
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool openDInput(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick (DInput)
+ ///
+ ////////////////////////////////////////////////////////////
+ void closeDInput();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities (DInput)
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilitiesDInput() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state (DInput)
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState updateDInput();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Device enumeration callback function passed to EnumDevices in updateConnections
+ ///
+ /// \param deviceInstance Device object instance
+ /// \param userData User data (unused)
+ ///
+ /// \return DIENUM_CONTINUE to continue enumerating devices or DIENUM_STOP to stop
+ ///
+ ////////////////////////////////////////////////////////////
+ static BOOL CALLBACK deviceEnumerationCallback(const DIDEVICEINSTANCE* deviceInstance, void* userData);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Device object enumeration callback function passed to EnumObjects in open
+ ///
+ /// \param deviceObjectInstance Device object instance
+ /// \param userData User data (pointer to our JoystickImpl object)
+ ///
+ /// \return DIENUM_CONTINUE to continue enumerating objects or DIENUM_STOP to stop
+ ///
+ ////////////////////////////////////////////////////////////
+ static BOOL CALLBACK deviceObjectEnumerationCallback(const DIDEVICEOBJECTINSTANCE* deviceObjectInstance, void* userData);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ unsigned int m_index; ///< Index of the joystick
+ JOYCAPS m_caps; ///< Joystick capabilities
+ IDirectInputDevice8W* m_device; ///< DirectInput 8.x device
+ DIDEVCAPS m_deviceCaps; ///< DirectInput device capabilities
+ int m_axes[Joystick::AxisCount]; ///< Offsets to the bytes containing the axes states, -1 if not available
+ int m_buttons[Joystick::ButtonCount]; ///< Offsets to the bytes containing the button states, -1 if not available
+ Joystick::Identification m_identification; ///< Joystick identification
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLWIN32_HPP
diff --git a/src/SFML/Window/Win32/SensorImpl.cpp b/src/SFML/Window/Win32/SensorImpl.cpp
new file mode 100644
index 0000000..3496265
--- /dev/null
+++ b/src/SFML/Window/Win32/SensorImpl.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ // To be implemented
+ return Vector3f(0, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool /*enabled*/)
+{
+ // To be implemented
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/SensorImpl.hpp b/src/SFML/Window/Win32/SensorImpl.hpp
new file mode 100644
index 0000000..e8b618e
--- /dev/null
+++ b/src/SFML/Window/Win32/SensorImpl.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPLWIN32_HPP
+#define SFML_SENSORIMPLWIN32_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLWIN32_HPP
diff --git a/src/SFML/Window/Win32/VideoModeImpl.cpp b/src/SFML/Window/Win32/VideoModeImpl.cpp
new file mode 100644
index 0000000..71ad671
--- /dev/null
+++ b/src/SFML/Window/Win32/VideoModeImpl.cpp
@@ -0,0 +1,73 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <windows.h>
+#include <algorithm>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ std::vector<VideoMode> modes;
+
+ // Enumerate all available video modes for the primary display adapter
+ DEVMODE win32Mode;
+ win32Mode.dmSize = sizeof(win32Mode);
+ win32Mode.dmDriverExtra = 0;
+ for (int count = 0; EnumDisplaySettings(NULL, count, &win32Mode); ++count)
+ {
+ // Convert to sf::VideoMode
+ VideoMode mode(win32Mode.dmPelsWidth, win32Mode.dmPelsHeight, win32Mode.dmBitsPerPel);
+
+ // Add it only if it is not already in the array
+ if (std::find(modes.begin(), modes.end(), mode) == modes.end())
+ modes.push_back(mode);
+ }
+
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ DEVMODE win32Mode;
+ win32Mode.dmSize = sizeof(win32Mode);
+ win32Mode.dmDriverExtra = 0;
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &win32Mode);
+
+ return VideoMode(win32Mode.dmPelsWidth, win32Mode.dmPelsHeight, win32Mode.dmBitsPerPel);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp
new file mode 100644
index 0000000..fd9f89e
--- /dev/null
+++ b/src/SFML/Window/Win32/WglContext.cpp
@@ -0,0 +1,737 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/WindowImpl.hpp> // included first to avoid a warning about macro redefinition
+#include <SFML/OpenGL.hpp> // included second to avoid an error in WglExtensions.hpp
+#include <SFML/Window/Win32/WglContext.hpp>
+#include <SFML/System/ThreadLocalPtr.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <SFML/System/Err.hpp>
+#include <sstream>
+#include <vector>
+
+
+namespace
+{
+ // Some drivers are bugged and don't track the current HDC/HGLRC properly
+ // In order to deactivate successfully, we need to track it ourselves as well
+ sf::ThreadLocalPtr<sf::priv::WglContext> currentContext(NULL);
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void ensureExtensionsInit(HDC deviceContext)
+{
+ static bool initialized = false;
+ if (!initialized)
+ {
+ initialized = true;
+
+ // We don't check the return value since the extension
+ // flags are cleared even if loading fails
+ sfwgl_LoadFunctions(deviceContext);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+String getErrorString(DWORD errorCode)
+{
+ std::basic_ostringstream<TCHAR, std::char_traits<TCHAR> > ss;
+ TCHAR errBuff[256];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, 0, errBuff, sizeof(errBuff), NULL);
+ ss << errBuff;
+ String errMsg(ss.str());
+
+ return errMsg;
+}
+
+
+////////////////////////////////////////////////////////////
+WglContext::WglContext(WglContext* shared) :
+m_window (NULL),
+m_pbuffer (NULL),
+m_deviceContext(NULL),
+m_context (NULL),
+m_ownsWindow (false)
+{
+ // Save the creation settings
+ m_settings = ContextSettings();
+
+ // Make sure that extensions are initialized if this is not the shared context
+ // The shared context is the context used to initialize the extensions
+ if (shared && shared->m_deviceContext)
+ ensureExtensionsInit(shared->m_deviceContext);
+
+ // Create the rendering surface (window or pbuffer if supported)
+ createSurface(shared, 1, 1, VideoMode::getDesktopMode().bitsPerPixel);
+
+ // Create the context
+ if (m_deviceContext)
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+WglContext::WglContext(WglContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_window (NULL),
+m_pbuffer (NULL),
+m_deviceContext(NULL),
+m_context (NULL),
+m_ownsWindow (false)
+{
+ // Save the creation settings
+ m_settings = settings;
+
+ // Make sure that extensions are initialized if this is not the shared context
+ // The shared context is the context used to initialize the extensions
+ if (shared && shared->m_deviceContext)
+ ensureExtensionsInit(shared->m_deviceContext);
+
+ // Create the rendering surface from the owner window
+ createSurface(owner->getSystemHandle(), bitsPerPixel);
+
+ // Create the context
+ if (m_deviceContext)
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+WglContext::WglContext(WglContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
+m_window (NULL),
+m_pbuffer (NULL),
+m_deviceContext(NULL),
+m_context (NULL),
+m_ownsWindow (false)
+{
+ // Save the creation settings
+ m_settings = settings;
+
+ // Make sure that extensions are initialized if this is not the shared context
+ // The shared context is the context used to initialize the extensions
+ if (shared && shared->m_deviceContext)
+ ensureExtensionsInit(shared->m_deviceContext);
+
+ // Create the rendering surface (window or pbuffer if supported)
+ createSurface(shared, width, height, VideoMode::getDesktopMode().bitsPerPixel);
+
+ // Create the context
+ if (m_deviceContext)
+ createContext(shared);
+}
+
+
+////////////////////////////////////////////////////////////
+WglContext::~WglContext()
+{
+ // Notify unshared OpenGL resources of context destruction
+ cleanupUnsharedResources();
+
+ // Destroy the OpenGL context
+ if (m_context)
+ {
+ if (currentContext == this)
+ {
+ if (wglMakeCurrent(m_deviceContext, NULL) == TRUE)
+ currentContext = NULL;
+ }
+
+ wglDeleteContext(m_context);
+ }
+
+ // Destroy the device context
+ if (m_deviceContext)
+ {
+ if (m_pbuffer)
+ {
+ wglReleasePbufferDCARB(m_pbuffer, m_deviceContext);
+ wglDestroyPbufferARB(m_pbuffer);
+ }
+ else
+ {
+ ReleaseDC(m_window, m_deviceContext);
+ }
+ }
+
+ // Destroy the window if we own it
+ if (m_window && m_ownsWindow)
+ DestroyWindow(m_window);
+}
+
+
+////////////////////////////////////////////////////////////
+GlFunctionPointer WglContext::getFunction(const char* name)
+{
+ GlFunctionPointer address = reinterpret_cast<GlFunctionPointer>(wglGetProcAddress(reinterpret_cast<LPCSTR>(name)));
+
+ if (address)
+ {
+ // Test whether the returned value is a valid error code
+ ptrdiff_t errorCode = reinterpret_cast<ptrdiff_t>(address);
+
+ if ((errorCode != -1) && (errorCode != 1) && (errorCode != 2) && (errorCode != 3))
+ return address;
+ }
+
+ static HMODULE module = NULL;
+
+ if (!module)
+ module = GetModuleHandleA("OpenGL32.dll");
+
+ if (module)
+ return reinterpret_cast<GlFunctionPointer>(GetProcAddress(module, reinterpret_cast<LPCSTR>(name)));
+
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+bool WglContext::makeCurrent(bool current)
+{
+ if (!m_deviceContext || !m_context)
+ return false;
+
+ if (wglMakeCurrent(m_deviceContext, current ? m_context : NULL) == FALSE)
+ {
+ err() << "Failed to " << (current ? "activate" : "deactivate") << " OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return false;
+ }
+
+ currentContext = (current ? this : NULL);
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::display()
+{
+ if (m_deviceContext && m_context)
+ SwapBuffers(m_deviceContext);
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::setVerticalSyncEnabled(bool enabled)
+{
+ // Make sure that extensions are initialized
+ ensureExtensionsInit(m_deviceContext);
+
+ if (sfwgl_ext_EXT_swap_control == sfwgl_LOAD_SUCCEEDED)
+ {
+ if (wglSwapIntervalEXT(enabled ? 1 : 0) == FALSE)
+ err() << "Setting vertical sync failed: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ }
+ else
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ // wglSwapIntervalEXT not supported
+ err() << "Setting vertical sync not supported" << std::endl;
+
+ warned = true;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings, bool pbuffer)
+{
+ // Let's find a suitable pixel format -- first try with wglChoosePixelFormatARB
+ int bestFormat = 0;
+ if (sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED)
+ {
+ // Define the basic attributes we want for our window
+ int intAttributes[] =
+ {
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
+ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
+ 0, 0
+ };
+
+ // Let's check how many formats are supporting our requirements
+ int formats[512];
+ UINT nbFormats;
+ bool isValid = wglChoosePixelFormatARB(deviceContext, intAttributes, NULL, 512, formats, &nbFormats) != FALSE;
+
+ if (!isValid)
+ err() << "Failed to enumerate pixel formats: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+
+ // Get the best format among the returned ones
+ if (isValid && (nbFormats > 0))
+ {
+ int bestScore = 0x7FFFFFFF;
+ for (UINT i = 0; i < nbFormats; ++i)
+ {
+ // Extract the components of the current format
+ int values[7];
+ const int attributes[] =
+ {
+ WGL_RED_BITS_ARB,
+ WGL_GREEN_BITS_ARB,
+ WGL_BLUE_BITS_ARB,
+ WGL_ALPHA_BITS_ARB,
+ WGL_DEPTH_BITS_ARB,
+ WGL_STENCIL_BITS_ARB,
+ WGL_ACCELERATION_ARB
+ };
+
+ if (wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 7, attributes, values) == FALSE)
+ {
+ err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ break;
+ }
+
+ int sampleValues[2] = {0, 0};
+ if (sfwgl_ext_ARB_multisample == sfwgl_LOAD_SUCCEEDED)
+ {
+ const int sampleAttributes[] =
+ {
+ WGL_SAMPLE_BUFFERS_ARB,
+ WGL_SAMPLES_ARB
+ };
+
+ if (wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues) == FALSE)
+ {
+ err() << "Failed to retrieve pixel format multisampling information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ break;
+ }
+ }
+
+ int sRgbCapableValue = 0;
+ if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED))
+ {
+ const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
+
+ if (wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue) == FALSE)
+ {
+ err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ break;
+ }
+ }
+
+ if (pbuffer)
+ {
+ const int pbufferAttributes[] =
+ {
+ WGL_DRAW_TO_PBUFFER_ARB
+ };
+
+ int pbufferValue = 0;
+
+ if (wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, pbufferAttributes, &pbufferValue) == FALSE)
+ {
+ err() << "Failed to retrieve pixel format pbuffer information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ break;
+ }
+
+ if (pbufferValue != GL_TRUE)
+ continue;
+ }
+
+ // Evaluate the current configuration
+ int color = values[0] + values[1] + values[2] + values[3];
+ int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB, sRgbCapableValue == TRUE);
+
+ // Keep it if it's better than the current best
+ if (score < bestScore)
+ {
+ bestScore = score;
+ bestFormat = formats[i];
+ }
+ }
+ }
+ }
+
+ // ChoosePixelFormat doesn't support pbuffers
+ if (pbuffer)
+ return bestFormat;
+
+ // Find a pixel format with ChoosePixelFormat, if wglChoosePixelFormatARB is not supported
+ if (bestFormat == 0)
+ {
+ // Setup a pixel format descriptor from the rendering settings
+ PIXELFORMATDESCRIPTOR descriptor;
+ ZeroMemory(&descriptor, sizeof(descriptor));
+ descriptor.nSize = sizeof(descriptor);
+ descriptor.nVersion = 1;
+ descriptor.iLayerType = PFD_MAIN_PLANE;
+ descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ descriptor.iPixelType = PFD_TYPE_RGBA;
+ descriptor.cColorBits = static_cast<BYTE>(bitsPerPixel);
+ descriptor.cDepthBits = static_cast<BYTE>(settings.depthBits);
+ descriptor.cStencilBits = static_cast<BYTE>(settings.stencilBits);
+ descriptor.cAlphaBits = bitsPerPixel == 32 ? 8 : 0;
+
+ // Get the pixel format that best matches our requirements
+ bestFormat = ChoosePixelFormat(deviceContext, &descriptor);
+ }
+
+ return bestFormat;
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::setDevicePixelFormat(unsigned int bitsPerPixel)
+{
+ int bestFormat = selectBestPixelFormat(m_deviceContext, bitsPerPixel, m_settings);
+
+ if (bestFormat == 0)
+ {
+ err() << "Failed to find a suitable pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl
+ << "Cannot create OpenGL context" << std::endl;
+ return;
+ }
+
+ // Extract the depth and stencil bits from the chosen format
+ PIXELFORMATDESCRIPTOR actualFormat;
+ actualFormat.nSize = sizeof(actualFormat);
+ actualFormat.nVersion = 1;
+ DescribePixelFormat(m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
+
+ // Set the chosen pixel format
+ if (SetPixelFormat(m_deviceContext, bestFormat, &actualFormat) == FALSE)
+ {
+ err() << "Failed to set pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl
+ << "Cannot create OpenGL context" << std::endl;
+ return;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::updateSettingsFromPixelFormat()
+{
+ int format = GetPixelFormat(m_deviceContext);
+
+ if (format == 0)
+ {
+ err() << "Failed to get selected pixel format: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return;
+ }
+
+ PIXELFORMATDESCRIPTOR actualFormat;
+ actualFormat.nSize = sizeof(actualFormat);
+ actualFormat.nVersion = 1;
+
+ if (DescribePixelFormat(m_deviceContext, format, sizeof(actualFormat), &actualFormat) == 0)
+ {
+ err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return;
+ }
+
+ if (sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED)
+ {
+ const int attributes[] = {WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB};
+ int values[2];
+
+ if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 2, attributes, values) == TRUE)
+ {
+ m_settings.depthBits = values[0];
+ m_settings.stencilBits = values[1];
+ }
+ else
+ {
+ err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ m_settings.depthBits = actualFormat.cDepthBits;
+ m_settings.stencilBits = actualFormat.cStencilBits;
+ }
+
+ if (sfwgl_ext_ARB_multisample == sfwgl_LOAD_SUCCEEDED)
+ {
+ const int sampleAttributes[] = {WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB};
+ int sampleValues[2];
+
+ if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues) == TRUE)
+ {
+ m_settings.antialiasingLevel = sampleValues[0] ? sampleValues[1] : 0;
+ }
+ else
+ {
+ err() << "Failed to retrieve pixel format multisampling information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ m_settings.antialiasingLevel = 0;
+ }
+ }
+ else
+ {
+ m_settings.antialiasingLevel = 0;
+ }
+
+ if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED))
+ {
+ const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
+ int sRgbCapableValue = 0;
+
+ if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue) == TRUE)
+ {
+ m_settings.sRgbCapable = (sRgbCapableValue == TRUE);
+ }
+ else
+ {
+ err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ m_settings.sRgbCapable = false;
+ }
+ }
+ else
+ {
+ m_settings.sRgbCapable = false;
+ }
+ }
+ else
+ {
+ m_settings.depthBits = actualFormat.cDepthBits;
+ m_settings.stencilBits = actualFormat.cStencilBits;
+ m_settings.antialiasingLevel = 0;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::createSurface(WglContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel)
+{
+ // Check if the shared context already exists and pbuffers are supported
+ if (shared && shared->m_deviceContext && (sfwgl_ext_ARB_pbuffer == sfwgl_LOAD_SUCCEEDED))
+ {
+ int bestFormat = selectBestPixelFormat(shared->m_deviceContext, bitsPerPixel, m_settings, true);
+
+ if (bestFormat > 0)
+ {
+ int attributes[] = {0, 0};
+
+ m_pbuffer = wglCreatePbufferARB(shared->m_deviceContext, bestFormat, width, height, attributes);
+
+ if (m_pbuffer)
+ {
+ m_window = shared->m_window;
+ m_deviceContext = wglGetPbufferDCARB(m_pbuffer);
+
+ if (!m_deviceContext)
+ {
+ err() << "Failed to retrieve pixel buffer device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+
+ wglDestroyPbufferARB(m_pbuffer);
+ m_pbuffer = NULL;
+ }
+ }
+ else
+ {
+ err() << "Failed to create pixel buffer: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ }
+ }
+ }
+
+ // If pbuffers are not available we use a hidden window as the off-screen surface to draw to
+ if (!m_deviceContext)
+ {
+ // We can't create a memory DC, the resulting context wouldn't be compatible
+ // with other contexts and thus wglShareLists would always fail
+
+ // Create the hidden window
+ m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, width, height, NULL, NULL, GetModuleHandle(NULL), NULL);
+ ShowWindow(m_window, SW_HIDE);
+ m_deviceContext = GetDC(m_window);
+
+ m_ownsWindow = true;
+
+ // Set the pixel format of the device context
+ setDevicePixelFormat(bitsPerPixel);
+ }
+
+ // Update context settings from the selected pixel format
+ updateSettingsFromPixelFormat();
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::createSurface(HWND window, unsigned int bitsPerPixel)
+{
+ m_window = window;
+ m_deviceContext = GetDC(window);
+
+ // Set the pixel format of the device context
+ setDevicePixelFormat(bitsPerPixel);
+
+ // Update context settings from the selected pixel format
+ updateSettingsFromPixelFormat();
+}
+
+
+////////////////////////////////////////////////////////////
+void WglContext::createContext(WglContext* shared)
+{
+ // Get a working copy of the context settings
+ ContextSettings settings = m_settings;
+
+ // Get the context to share display lists with
+ HGLRC sharedContext = shared ? shared->m_context : NULL;
+
+ // Create the OpenGL context -- first try using wglCreateContextAttribsARB
+ while (!m_context && m_settings.majorVersion)
+ {
+ if (sfwgl_ext_ARB_create_context == sfwgl_LOAD_SUCCEEDED)
+ {
+ std::vector<int> attributes;
+
+ // Check if the user requested a specific context version (anything > 1.1)
+ if ((m_settings.majorVersion > 1) || ((m_settings.majorVersion == 1) && (m_settings.minorVersion > 1)))
+ {
+ attributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
+ attributes.push_back(m_settings.majorVersion);
+ attributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
+ attributes.push_back(m_settings.minorVersion);
+ }
+
+ // Check if setting the profile is supported
+ if (sfwgl_ext_ARB_create_context_profile == sfwgl_LOAD_SUCCEEDED)
+ {
+ int profile = (m_settings.attributeFlags & ContextSettings::Core) ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ int debug = (m_settings.attributeFlags & ContextSettings::Debug) ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
+
+ attributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
+ attributes.push_back(profile);
+ attributes.push_back(WGL_CONTEXT_FLAGS_ARB);
+ attributes.push_back(debug);
+ }
+ else
+ {
+ if ((m_settings.attributeFlags & ContextSettings::Core) || (m_settings.attributeFlags & ContextSettings::Debug))
+ err() << "Selecting a profile during context creation is not supported,"
+ << "disabling comptibility and debug" << std::endl;
+
+ m_settings.attributeFlags = ContextSettings::Default;
+ }
+
+ // Append the terminating 0
+ attributes.push_back(0);
+ attributes.push_back(0);
+
+ if (sharedContext)
+ {
+ static Mutex mutex;
+ Lock lock(mutex);
+
+ if (currentContext == shared)
+ {
+ if (wglMakeCurrent(shared->m_deviceContext, NULL) == FALSE)
+ {
+ err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return;
+ }
+
+ currentContext = NULL;
+ }
+ }
+
+ // Create the context
+ m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]);
+ }
+ else
+ {
+ // If wglCreateContextAttribsARB is not supported, there is no need to keep trying
+ break;
+ }
+
+ // If we couldn't create the context, first try disabling flags,
+ // then lower the version number and try again -- stop at 0.0
+ // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
+ if (!m_context)
+ {
+ if (m_settings.attributeFlags != ContextSettings::Default)
+ {
+ m_settings.attributeFlags = ContextSettings::Default;
+ }
+ else if (m_settings.minorVersion > 0)
+ {
+ // If the minor version is not 0, we decrease it and try again
+ m_settings.minorVersion--;
+
+ m_settings.attributeFlags = settings.attributeFlags;
+ }
+ else
+ {
+ // If the minor version is 0, we decrease the major version
+ m_settings.majorVersion--;
+ m_settings.minorVersion = 9;
+
+ m_settings.attributeFlags = settings.attributeFlags;
+ }
+ }
+ }
+
+ // If wglCreateContextAttribsARB failed, use wglCreateContext
+ if (!m_context)
+ {
+ // set the context version to 1.1 (arbitrary) and disable flags
+ m_settings.majorVersion = 1;
+ m_settings.minorVersion = 1;
+ m_settings.attributeFlags = ContextSettings::Default;
+
+ m_context = wglCreateContext(m_deviceContext);
+ if (!m_context)
+ {
+ err() << "Failed to create an OpenGL context for this window: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return;
+ }
+
+ // Share this context with others
+ if (sharedContext)
+ {
+ // wglShareLists doesn't seem to be thread-safe
+ static Mutex mutex;
+ Lock lock(mutex);
+
+ if (currentContext == shared)
+ {
+ if (wglMakeCurrent(shared->m_deviceContext, NULL) == FALSE)
+ {
+ err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ return;
+ }
+
+ currentContext = NULL;
+ }
+
+ if (wglShareLists(sharedContext, m_context) == FALSE)
+ err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
+ }
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Win32/WglContext.hpp b/src/SFML/Window/Win32/WglContext.hpp
new file mode 100644
index 0000000..d692605
--- /dev/null
+++ b/src/SFML/Window/Win32/WglContext.hpp
@@ -0,0 +1,193 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_WGLCONTEXT_HPP
+#define SFML_WGLCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/Window/Win32/WglExtensions.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows (WGL) implementation of OpenGL contexts
+///
+////////////////////////////////////////////////////////////
+class WglContext : public GlContext
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new default context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ WglContext(WglContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ WglContext(WglContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ WglContext(WglContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WglContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \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 Activate the context as the current target for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled: True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Select the best pixel format for a given set of settings
+ ///
+ /// \param deviceContext Device context
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Requested context settings
+ /// \param pbuffer Whether the pixel format should support pbuffers
+ ///
+ /// \return The best pixel format
+ ///
+ ////////////////////////////////////////////////////////////
+ static int selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings, bool pbuffer = false);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the pixel format of the device context
+ ///
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ void setDevicePixelFormat(unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the context settings from the selected pixel format
+ ///
+ ////////////////////////////////////////////////////////////
+ void updateSettingsFromPixelFormat();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context's drawing surface
+ ///
+ /// \param shared Shared context (can be NULL)
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ void createSurface(WglContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context's drawing surface from an existing window
+ ///
+ /// \param window Window handle of the owning window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ void createSurface(HWND window, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(WglContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ HWND m_window; ///< Window to which the context is attached
+ HPBUFFERARB m_pbuffer; ///< Handle to a pbuffer if one was created
+ HDC m_deviceContext; ///< Device context associated to the context
+ HGLRC m_context; ///< OpenGL context
+ bool m_ownsWindow; ///< Do we own the target window?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_WGLCONTEXT_HPP
diff --git a/src/SFML/Window/Win32/WglExtensions.cpp b/src/SFML/Window/Win32/WglExtensions.cpp
new file mode 100644
index 0000000..b96271b
--- /dev/null
+++ b/src/SFML/Window/Win32/WglExtensions.cpp
@@ -0,0 +1,223 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Win32/WglExtensions.hpp>
+#include <SFML/Window/Context.hpp>
+#include <cstdlib>
+#include <cstring>
+#include <cstddef>
+#include <string>
+
+static sf::GlFunctionPointer IntGetProcAddress(const char* name)
+{
+ return sf::Context::getFunction(name);
+}
+
+int sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED;
+int sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_create_context = sfwgl_LOAD_FAILED;
+int sfwgl_ext_ARB_create_context_profile = sfwgl_LOAD_FAILED;
+
+int (CODEGEN_FUNCPTR *sf_ptrc_wglGetSwapIntervalEXT)(void) = NULL;
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglSwapIntervalEXT)(int) = NULL;
+
+static int Load_EXT_swap_control(void)
+{
+ int numFailed = 0;
+ sf_ptrc_wglGetSwapIntervalEXT = reinterpret_cast<int (CODEGEN_FUNCPTR*)(void)>(IntGetProcAddress("wglGetSwapIntervalEXT"));
+ if (!sf_ptrc_wglGetSwapIntervalEXT)
+ numFailed++;
+ sf_ptrc_wglSwapIntervalEXT = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(int)>(IntGetProcAddress("wglSwapIntervalEXT"));
+ if (!sf_ptrc_wglSwapIntervalEXT)
+ numFailed++;
+ return numFailed;
+}
+
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int*, const FLOAT*, UINT, int*, UINT*) = NULL;
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int*, FLOAT*) = NULL;
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int*, int*) = NULL;
+
+static int Load_ARB_pixel_format(void)
+{
+ int numFailed = 0;
+ sf_ptrc_wglChoosePixelFormatARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HDC, const int*, const FLOAT*, UINT, int*, UINT*)>(IntGetProcAddress("wglChoosePixelFormatARB"));
+ if (!sf_ptrc_wglChoosePixelFormatARB)
+ numFailed++;
+ sf_ptrc_wglGetPixelFormatAttribfvARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR *)(HDC, int, int, UINT, const int*, FLOAT*)>(IntGetProcAddress("wglGetPixelFormatAttribfvARB"));
+ if (!sf_ptrc_wglGetPixelFormatAttribfvARB)
+ numFailed++;
+ sf_ptrc_wglGetPixelFormatAttribivARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HDC, int, int, UINT, const int*, int*)>(IntGetProcAddress("wglGetPixelFormatAttribivARB"));
+ if (!sf_ptrc_wglGetPixelFormatAttribivARB)
+ numFailed++;
+ return numFailed;
+}
+
+HPBUFFERARB (CODEGEN_FUNCPTR *sf_ptrc_wglCreatePbufferARB)(HDC, int, int, int, const int*) = NULL;
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglDestroyPbufferARB)(HPBUFFERARB) = NULL;
+HDC (CODEGEN_FUNCPTR *sf_ptrc_wglGetPbufferDCARB)(HPBUFFERARB) = NULL;
+BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglQueryPbufferARB)(HPBUFFERARB, int, int*) = NULL;
+int (CODEGEN_FUNCPTR *sf_ptrc_wglReleasePbufferDCARB)(HPBUFFERARB, HDC) = NULL;
+
+static int Load_ARB_pbuffer()
+{
+ int numFailed = 0;
+ sf_ptrc_wglCreatePbufferARB = reinterpret_cast<HPBUFFERARB (CODEGEN_FUNCPTR*)(HDC, int, int, int, const int*)>(IntGetProcAddress("wglCreatePbufferARB"));
+ if (!sf_ptrc_wglCreatePbufferARB)
+ numFailed++;
+ sf_ptrc_wglDestroyPbufferARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HPBUFFERARB)>(IntGetProcAddress("wglDestroyPbufferARB"));
+ if (!sf_ptrc_wglDestroyPbufferARB)
+ numFailed++;
+ sf_ptrc_wglGetPbufferDCARB = reinterpret_cast<HDC (CODEGEN_FUNCPTR*)(HPBUFFERARB)>(IntGetProcAddress("wglGetPbufferDCARB"));
+ if (!sf_ptrc_wglGetPbufferDCARB)
+ numFailed++;
+ sf_ptrc_wglQueryPbufferARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HPBUFFERARB, int, int*)>(IntGetProcAddress("wglQueryPbufferARB"));
+ if (!sf_ptrc_wglQueryPbufferARB)
+ numFailed++;
+ sf_ptrc_wglReleasePbufferDCARB = reinterpret_cast<int (CODEGEN_FUNCPTR*)(HPBUFFERARB, HDC)>(IntGetProcAddress("wglReleasePbufferDCARB"));
+ if (!sf_ptrc_wglReleasePbufferDCARB)
+ numFailed++;
+ return numFailed;
+}
+
+HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int*) = NULL;
+
+static int Load_ARB_create_context(void)
+{
+ int numFailed = 0;
+ sf_ptrc_wglCreateContextAttribsARB = reinterpret_cast<HGLRC (CODEGEN_FUNCPTR*)(HDC, HGLRC, const int*)>(IntGetProcAddress("wglCreateContextAttribsARB"));
+ if (!sf_ptrc_wglCreateContextAttribsARB)
+ numFailed++;
+ return numFailed;
+}
+
+
+static const char* (CODEGEN_FUNCPTR *sf_ptrc_wglGetExtensionsStringARB)(HDC) = NULL;
+
+typedef int (*PFN_LOADFUNCPOINTERS)(void);
+typedef struct sfwgl_StrToExtMap_s
+{
+ const char* extensionName;
+ int* extensionVariable;
+ PFN_LOADFUNCPOINTERS LoadExtension;
+} sfwgl_StrToExtMap;
+
+static sfwgl_StrToExtMap ExtensionMap[8] = {
+ {"WGL_EXT_swap_control", &sfwgl_ext_EXT_swap_control, Load_EXT_swap_control},
+ {"WGL_EXT_framebuffer_sRGB", &sfwgl_ext_EXT_framebuffer_sRGB, NULL},
+ {"WGL_ARB_framebuffer_sRGB", &sfwgl_ext_ARB_framebuffer_sRGB, NULL},
+ {"WGL_ARB_multisample", &sfwgl_ext_ARB_multisample, NULL},
+ {"WGL_ARB_pixel_format", &sfwgl_ext_ARB_pixel_format, Load_ARB_pixel_format},
+ {"WGL_ARB_pbuffer", &sfwgl_ext_ARB_pbuffer, Load_ARB_pbuffer},
+ {"WGL_ARB_create_context", &sfwgl_ext_ARB_create_context, Load_ARB_create_context},
+ {"WGL_ARB_create_context_profile", &sfwgl_ext_ARB_create_context_profile, NULL}
+};
+
+static int g_extensionMapSize = 8;
+
+
+static sfwgl_StrToExtMap* FindExtEntry(const char* extensionName)
+{
+ sfwgl_StrToExtMap* currLoc = ExtensionMap;
+ for (int loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc)
+ {
+ if (std::strcmp(extensionName, currLoc->extensionName) == 0)
+ return currLoc;
+ }
+
+ return NULL;
+}
+
+
+static void ClearExtensionVars(void)
+{
+ sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED;
+ sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_create_context = sfwgl_LOAD_FAILED;
+ sfwgl_ext_ARB_create_context_profile = sfwgl_LOAD_FAILED;
+}
+
+
+static void LoadExtByName(const char* extensionName)
+{
+ sfwgl_StrToExtMap* entry = NULL;
+ entry = FindExtEntry(extensionName);
+ if (entry)
+ {
+ if (entry->LoadExtension)
+ {
+ int numFailed = entry->LoadExtension();
+ if (numFailed == 0)
+ {
+ *(entry->extensionVariable) = sfwgl_LOAD_SUCCEEDED;
+ }
+ else
+ {
+ *(entry->extensionVariable) = sfwgl_LOAD_SUCCEEDED + numFailed;
+ }
+ }
+ else
+ {
+ *(entry->extensionVariable) = sfwgl_LOAD_SUCCEEDED;
+ }
+ }
+}
+
+
+static void ProcExtsFromExtString(const char* strExtList)
+{
+ do
+ {
+ const char* begin = strExtList;
+
+ while ((*strExtList != ' ') && *strExtList)
+ strExtList++;
+
+ LoadExtByName(std::string(begin, strExtList).c_str());
+ } while (*strExtList++);
+}
+
+
+int sfwgl_LoadFunctions(HDC hdc)
+{
+ ClearExtensionVars();
+
+ sf_ptrc_wglGetExtensionsStringARB = reinterpret_cast<const char* (CODEGEN_FUNCPTR*)(HDC)>(IntGetProcAddress("wglGetExtensionsStringARB"));
+ if (!sf_ptrc_wglGetExtensionsStringARB)
+ return sfwgl_LOAD_FAILED;
+
+ ProcExtsFromExtString(reinterpret_cast<const char*>(sf_ptrc_wglGetExtensionsStringARB(hdc)));
+ return sfwgl_LOAD_SUCCEEDED;
+}
+
diff --git a/src/SFML/Window/Win32/WglExtensions.hpp b/src/SFML/Window/Win32/WglExtensions.hpp
new file mode 100644
index 0000000..3cefd99
--- /dev/null
+++ b/src/SFML/Window/Win32/WglExtensions.hpp
@@ -0,0 +1,236 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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 SF_POINTER_C_GENERATED_HEADER_WINDOWSGL_HPP
+#define SF_POINTER_C_GENERATED_HEADER_WINDOWSGL_HPP
+
+#ifdef __wglext_h_
+#error Attempt to include auto-generated WGL header after wglext.h
+#endif
+
+#define __wglext_h_
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN 1
+#endif
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif
+#include <windows.h>
+
+#ifdef CODEGEN_FUNCPTR
+#undef CODEGEN_FUNCPTR
+#endif // CODEGEN_FUNCPTR
+#define CODEGEN_FUNCPTR WINAPI
+
+#ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+#define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+#define GLvoid void
+
+#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+#ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+#define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS
+
+
+struct _GPU_DEVICE {
+ DWORD cb;
+ CHAR DeviceName[32];
+ CHAR DeviceString[128];
+ DWORD Flags;
+ RECT rcVirtualScreen;
+};
+DECLARE_HANDLE(HPBUFFERARB);
+DECLARE_HANDLE(HPBUFFEREXT);
+DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);
+DECLARE_HANDLE(HPVIDEODEV);
+DECLARE_HANDLE(HGPUNV);
+DECLARE_HANDLE(HVIDEOINPUTDEVICENV);
+typedef struct _GPU_DEVICE *PGPU_DEVICE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+extern int sfwgl_ext_EXT_swap_control;
+extern int sfwgl_ext_EXT_framebuffer_sRGB;
+extern int sfwgl_ext_ARB_framebuffer_sRGB;
+extern int sfwgl_ext_ARB_multisample;
+extern int sfwgl_ext_ARB_pixel_format;
+extern int sfwgl_ext_ARB_pbuffer;
+extern int sfwgl_ext_ARB_create_context;
+extern int sfwgl_ext_ARB_create_context_profile;
+
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
+
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
+
+#define WGL_SAMPLES_ARB 0x2042
+#define WGL_SAMPLE_BUFFERS_ARB 0x2041
+
+#define WGL_ACCELERATION_ARB 0x2003
+#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
+#define WGL_ACCUM_BITS_ARB 0x201D
+#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
+#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
+#define WGL_ACCUM_RED_BITS_ARB 0x201E
+#define WGL_ALPHA_BITS_ARB 0x201B
+#define WGL_ALPHA_SHIFT_ARB 0x201C
+#define WGL_AUX_BUFFERS_ARB 0x2024
+#define WGL_BLUE_BITS_ARB 0x2019
+#define WGL_BLUE_SHIFT_ARB 0x201A
+#define WGL_COLOR_BITS_ARB 0x2014
+#define WGL_DEPTH_BITS_ARB 0x2022
+#define WGL_DOUBLE_BUFFER_ARB 0x2011
+#define WGL_DRAW_TO_BITMAP_ARB 0x2002
+#define WGL_DRAW_TO_WINDOW_ARB 0x2001
+#define WGL_FULL_ACCELERATION_ARB 0x2027
+#define WGL_GENERIC_ACCELERATION_ARB 0x2026
+#define WGL_GREEN_BITS_ARB 0x2017
+#define WGL_GREEN_SHIFT_ARB 0x2018
+#define WGL_NEED_PALETTE_ARB 0x2004
+#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
+#define WGL_NO_ACCELERATION_ARB 0x2025
+#define WGL_NUMBER_OVERLAYS_ARB 0x2008
+#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
+#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
+#define WGL_PIXEL_TYPE_ARB 0x2013
+#define WGL_RED_BITS_ARB 0x2015
+#define WGL_RED_SHIFT_ARB 0x2017
+#define WGL_SHARE_ACCUM_ARB 0x200E
+#define WGL_SHARE_DEPTH_ARB 0x200C
+#define WGL_SHARE_STENCIL_ARB 0x200D
+#define WGL_STENCIL_BITS_ARB 0x2023
+#define WGL_STEREO_ARB 0x2012
+#define WGL_SUPPORT_GDI_ARB 0x200F
+#define WGL_SUPPORT_OPENGL_ARB 0x2010
+#define WGL_SWAP_COPY_ARB 0x2029
+#define WGL_SWAP_EXCHANGE_ARB 0x2028
+#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
+#define WGL_SWAP_METHOD_ARB 0x2007
+#define WGL_SWAP_UNDEFINED_ARB 0x202A
+#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
+#define WGL_TRANSPARENT_ARB 0x200A
+#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
+#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
+#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
+#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
+#define WGL_TYPE_COLORINDEX_ARB 0x202C
+#define WGL_TYPE_RGBA_ARB 0x202B
+
+#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
+#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
+#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
+#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
+#define WGL_PBUFFER_HEIGHT_ARB 0x2035
+#define WGL_PBUFFER_LARGEST_ARB 0x2033
+#define WGL_PBUFFER_LOST_ARB 0x2036
+#define WGL_PBUFFER_WIDTH_ARB 0x2034
+
+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_ERROR_INVALID_VERSION_ARB 0x2095
+
+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_ERROR_INVALID_PROFILE_ARB 0x2096
+
+#ifndef WGL_EXT_swap_control
+#define WGL_EXT_swap_control 1
+extern int (CODEGEN_FUNCPTR *sf_ptrc_wglGetSwapIntervalEXT)(void);
+#define wglGetSwapIntervalEXT sf_ptrc_wglGetSwapIntervalEXT
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglSwapIntervalEXT)(int);
+#define wglSwapIntervalEXT sf_ptrc_wglSwapIntervalEXT
+#endif // WGL_EXT_swap_control
+
+
+#ifndef WGL_ARB_pixel_format
+#define WGL_ARB_pixel_format 1
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int*, const FLOAT*, UINT, int*, UINT*);
+#define wglChoosePixelFormatARB sf_ptrc_wglChoosePixelFormatARB
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int*, FLOAT*);
+#define wglGetPixelFormatAttribfvARB sf_ptrc_wglGetPixelFormatAttribfvARB
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int*, int*);
+#define wglGetPixelFormatAttribivARB sf_ptrc_wglGetPixelFormatAttribivARB
+#endif // WGL_ARB_pixel_format
+
+#ifndef WGL_ARB_pbuffer
+#define WGL_ARB_pbuffer 1
+extern HPBUFFERARB (CODEGEN_FUNCPTR *sf_ptrc_wglCreatePbufferARB)(HDC, int, int, int, const int*);
+#define wglCreatePbufferARB sf_ptrc_wglCreatePbufferARB
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglDestroyPbufferARB)(HPBUFFERARB);
+#define wglDestroyPbufferARB sf_ptrc_wglDestroyPbufferARB
+extern HDC (CODEGEN_FUNCPTR *sf_ptrc_wglGetPbufferDCARB)(HPBUFFERARB);
+#define wglGetPbufferDCARB sf_ptrc_wglGetPbufferDCARB
+extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglQueryPbufferARB)(HPBUFFERARB, int, int*);
+#define wglQueryPbufferARB sf_ptrc_wglQueryPbufferARB
+extern int (CODEGEN_FUNCPTR *sf_ptrc_wglReleasePbufferDCARB)(HPBUFFERARB, HDC);
+#define wglReleasePbufferDCARB sf_ptrc_wglReleasePbufferDCARB
+#endif // WGL_ARB_pbuffer
+
+#ifndef WGL_ARB_create_context
+#define WGL_ARB_create_context 1
+extern HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int*);
+#define wglCreateContextAttribsARB sf_ptrc_wglCreateContextAttribsARB
+#endif // WGL_ARB_create_context
+
+
+enum sfwgl_LoadStatus
+{
+ sfwgl_LOAD_FAILED = 0,
+ sfwgl_LOAD_SUCCEEDED = 1
+};
+
+int sfwgl_LoadFunctions(HDC hdc);
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SF_POINTER_C_GENERATED_HEADER_WINDOWSGL_HPP
diff --git a/src/SFML/Window/Win32/WglExtensions.txt b/src/SFML/Window/Win32/WglExtensions.txt
new file mode 100644
index 0000000..fa61675
--- /dev/null
+++ b/src/SFML/Window/Win32/WglExtensions.txt
@@ -0,0 +1,13 @@
+// Created with:
+// https://bitbucket.org/KhronosGroup/glloadgen
+// Commit d143d66ac90d538ed06f806188714861b8e8e2f9
+// lua LoadGen.lua -style=pointer_c -spec=wgl -indent=space -prefix=sf -extfile=WglExtensions.txt WglExtensions
+
+EXT_swap_control
+EXT_framebuffer_sRGB
+ARB_framebuffer_sRGB
+WGL_ARB_multisample
+WGL_ARB_pixel_format
+WGL_ARB_pbuffer
+WGL_ARB_create_context
+WGL_ARB_create_context_profile
diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp
new file mode 100755
index 0000000..e8e17fe
--- /dev/null
+++ b/src/SFML/Window/Win32/WindowImplWin32.cpp
@@ -0,0 +1,1166 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#ifdef _WIN32_WINDOWS
+ #undef _WIN32_WINDOWS
+#endif
+#ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+#endif
+#define _WIN32_WINDOWS 0x0501
+#define _WIN32_WINNT 0x0501
+#define WINVER 0x0501
+#include <SFML/Window/Win32/WindowImplWin32.hpp>
+#include <SFML/Window/WindowStyle.hpp>
+#include <GL/gl.h>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Utf.hpp>
+// dbt.h is lowercase here, as a cross-compile on linux with mingw-w64
+// expects lowercase, and a native compile on windows, whether via msvc
+// or mingw-w64 addresses files in a case insensitive manner.
+#include <dbt.h>
+#include <vector>
+#include <cstring>
+
+// MinGW lacks the definition of some Win32 constants
+#ifndef XBUTTON1
+ #define XBUTTON1 0x0001
+#endif
+#ifndef XBUTTON2
+ #define XBUTTON2 0x0002
+#endif
+#ifndef WM_MOUSEHWHEEL
+ #define WM_MOUSEHWHEEL 0x020E
+#endif
+#ifndef MAPVK_VK_TO_VSC
+ #define MAPVK_VK_TO_VSC (0)
+#endif
+
+namespace
+{
+ unsigned int windowCount = 0; // Windows owned by SFML
+ unsigned int handleCount = 0; // All window handles
+ const wchar_t* className = L"SFML_Window";
+ sf::priv::WindowImplWin32* fullscreenWindow = NULL;
+
+ const GUID GUID_DEVINTERFACE_HID = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}};
+
+ void setProcessDpiAware()
+ {
+ // Try SetProcessDpiAwareness first
+ HINSTANCE shCoreDll = LoadLibrary(L"Shcore.dll");
+
+ if (shCoreDll)
+ {
+ enum ProcessDpiAwareness
+ {
+ ProcessDpiUnaware = 0,
+ ProcessSystemDpiAware = 1,
+ ProcessPerMonitorDpiAware = 2
+ };
+
+ typedef HRESULT (WINAPI* SetProcessDpiAwarenessFuncType)(ProcessDpiAwareness);
+ SetProcessDpiAwarenessFuncType SetProcessDpiAwarenessFunc = reinterpret_cast<SetProcessDpiAwarenessFuncType>(GetProcAddress(shCoreDll, "SetProcessDpiAwareness"));
+
+ if (SetProcessDpiAwarenessFunc)
+ {
+ // We only check for E_INVALIDARG because we would get
+ // E_ACCESSDENIED if the DPI was already set previously
+ // and S_OK means the call was successful
+ if (SetProcessDpiAwarenessFunc(ProcessSystemDpiAware) == E_INVALIDARG)
+ {
+ sf::err() << "Failed to set process DPI awareness" << std::endl;
+ }
+ else
+ {
+ FreeLibrary(shCoreDll);
+ return;
+ }
+ }
+
+ FreeLibrary(shCoreDll);
+ }
+
+ // Fall back to SetProcessDPIAware if SetProcessDpiAwareness
+ // is not available on this system
+ HINSTANCE user32Dll = LoadLibrary(L"user32.dll");
+
+ if (user32Dll)
+ {
+ typedef BOOL (WINAPI* SetProcessDPIAwareFuncType)(void);
+ SetProcessDPIAwareFuncType SetProcessDPIAwareFunc = reinterpret_cast<SetProcessDPIAwareFuncType>(GetProcAddress(user32Dll, "SetProcessDPIAware"));
+
+ if (SetProcessDPIAwareFunc)
+ {
+ if (!SetProcessDPIAwareFunc())
+ sf::err() << "Failed to set process DPI awareness" << std::endl;
+ }
+
+ FreeLibrary(user32Dll);
+ }
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+WindowImplWin32::WindowImplWin32(WindowHandle handle) :
+m_handle (handle),
+m_callback (0),
+m_cursorVisible (true), // might need to call GetCursorInfo
+m_lastCursor (LoadCursor(NULL, IDC_ARROW)),
+m_icon (NULL),
+m_keyRepeatEnabled(true),
+m_lastSize (0, 0),
+m_resizing (false),
+m_surrogate (0),
+m_mouseInside (false),
+m_fullscreen (false),
+m_cursorGrabbed (false)
+{
+ // Set that this process is DPI aware and can handle DPI scaling
+ setProcessDpiAware();
+
+ if (m_handle)
+ {
+ // If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received
+ if (handleCount == 0)
+ JoystickImpl::setLazyUpdates(true);
+
+ ++handleCount;
+
+ // We change the event procedure of the control (it is important to save the old one)
+ SetWindowLongPtrW(m_handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
+ m_callback = SetWindowLongPtrW(m_handle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&WindowImplWin32::globalOnEvent));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& /*settings*/) :
+m_handle (NULL),
+m_callback (0),
+m_cursorVisible (true), // might need to call GetCursorInfo
+m_lastCursor (LoadCursor(NULL, IDC_ARROW)),
+m_icon (NULL),
+m_keyRepeatEnabled(true),
+m_lastSize (mode.width, mode.height),
+m_resizing (false),
+m_surrogate (0),
+m_mouseInside (false),
+m_fullscreen ((style & Style::Fullscreen) != 0),
+m_cursorGrabbed (m_fullscreen)
+{
+ // Set that this process is DPI aware and can handle DPI scaling
+ setProcessDpiAware();
+
+ // Register the window class at first call
+ if (windowCount == 0)
+ registerWindowClass();
+
+ // Compute position and size
+ HDC screenDC = GetDC(NULL);
+ int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(mode.width)) / 2;
+ int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(mode.height)) / 2;
+ int width = mode.width;
+ int height = mode.height;
+ ReleaseDC(NULL, screenDC);
+
+ // Choose the window style according to the Style parameter
+ DWORD win32Style = WS_VISIBLE;
+ if (style == Style::None)
+ {
+ win32Style |= WS_POPUP;
+ }
+ else
+ {
+ if (style & Style::Titlebar) win32Style |= WS_CAPTION | WS_MINIMIZEBOX;
+ if (style & Style::Resize) win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
+ if (style & Style::Close) win32Style |= WS_SYSMENU;
+ }
+
+ // In windowed mode, adjust width and height so that window will have the requested client area
+ if (!m_fullscreen)
+ {
+ RECT rectangle = {0, 0, width, height};
+ AdjustWindowRect(&rectangle, win32Style, false);
+ width = rectangle.right - rectangle.left;
+ height = rectangle.bottom - rectangle.top;
+ }
+
+ // Create the window
+ m_handle = CreateWindowW(className, title.toWideString().c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(NULL), this);
+
+ // Register to receive device interface change notifications (used for joystick connection handling)
+ DEV_BROADCAST_DEVICEINTERFACE deviceInterface = {sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE, 0, GUID_DEVINTERFACE_HID, 0};
+ RegisterDeviceNotification(m_handle, &deviceInterface, DEVICE_NOTIFY_WINDOW_HANDLE);
+
+ // If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received
+ if (m_handle)
+ {
+ if (handleCount == 0)
+ JoystickImpl::setLazyUpdates(true);
+
+ ++handleCount;
+ }
+
+ // By default, the OS limits the size of the window the the desktop size,
+ // we have to resize it after creation to apply the real size
+ setSize(Vector2u(mode.width, mode.height));
+
+ // Switch to fullscreen if requested
+ if (m_fullscreen)
+ switchToFullscreen(mode);
+
+ // Increment window count
+ windowCount++;
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplWin32::~WindowImplWin32()
+{
+ // TODO should we restore the cursor shape and visibility?
+
+ // Destroy the custom icon, if any
+ if (m_icon)
+ DestroyIcon(m_icon);
+
+ // If it's the last window handle we have to poll for joysticks again
+ if (m_handle)
+ {
+ --handleCount;
+
+ if (handleCount == 0)
+ JoystickImpl::setLazyUpdates(false);
+ }
+
+ if (!m_callback)
+ {
+ // Destroy the window
+ if (m_handle)
+ DestroyWindow(m_handle);
+
+ // Decrement the window count
+ windowCount--;
+
+ // Unregister window class if we were the last window
+ if (windowCount == 0)
+ UnregisterClassW(className, GetModuleHandleW(NULL));
+ }
+ else
+ {
+ // The window is external: remove the hook on its message callback
+ SetWindowLongPtrW(m_handle, GWLP_WNDPROC, m_callback);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplWin32::getSystemHandle() const
+{
+ return m_handle;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::processEvents()
+{
+ // We process the window events only if we own it
+ if (!m_callback)
+ {
+ MSG message;
+ while (PeekMessageW(&message, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&message);
+ DispatchMessageW(&message);
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplWin32::getPosition() const
+{
+ RECT rect;
+ GetWindowRect(m_handle, &rect);
+
+ return Vector2i(rect.left, rect.top);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setPosition(const Vector2i& position)
+{
+ SetWindowPos(m_handle, NULL, position.x, position.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ if(m_cursorGrabbed)
+ grabCursor(true);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplWin32::getSize() const
+{
+ RECT rect;
+ GetClientRect(m_handle, &rect);
+
+ return Vector2u(rect.right - rect.left, rect.bottom - rect.top);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setSize(const Vector2u& size)
+{
+ // SetWindowPos wants the total size of the window (including title bar and borders),
+ // so we have to compute it
+ RECT rectangle = {0, 0, static_cast<long>(size.x), static_cast<long>(size.y)};
+ AdjustWindowRect(&rectangle, GetWindowLong(m_handle, GWL_STYLE), false);
+ int width = rectangle.right - rectangle.left;
+ int height = rectangle.bottom - rectangle.top;
+
+ SetWindowPos(m_handle, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setTitle(const String& title)
+{
+ SetWindowTextW(m_handle, title.toWideString().c_str());
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ // First destroy the previous one
+ if (m_icon)
+ DestroyIcon(m_icon);
+
+ // Windows wants BGRA pixels: swap red and blue channels
+ std::vector<Uint8> iconPixels(width * height * 4);
+ for (std::size_t i = 0; i < iconPixels.size() / 4; ++i)
+ {
+ iconPixels[i * 4 + 0] = pixels[i * 4 + 2];
+ iconPixels[i * 4 + 1] = pixels[i * 4 + 1];
+ iconPixels[i * 4 + 2] = pixels[i * 4 + 0];
+ iconPixels[i * 4 + 3] = pixels[i * 4 + 3];
+ }
+
+ // Create the icon from the pixel array
+ m_icon = CreateIcon(GetModuleHandleW(NULL), width, height, 1, 32, NULL, &iconPixels[0]);
+
+ // Set it as both big and small icon of the window
+ if (m_icon)
+ {
+ SendMessageW(m_handle, WM_SETICON, ICON_BIG, (LPARAM)m_icon);
+ SendMessageW(m_handle, WM_SETICON, ICON_SMALL, (LPARAM)m_icon);
+ }
+ else
+ {
+ err() << "Failed to set the window's icon" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setVisible(bool visible)
+{
+ ShowWindow(m_handle, visible ? SW_SHOW : SW_HIDE);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setMouseCursorVisible(bool visible)
+{
+ // Don't call twice ShowCursor with the same parameter value;
+ // we don't want to increment/decrement the internal counter
+ // more than once.
+ if (visible != m_cursorVisible)
+ {
+ m_cursorVisible = visible;
+ ShowCursor(visible);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setMouseCursorGrabbed(bool grabbed)
+{
+ m_cursorGrabbed = grabbed;
+ grabCursor(m_cursorGrabbed);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setMouseCursor(const CursorImpl& cursor)
+{
+ m_lastCursor = cursor.m_cursor;
+ SetCursor(m_lastCursor);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setKeyRepeatEnabled(bool enabled)
+{
+ m_keyRepeatEnabled = enabled;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::requestFocus()
+{
+ // Allow focus stealing only within the same process; compare PIDs of current and foreground window
+ DWORD thisPid = GetWindowThreadProcessId(m_handle, NULL);
+ DWORD foregroundPid = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
+
+ if (thisPid == foregroundPid)
+ {
+ // The window requesting focus belongs to the same process as the current window: steal focus
+ SetForegroundWindow(m_handle);
+ }
+ else
+ {
+ // Different process: don't steal focus, but create a taskbar notification ("flash")
+ FLASHWINFO info;
+ info.cbSize = sizeof(info);
+ info.hwnd = m_handle;
+ info.dwFlags = FLASHW_TRAY;
+ info.dwTimeout = 0;
+ info.uCount = 3;
+
+ FlashWindowEx(&info);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplWin32::hasFocus() const
+{
+ return m_handle == GetForegroundWindow();
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::registerWindowClass()
+{
+ WNDCLASSW windowClass;
+ windowClass.style = 0;
+ windowClass.lpfnWndProc = &WindowImplWin32::globalOnEvent;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = 0;
+ windowClass.hInstance = GetModuleHandleW(NULL);
+ windowClass.hIcon = NULL;
+ windowClass.hCursor = 0;
+ windowClass.hbrBackground = 0;
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = className;
+ RegisterClassW(&windowClass);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::switchToFullscreen(const VideoMode& mode)
+{
+ DEVMODE devMode;
+ devMode.dmSize = sizeof(devMode);
+ devMode.dmPelsWidth = mode.width;
+ devMode.dmPelsHeight = mode.height;
+ devMode.dmBitsPerPel = mode.bitsPerPixel;
+ devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
+
+ // Apply fullscreen mode
+ if (ChangeDisplaySettingsW(&devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
+ {
+ err() << "Failed to change display mode for fullscreen" << std::endl;
+ return;
+ }
+
+ // Make the window flags compatible with fullscreen mode
+ SetWindowLongW(m_handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ SetWindowLongW(m_handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
+
+ // Resize the window so that it fits the entire screen
+ SetWindowPos(m_handle, HWND_TOP, 0, 0, mode.width, mode.height, SWP_FRAMECHANGED);
+ ShowWindow(m_handle, SW_SHOW);
+
+ // Set "this" as the current fullscreen window
+ fullscreenWindow = this;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::cleanup()
+{
+ // Restore the previous video mode (in case we were running in fullscreen)
+ if (fullscreenWindow == this)
+ {
+ ChangeDisplaySettingsW(NULL, 0);
+ fullscreenWindow = NULL;
+ }
+
+ // Unhide the mouse cursor (in case it was hidden)
+ setMouseCursorVisible(true);
+
+ // No longer track the cursor
+ setTracking(false);
+
+ // No longer capture the cursor
+ ReleaseCapture();
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::setTracking(bool track)
+{
+ TRACKMOUSEEVENT mouseEvent;
+ mouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ mouseEvent.dwFlags = track ? TME_LEAVE : TME_CANCEL;
+ mouseEvent.hwndTrack = m_handle;
+ mouseEvent.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&mouseEvent);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::grabCursor(bool grabbed)
+{
+ if (grabbed)
+ {
+ RECT rect;
+ GetClientRect(m_handle, &rect);
+ MapWindowPoints(m_handle, NULL, reinterpret_cast<LPPOINT>(&rect), 2);
+ ClipCursor(&rect);
+ }
+ else
+ {
+ ClipCursor(NULL);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // Don't process any message until window is created
+ if (m_handle == NULL)
+ return;
+
+ switch (message)
+ {
+ // Destroy event
+ case WM_DESTROY:
+ {
+ // Here we must cleanup resources !
+ cleanup();
+ break;
+ }
+
+ // Set cursor event
+ case WM_SETCURSOR:
+ {
+ // The mouse has moved, if the cursor is in our window we must refresh the cursor
+ if (LOWORD(lParam) == HTCLIENT)
+ SetCursor(m_lastCursor);
+
+ break;
+ }
+
+ // Close event
+ case WM_CLOSE:
+ {
+ Event event;
+ event.type = Event::Closed;
+ pushEvent(event);
+ break;
+ }
+
+ // Resize event
+ case WM_SIZE:
+ {
+ // Consider only events triggered by a maximize or a un-maximize
+ if (wParam != SIZE_MINIMIZED && !m_resizing && m_lastSize != getSize())
+ {
+ // Update the last handled size
+ m_lastSize = getSize();
+
+ // Push a resize event
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = m_lastSize.x;
+ event.size.height = m_lastSize.y;
+ pushEvent(event);
+
+ // Restore/update cursor grabbing
+ grabCursor(m_cursorGrabbed);
+ }
+ break;
+ }
+
+ // Start resizing
+ case WM_ENTERSIZEMOVE:
+ {
+ m_resizing = true;
+ grabCursor(false);
+ break;
+ }
+
+ // Stop resizing
+ case WM_EXITSIZEMOVE:
+ {
+ m_resizing = false;
+
+ // Ignore cases where the window has only been moved
+ if(m_lastSize != getSize())
+ {
+ // Update the last handled size
+ m_lastSize = getSize();
+
+ // Push a resize event
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = m_lastSize.x;
+ event.size.height = m_lastSize.y;
+ pushEvent(event);
+ }
+
+ // Restore/update cursor grabbing
+ grabCursor(m_cursorGrabbed);
+ break;
+ }
+
+ // The system request the min/max window size and position
+ case WM_GETMINMAXINFO:
+ {
+ // We override the returned information to remove the default limit
+ // (the OS doesn't allow windows bigger than the desktop by default)
+ MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lParam);
+ info->ptMaxTrackSize.x = 50000;
+ info->ptMaxTrackSize.y = 50000;
+ break;
+ }
+
+ // Gain focus event
+ case WM_SETFOCUS:
+ {
+ // Restore cursor grabbing
+ grabCursor(m_cursorGrabbed);
+
+ Event event;
+ event.type = Event::GainedFocus;
+ pushEvent(event);
+ break;
+ }
+
+ // Lost focus event
+ case WM_KILLFOCUS:
+ {
+ // Ungrab the cursor
+ grabCursor(false);
+
+ Event event;
+ event.type = Event::LostFocus;
+ pushEvent(event);
+ break;
+ }
+
+ // Text event
+ case WM_CHAR:
+ {
+ if (m_keyRepeatEnabled || ((lParam & (1 << 30)) == 0))
+ {
+ // Get the code of the typed character
+ Uint32 character = static_cast<Uint32>(wParam);
+
+ // Check if it is the first part of a surrogate pair, or a regular character
+ if ((character >= 0xD800) && (character <= 0xDBFF))
+ {
+ // First part of a surrogate pair: store it and wait for the second one
+ m_surrogate = static_cast<Uint16>(character);
+ }
+ else
+ {
+ // Check if it is the second part of a surrogate pair, or a regular character
+ if ((character >= 0xDC00) && (character <= 0xDFFF))
+ {
+ // Convert the UTF-16 surrogate pair to a single UTF-32 value
+ Uint16 utf16[] = {m_surrogate, static_cast<Uint16>(character)};
+ sf::Utf16::toUtf32(utf16, utf16 + 2, &character);
+ m_surrogate = 0;
+ }
+
+ // Send a TextEntered event
+ Event event;
+ event.type = Event::TextEntered;
+ event.text.unicode = character;
+ pushEvent(event);
+ }
+ }
+ break;
+ }
+
+ // Keydown event
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ if (m_keyRepeatEnabled || ((HIWORD(lParam) & KF_REPEAT) == 0))
+ {
+ Event event;
+ event.type = Event::KeyPressed;
+ event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
+ event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
+ event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
+ event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
+ event.key.code = virtualKeyCodeToSF(wParam, lParam);
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Keyup event
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ {
+ Event event;
+ event.type = Event::KeyReleased;
+ event.key.alt = HIWORD(GetKeyState(VK_MENU)) != 0;
+ event.key.control = HIWORD(GetKeyState(VK_CONTROL)) != 0;
+ event.key.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0;
+ event.key.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN));
+ event.key.code = virtualKeyCodeToSF(wParam, lParam);
+ pushEvent(event);
+ break;
+ }
+
+ // Vertical mouse wheel event
+ case WM_MOUSEWHEEL:
+ {
+ // Mouse position is in screen coordinates, convert it to window coordinates
+ POINT position;
+ position.x = static_cast<Int16>(LOWORD(lParam));
+ position.y = static_cast<Int16>(HIWORD(lParam));
+ ScreenToClient(m_handle, &position);
+
+ Int16 delta = static_cast<Int16>(HIWORD(wParam));
+
+ Event event;
+
+ event.type = Event::MouseWheelMoved;
+ event.mouseWheel.delta = delta / 120;
+ event.mouseWheel.x = position.x;
+ event.mouseWheel.y = position.y;
+ pushEvent(event);
+
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::VerticalWheel;
+ event.mouseWheelScroll.delta = static_cast<float>(delta) / 120.f;
+ event.mouseWheelScroll.x = position.x;
+ event.mouseWheelScroll.y = position.y;
+ pushEvent(event);
+ break;
+ }
+
+ // Horizontal mouse wheel event
+ case WM_MOUSEHWHEEL:
+ {
+ // Mouse position is in screen coordinates, convert it to window coordinates
+ POINT position;
+ position.x = static_cast<Int16>(LOWORD(lParam));
+ position.y = static_cast<Int16>(HIWORD(lParam));
+ ScreenToClient(m_handle, &position);
+
+ Int16 delta = static_cast<Int16>(HIWORD(wParam));
+
+ Event event;
+ event.type = Event::MouseWheelScrolled;
+ event.mouseWheelScroll.wheel = Mouse::HorizontalWheel;
+ event.mouseWheelScroll.delta = -static_cast<float>(delta) / 120.f;
+ event.mouseWheelScroll.x = position.x;
+ event.mouseWheelScroll.y = position.y;
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse left button down event
+ case WM_LBUTTONDOWN:
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = Mouse::Left;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse left button up event
+ case WM_LBUTTONUP:
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = Mouse::Left;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse right button down event
+ case WM_RBUTTONDOWN:
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = Mouse::Right;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse right button up event
+ case WM_RBUTTONUP:
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = Mouse::Right;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse wheel button down event
+ case WM_MBUTTONDOWN:
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = Mouse::Middle;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse wheel button up event
+ case WM_MBUTTONUP:
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = Mouse::Middle;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse X button down event
+ case WM_XBUTTONDOWN:
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.button = HIWORD(wParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse X button up event
+ case WM_XBUTTONUP:
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.button = HIWORD(wParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
+ event.mouseButton.x = static_cast<Int16>(LOWORD(lParam));
+ event.mouseButton.y = static_cast<Int16>(HIWORD(lParam));
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse leave event
+ case WM_MOUSELEAVE:
+ {
+ // Avoid this firing a second time in case the cursor is dragged outside
+ if (m_mouseInside)
+ {
+ m_mouseInside = false;
+
+ // Generate a MouseLeft event
+ Event event;
+ event.type = Event::MouseLeft;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse move event
+ case WM_MOUSEMOVE:
+ {
+ // Extract the mouse local coordinates
+ int x = static_cast<Int16>(LOWORD(lParam));
+ int y = static_cast<Int16>(HIWORD(lParam));
+
+ // Get the client area of the window
+ RECT area;
+ GetClientRect(m_handle, &area);
+
+ // Capture the mouse in case the user wants to drag it outside
+ if ((wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2)) == 0)
+ {
+ // Only release the capture if we really have it
+ if (GetCapture() == m_handle)
+ ReleaseCapture();
+ }
+ else if (GetCapture() != m_handle)
+ {
+ // Set the capture to continue receiving mouse events
+ SetCapture(m_handle);
+ }
+
+ // If the cursor is outside the client area...
+ if ((x < area.left) || (x > area.right) || (y < area.top) || (y > area.bottom))
+ {
+ // and it used to be inside, the mouse left it.
+ if (m_mouseInside)
+ {
+ m_mouseInside = false;
+
+ // No longer care for the mouse leaving the window
+ setTracking(false);
+
+ // Generate a MouseLeft event
+ Event event;
+ event.type = Event::MouseLeft;
+ pushEvent(event);
+ }
+ }
+ else
+ {
+ // and vice-versa
+ if (!m_mouseInside)
+ {
+ m_mouseInside = true;
+
+ // Look for the mouse leaving the window
+ setTracking(true);
+
+ // Generate a MouseEntered event
+ Event event;
+ event.type = Event::MouseEntered;
+ pushEvent(event);
+ }
+ }
+
+ // Generate a MouseMove event
+ Event event;
+ event.type = Event::MouseMoved;
+ event.mouseMove.x = x;
+ event.mouseMove.y = y;
+ pushEvent(event);
+ break;
+ }
+ case WM_DEVICECHANGE:
+ {
+ // Some sort of device change has happened, update joystick connections
+ if ((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE))
+ {
+ // Some sort of device change has happened, update joystick connections if it is a device interface
+ DEV_BROADCAST_HDR* deviceBroadcastHeader = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
+
+ if (deviceBroadcastHeader && (deviceBroadcastHeader->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
+ JoystickImpl::updateConnections();
+ }
+
+ break;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Keyboard::Key WindowImplWin32::virtualKeyCodeToSF(WPARAM key, LPARAM flags)
+{
+ switch (key)
+ {
+ // Check the scancode to distinguish between left and right shift
+ case VK_SHIFT:
+ {
+ static UINT lShift = MapVirtualKeyW(VK_LSHIFT, MAPVK_VK_TO_VSC);
+ UINT scancode = static_cast<UINT>((flags & (0xFF << 16)) >> 16);
+ return scancode == lShift ? Keyboard::LShift : Keyboard::RShift;
+ }
+
+ // Check the "extended" flag to distinguish between left and right alt
+ case VK_MENU : return (HIWORD(flags) & KF_EXTENDED) ? Keyboard::RAlt : Keyboard::LAlt;
+
+ // Check the "extended" flag to distinguish between left and right control
+ case VK_CONTROL : return (HIWORD(flags) & KF_EXTENDED) ? Keyboard::RControl : Keyboard::LControl;
+
+ // Other keys are reported properly
+ case VK_LWIN: return Keyboard::LSystem;
+ case VK_RWIN: return Keyboard::RSystem;
+ case VK_APPS: return Keyboard::Menu;
+ case VK_OEM_1: return Keyboard::Semicolon;
+ case VK_OEM_2: return Keyboard::Slash;
+ case VK_OEM_PLUS: return Keyboard::Equal;
+ case VK_OEM_MINUS: return Keyboard::Hyphen;
+ case VK_OEM_4: return Keyboard::LBracket;
+ case VK_OEM_6: return Keyboard::RBracket;
+ case VK_OEM_COMMA: return Keyboard::Comma;
+ case VK_OEM_PERIOD: return Keyboard::Period;
+ case VK_OEM_7: return Keyboard::Quote;
+ case VK_OEM_5: return Keyboard::Backslash;
+ case VK_OEM_3: return Keyboard::Tilde;
+ case VK_ESCAPE: return Keyboard::Escape;
+ case VK_SPACE: return Keyboard::Space;
+ case VK_RETURN: return Keyboard::Enter;
+ case VK_BACK: return Keyboard::Backspace;
+ case VK_TAB: return Keyboard::Tab;
+ case VK_PRIOR: return Keyboard::PageUp;
+ case VK_NEXT: return Keyboard::PageDown;
+ case VK_END: return Keyboard::End;
+ case VK_HOME: return Keyboard::Home;
+ case VK_INSERT: return Keyboard::Insert;
+ case VK_DELETE: return Keyboard::Delete;
+ case VK_ADD: return Keyboard::Add;
+ case VK_SUBTRACT: return Keyboard::Subtract;
+ case VK_MULTIPLY: return Keyboard::Multiply;
+ case VK_DIVIDE: return Keyboard::Divide;
+ case VK_PAUSE: return Keyboard::Pause;
+ case VK_F1: return Keyboard::F1;
+ case VK_F2: return Keyboard::F2;
+ case VK_F3: return Keyboard::F3;
+ case VK_F4: return Keyboard::F4;
+ case VK_F5: return Keyboard::F5;
+ case VK_F6: return Keyboard::F6;
+ case VK_F7: return Keyboard::F7;
+ case VK_F8: return Keyboard::F8;
+ case VK_F9: return Keyboard::F9;
+ case VK_F10: return Keyboard::F10;
+ case VK_F11: return Keyboard::F11;
+ case VK_F12: return Keyboard::F12;
+ case VK_F13: return Keyboard::F13;
+ case VK_F14: return Keyboard::F14;
+ case VK_F15: return Keyboard::F15;
+ case VK_LEFT: return Keyboard::Left;
+ case VK_RIGHT: return Keyboard::Right;
+ case VK_UP: return Keyboard::Up;
+ case VK_DOWN: return Keyboard::Down;
+ case VK_NUMPAD0: return Keyboard::Numpad0;
+ case VK_NUMPAD1: return Keyboard::Numpad1;
+ case VK_NUMPAD2: return Keyboard::Numpad2;
+ case VK_NUMPAD3: return Keyboard::Numpad3;
+ case VK_NUMPAD4: return Keyboard::Numpad4;
+ case VK_NUMPAD5: return Keyboard::Numpad5;
+ case VK_NUMPAD6: return Keyboard::Numpad6;
+ case VK_NUMPAD7: return Keyboard::Numpad7;
+ case VK_NUMPAD8: return Keyboard::Numpad8;
+ case VK_NUMPAD9: return Keyboard::Numpad9;
+ case 'A': return Keyboard::A;
+ case 'Z': return Keyboard::Z;
+ case 'E': return Keyboard::E;
+ case 'R': return Keyboard::R;
+ case 'T': return Keyboard::T;
+ case 'Y': return Keyboard::Y;
+ case 'U': return Keyboard::U;
+ case 'I': return Keyboard::I;
+ case 'O': return Keyboard::O;
+ case 'P': return Keyboard::P;
+ case 'Q': return Keyboard::Q;
+ case 'S': return Keyboard::S;
+ case 'D': return Keyboard::D;
+ case 'F': return Keyboard::F;
+ case 'G': return Keyboard::G;
+ case 'H': return Keyboard::H;
+ case 'J': return Keyboard::J;
+ case 'K': return Keyboard::K;
+ case 'L': return Keyboard::L;
+ case 'M': return Keyboard::M;
+ case 'W': return Keyboard::W;
+ case 'X': return Keyboard::X;
+ case 'C': return Keyboard::C;
+ case 'V': return Keyboard::V;
+ case 'B': return Keyboard::B;
+ case 'N': return Keyboard::N;
+ case '0': return Keyboard::Num0;
+ case '1': return Keyboard::Num1;
+ case '2': return Keyboard::Num2;
+ case '3': return Keyboard::Num3;
+ case '4': return Keyboard::Num4;
+ case '5': return Keyboard::Num5;
+ case '6': return Keyboard::Num6;
+ case '7': return Keyboard::Num7;
+ case '8': return Keyboard::Num8;
+ case '9': return Keyboard::Num9;
+ }
+
+ return Keyboard::Unknown;
+}
+
+
+////////////////////////////////////////////////////////////
+LRESULT CALLBACK WindowImplWin32::globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // Associate handle and Window instance when the creation message is received
+ if (message == WM_CREATE)
+ {
+ // Get WindowImplWin32 instance (it was passed as the last argument of CreateWindow)
+ LONG_PTR window = (LONG_PTR)reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams;
+
+ // Set as the "user data" parameter of the window
+ SetWindowLongPtrW(handle, GWLP_USERDATA, window);
+ }
+
+ // Get the WindowImpl instance corresponding to the window handle
+ WindowImplWin32* window = handle ? reinterpret_cast<WindowImplWin32*>(GetWindowLongPtr(handle, GWLP_USERDATA)) : NULL;
+
+ // Forward the event to the appropriate function
+ if (window)
+ {
+ window->processEvent(message, wParam, lParam);
+
+ if (window->m_callback)
+ return CallWindowProcW(reinterpret_cast<WNDPROC>(window->m_callback), handle, message, wParam, lParam);
+ }
+
+ // We don't forward the WM_CLOSE message to prevent the OS from automatically destroying the window
+ if (message == WM_CLOSE)
+ return 0;
+
+ // Don't forward the menu system command, so that pressing ALT or F10 doesn't steal the focus
+ if ((message == WM_SYSCOMMAND) && (wParam == SC_KEYMENU))
+ return 0;
+
+ return DefWindowProcW(handle, message, wParam, lParam);
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/Win32/WindowImplWin32.hpp b/src/SFML/Window/Win32/WindowImplWin32.hpp
new file mode 100755
index 0000000..4114c51
--- /dev/null
+++ b/src/SFML/Window/Win32/WindowImplWin32.hpp
@@ -0,0 +1,293 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_WINDOWIMPLWIN32_HPP
+#define SFML_WINDOWIMPLWIN32_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <windows.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Windows implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplWin32 : public WindowImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplWin32(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplWin32();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Grab or release the mouse cursor
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// Register the window class
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerWindowClass();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Switch to fullscreen mode
+ ///
+ /// \param mode Video mode to switch to
+ ///
+ ////////////////////////////////////////////////////////////
+ void switchToFullscreen(const VideoMode& mode);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Free all the graphical resources attached to the window
+ ///
+ ////////////////////////////////////////////////////////////
+ void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process a Win32 event
+ ///
+ /// \param message Message to process
+ /// \param wParam First parameter of the event
+ /// \param lParam Second parameter of the event
+ ///
+ ////////////////////////////////////////////////////////////
+ void processEvent(UINT message, WPARAM wParam, LPARAM lParam);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enables or disables tracking for the mouse cursor leaving the window
+ ///
+ /// \param track True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setTracking(bool track);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Grab or release the mouse cursor
+ ///
+ /// This is not to be confused with setMouseCursorGrabbed.
+ /// Here m_cursorGrabbed is not modified; it is used,
+ /// for example, to release the cursor when switching to
+ /// another application.
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void grabCursor(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a Win32 virtual key code to a SFML key code
+ ///
+ /// \param key Virtual key code to convert
+ /// \param flags Additional flags
+ ///
+ /// \return SFML key code corresponding to the key
+ ///
+ ////////////////////////////////////////////////////////////
+ static Keyboard::Key virtualKeyCodeToSF(WPARAM key, LPARAM flags);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Function called whenever one of our windows receives a message
+ ///
+ /// \param handle Win32 handle of the window
+ /// \param message Message received
+ /// \param wParam First parameter of the message
+ /// \param lParam Second parameter of the message
+ ///
+ /// \return True to discard the event after it has been processed
+ ///
+ ////////////////////////////////////////////////////////////
+ static LRESULT CALLBACK globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ HWND m_handle; ///< Win32 handle of the window
+ LONG_PTR m_callback; ///< Stores the original event callback function of the control
+ bool m_cursorVisible; ///< Is the cursor visible or hidden?
+ HCURSOR m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
+ HICON m_icon; ///< Custom icon assigned to the window
+ bool m_keyRepeatEnabled; ///< Automatic key-repeat state for keydown events
+ Vector2u m_lastSize; ///< The last handled size of the window
+ bool m_resizing; ///< Is the window being resized?
+ Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events
+ bool m_mouseInside; ///< Mouse is inside the window?
+ bool m_fullscreen; ///< Is the window fullscreen?
+ bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_WINDOWIMPLWIN32_HPP
diff --git a/src/SFML/Window/Window.cpp b/src/SFML/Window/Window.cpp
new file mode 100644
index 0000000..b1ed548
--- /dev/null
+++ b/src/SFML/Window/Window.cpp
@@ -0,0 +1,449 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Window.hpp>
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace
+{
+ const sf::Window* fullscreenWindow = NULL;
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+Window::Window() :
+m_impl (NULL),
+m_context (NULL),
+m_frameTimeLimit(Time::Zero),
+m_size (0, 0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+Window::Window(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings) :
+m_impl (NULL),
+m_context (NULL),
+m_frameTimeLimit(Time::Zero),
+m_size (0, 0)
+{
+ create(mode, title, style, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+Window::Window(WindowHandle handle, const ContextSettings& settings) :
+m_impl (NULL),
+m_context (NULL),
+m_frameTimeLimit(Time::Zero),
+m_size (0, 0)
+{
+ create(handle, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+Window::~Window()
+{
+ close();
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
+{
+ // Destroy the previous window implementation
+ close();
+
+ // Fullscreen style requires some tests
+ if (style & Style::Fullscreen)
+ {
+ // Make sure there's not already a fullscreen window (only one is allowed)
+ if (fullscreenWindow)
+ {
+ err() << "Creating two fullscreen windows is not allowed, switching to windowed mode" << std::endl;
+ style &= ~Style::Fullscreen;
+ }
+ else
+ {
+ // Make sure that the chosen video mode is compatible
+ if (!mode.isValid())
+ {
+ err() << "The requested video mode is not available, switching to a valid mode" << std::endl;
+ mode = VideoMode::getFullscreenModes()[0];
+ }
+
+ // Update the fullscreen window
+ fullscreenWindow = this;
+ }
+ }
+
+ // Check validity of style according to the underlying platform
+ #if defined(SFML_SYSTEM_IOS) || defined(SFML_SYSTEM_ANDROID)
+ if (style & Style::Fullscreen)
+ style &= ~Style::Titlebar;
+ else
+ style |= Style::Titlebar;
+ #else
+ if ((style & Style::Close) || (style & Style::Resize))
+ style |= Style::Titlebar;
+ #endif
+
+ // Recreate the window implementation
+ m_impl = priv::WindowImpl::create(mode, title, style, settings);
+
+ // Recreate the context
+ m_context = priv::GlContext::create(settings, m_impl, mode.bitsPerPixel);
+
+ // Perform common initializations
+ initialize();
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::create(WindowHandle handle, const ContextSettings& settings)
+{
+ // Destroy the previous window implementation
+ close();
+
+ // Recreate the window implementation
+ m_impl = priv::WindowImpl::create(handle);
+
+ // Recreate the context
+ m_context = priv::GlContext::create(settings, m_impl, VideoMode::getDesktopMode().bitsPerPixel);
+
+ // Perform common initializations
+ initialize();
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::close()
+{
+ // Delete the context
+ delete m_context;
+ m_context = NULL;
+
+ // Delete the window implementation
+ delete m_impl;
+ m_impl = NULL;
+
+ // Update the fullscreen window
+ if (this == fullscreenWindow)
+ fullscreenWindow = NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::isOpen() const
+{
+ return m_impl != NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+const ContextSettings& Window::getSettings() const
+{
+ static const ContextSettings empty(0, 0, 0);
+
+ return m_context ? m_context->getSettings() : empty;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::pollEvent(Event& event)
+{
+ if (m_impl && m_impl->popEvent(event, false))
+ {
+ return filterEvent(event);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::waitEvent(Event& event)
+{
+ if (m_impl && m_impl->popEvent(event, true))
+ {
+ return filterEvent(event);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i Window::getPosition() const
+{
+ return m_impl ? m_impl->getPosition() : Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setPosition(const Vector2i& position)
+{
+ if (m_impl)
+ m_impl->setPosition(position);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u Window::getSize() const
+{
+ return m_size;
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setSize(const Vector2u& size)
+{
+ if (m_impl)
+ {
+ m_impl->setSize(size);
+
+ // Cache the new size
+ m_size.x = size.x;
+ m_size.y = size.y;
+
+ // Notify the derived class
+ onResize();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setTitle(const String& title)
+{
+ if (m_impl)
+ m_impl->setTitle(title);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ if (m_impl)
+ m_impl->setIcon(width, height, pixels);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setVisible(bool visible)
+{
+ if (m_impl)
+ m_impl->setVisible(visible);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setVerticalSyncEnabled(bool enabled)
+{
+ if (setActive())
+ m_context->setVerticalSyncEnabled(enabled);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setMouseCursorVisible(bool visible)
+{
+ if (m_impl)
+ m_impl->setMouseCursorVisible(visible);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setMouseCursorGrabbed(bool grabbed)
+{
+ if (m_impl)
+ m_impl->setMouseCursorGrabbed(grabbed);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setMouseCursor(const Cursor& cursor)
+{
+ if (m_impl)
+ m_impl->setMouseCursor(cursor.getImpl());
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setKeyRepeatEnabled(bool enabled)
+{
+ if (m_impl)
+ m_impl->setKeyRepeatEnabled(enabled);
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setFramerateLimit(unsigned int limit)
+{
+ if (limit > 0)
+ m_frameTimeLimit = seconds(1.f / limit);
+ else
+ m_frameTimeLimit = Time::Zero;
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::setJoystickThreshold(float threshold)
+{
+ if (m_impl)
+ m_impl->setJoystickThreshold(threshold);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::setActive(bool active) const
+{
+ if (m_context)
+ {
+ if (m_context->setActive(active))
+ {
+ return true;
+ }
+ else
+ {
+ err() << "Failed to activate the window's context" << std::endl;
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::requestFocus()
+{
+ if (m_impl)
+ m_impl->requestFocus();
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::hasFocus() const
+{
+ return m_impl && m_impl->hasFocus();
+}
+
+
+////////////////////////////////////////////////////////////
+
+void Window::display()
+{
+ // Display the backbuffer on screen
+ if (setActive())
+ m_context->display();
+
+ // Limit the framerate if needed
+ if (m_frameTimeLimit != Time::Zero)
+ {
+ sleep(m_frameTimeLimit - m_clock.getElapsedTime());
+ m_clock.restart();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle Window::getSystemHandle() const
+{
+ return m_impl ? m_impl->getSystemHandle() : 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::onCreate()
+{
+ // Nothing by default
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::onResize()
+{
+ // Nothing by default
+}
+
+
+////////////////////////////////////////////////////////////
+bool Window::filterEvent(const Event& event)
+{
+ // Notify resize events to the derived class
+ if (event.type == Event::Resized)
+ {
+ // Cache the new size
+ m_size.x = event.size.width;
+ m_size.y = event.size.height;
+
+ // Notify the derived class
+ onResize();
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Window::initialize()
+{
+ // Setup default behaviors (to get a consistent behavior across different implementations)
+ setVisible(true);
+ setMouseCursorVisible(true);
+ setVerticalSyncEnabled(false);
+ setKeyRepeatEnabled(true);
+ setFramerateLimit(0);
+
+ // Get and cache the initial size of the window
+ m_size = m_impl->getSize();
+
+ // Reset frame time
+ m_clock.restart();
+
+ // Activate the window
+ setActive();
+
+ // Notify the derived class
+ onCreate();
+}
+
+} // namespace sf
diff --git a/src/SFML/Window/WindowImpl.cpp b/src/SFML/Window/WindowImpl.cpp
new file mode 100644
index 0000000..3de404a
--- /dev/null
+++ b/src/SFML/Window/WindowImpl.cpp
@@ -0,0 +1,266 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/JoystickManager.hpp>
+#include <SFML/Window/SensorManager.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <algorithm>
+#include <cmath>
+
+#if defined(SFML_SYSTEM_WINDOWS)
+
+ #include <SFML/Window/Win32/WindowImplWin32.hpp>
+ typedef sf::priv::WindowImplWin32 WindowImplType;
+
+#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD)
+
+ #include <SFML/Window/Unix/WindowImplX11.hpp>
+ typedef sf::priv::WindowImplX11 WindowImplType;
+
+#elif defined(SFML_SYSTEM_MACOS)
+
+ #include <SFML/Window/OSX/WindowImplCocoa.hpp>
+ typedef sf::priv::WindowImplCocoa WindowImplType;
+
+#elif defined(SFML_SYSTEM_IOS)
+
+ #include <SFML/Window/iOS/WindowImplUIKit.hpp>
+ typedef sf::priv::WindowImplUIKit WindowImplType;
+
+#elif defined(SFML_SYSTEM_ANDROID)
+
+ #include <SFML/Window/Android/WindowImplAndroid.hpp>
+ typedef sf::priv::WindowImplAndroid WindowImplType;
+
+#endif
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+WindowImpl* WindowImpl::create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
+{
+ return new WindowImplType(mode, title, style, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImpl* WindowImpl::create(WindowHandle handle)
+{
+ return new WindowImplType(handle);
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImpl::WindowImpl() :
+m_joystickThreshold(0.1f)
+{
+ // Get the initial joystick states
+ JoystickManager::getInstance().update();
+ for (unsigned int i = 0; i < Joystick::Count; ++i)
+ {
+ m_joystickStates[i] = JoystickManager::getInstance().getState(i);
+ std::fill_n(m_previousAxes[i], static_cast<std::size_t>(Joystick::AxisCount), 0.f);
+ }
+
+ // Get the initial sensor states
+ for (unsigned int i = 0; i < Sensor::Count; ++i)
+ m_sensorValue[i] = Vector3f(0, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImpl::~WindowImpl()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImpl::setJoystickThreshold(float threshold)
+{
+ m_joystickThreshold = threshold;
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImpl::popEvent(Event& event, bool block)
+{
+ // If the event queue is empty, let's first check if new events are available from the OS
+ if (m_events.empty())
+ {
+ // Get events from the system
+ processJoystickEvents();
+ processSensorEvents();
+ processEvents();
+
+ // In blocking mode, we must process events until one is triggered
+ if (block)
+ {
+ // Here we use a manual wait loop instead of the optimized
+ // wait-event provided by the OS, so that we don't skip joystick
+ // events (which require polling)
+ while (m_events.empty())
+ {
+ sleep(milliseconds(10));
+ processJoystickEvents();
+ processSensorEvents();
+ processEvents();
+ }
+ }
+ }
+
+ // Pop the first event of the queue, if it is not empty
+ if (!m_events.empty())
+ {
+ event = m_events.front();
+ m_events.pop();
+
+ return true;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImpl::pushEvent(const Event& event)
+{
+ m_events.push(event);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImpl::processJoystickEvents()
+{
+ // First update the global joystick states
+ JoystickManager::getInstance().update();
+
+ for (unsigned int i = 0; i < Joystick::Count; ++i)
+ {
+ // Copy the previous state of the joystick and get the new one
+ JoystickState previousState = m_joystickStates[i];
+ m_joystickStates[i] = JoystickManager::getInstance().getState(i);
+ JoystickCaps caps = JoystickManager::getInstance().getCapabilities(i);
+
+ // Connection state
+ bool connected = m_joystickStates[i].connected;
+ if (previousState.connected ^ connected)
+ {
+ Event event;
+ event.type = connected ? Event::JoystickConnected : Event::JoystickDisconnected;
+ event.joystickButton.joystickId = i;
+ pushEvent(event);
+
+ // Clear previous axes positions
+ if (connected)
+ std::fill_n(m_previousAxes[i], static_cast<std::size_t>(Joystick::AxisCount), 0.f);
+ }
+
+ if (connected)
+ {
+ // Axes
+ for (unsigned int j = 0; j < Joystick::AxisCount; ++j)
+ {
+ if (caps.axes[j])
+ {
+ Joystick::Axis axis = static_cast<Joystick::Axis>(j);
+ float prevPos = m_previousAxes[i][axis];
+ float currPos = m_joystickStates[i].axes[axis];
+ if (fabs(currPos - prevPos) >= m_joystickThreshold)
+ {
+ Event event;
+ event.type = Event::JoystickMoved;
+ event.joystickMove.joystickId = i;
+ event.joystickMove.axis = axis;
+ event.joystickMove.position = currPos;
+ pushEvent(event);
+
+ m_previousAxes[i][axis] = currPos;
+ }
+ }
+ }
+
+ // Buttons
+ for (unsigned int j = 0; j < caps.buttonCount; ++j)
+ {
+ bool prevPressed = previousState.buttons[j];
+ bool currPressed = m_joystickStates[i].buttons[j];
+
+ if (prevPressed ^ currPressed)
+ {
+ Event event;
+ event.type = currPressed ? Event::JoystickButtonPressed : Event::JoystickButtonReleased;
+ event.joystickButton.joystickId = i;
+ event.joystickButton.button = j;
+ pushEvent(event);
+ }
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImpl::processSensorEvents()
+{
+ // First update the sensor states
+ SensorManager::getInstance().update();
+
+ for (unsigned int i = 0; i < Sensor::Count; ++i)
+ {
+ Sensor::Type sensor = static_cast<Sensor::Type>(i);
+
+ // Only process enabled sensors
+ if (SensorManager::getInstance().isEnabled(sensor))
+ {
+ // Copy the previous value of the sensor and get the new one
+ Vector3f previousValue = m_sensorValue[i];
+ m_sensorValue[i] = SensorManager::getInstance().getValue(sensor);
+
+ // If the value has changed, trigger an event
+ if (m_sensorValue[i] != previousValue) // @todo use a threshold?
+ {
+ Event event;
+ event.type = Event::SensorChanged;
+ event.sensor.type = sensor;
+ event.sensor.x = m_sensorValue[i].x;
+ event.sensor.y = m_sensorValue[i].y;
+ event.sensor.z = m_sensorValue[i].z;
+ pushEvent(event);
+ }
+ }
+ }
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/WindowImpl.hpp b/src/SFML/Window/WindowImpl.hpp
new file mode 100644
index 0000000..a360a01
--- /dev/null
+++ b/src/SFML/Window/WindowImpl.hpp
@@ -0,0 +1,285 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_WINDOWIMPL_HPP
+#define SFML_WINDOWIMPL_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Config.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/String.hpp>
+#include <SFML/Window/ContextSettings.hpp>
+#include <SFML/Window/CursorImpl.hpp>
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/Joystick.hpp>
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/Window/Sensor.hpp>
+#include <SFML/Window/SensorImpl.hpp>
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/WindowHandle.hpp>
+#include <SFML/Window/Window.hpp>
+#include <queue>
+#include <set>
+
+namespace sf
+{
+class WindowListener;
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Abstract base class for OS-specific window implementation
+///
+////////////////////////////////////////////////////////////
+class WindowImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new window depending on the current OS
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ /// \return Pointer to the created window (don't forget to delete it)
+ ///
+ ////////////////////////////////////////////////////////////
+ static WindowImpl* create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new window depending on to the current OS
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ /// \return Pointer to the created window (don't forget to delete it)
+ ///
+ ////////////////////////////////////////////////////////////
+ static WindowImpl* create(WindowHandle handle);
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~WindowImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the joystick threshold, i.e. the value below which
+ /// no move event will be generated
+ ///
+ /// \param threshold New threshold, in range [0, 100]
+ ///
+ ////////////////////////////////////////////////////////////
+ void setJoystickThreshold(float threshold);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Return the next window event available
+ ///
+ /// If there's no event available, this function calls the
+ /// window's internal event processing function.
+ /// The \a block parameter controls the behavior of the function
+ /// if no event is available: if it is true then the function
+ /// doesn't return until a new event is triggered; otherwise it
+ /// returns false to indicate that no event is available.
+ ///
+ /// \param event Event to be returned
+ /// \param block Use true to block the thread until an event arrives
+ ///
+ ////////////////////////////////////////////////////////////
+ bool popEvent(Event& event, bool block);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Grab or release the mouse cursor and keeps it from leaving
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled) = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus() = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const = 0;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Push a new event into the event queue
+ ///
+ /// This function is to be used by derived classes, to
+ /// notify the SFML window that a new event was triggered
+ /// by the system.
+ ///
+ /// \param event Event to push
+ ///
+ ////////////////////////////////////////////////////////////
+ void pushEvent(const Event& event);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents() = 0;
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Read the joysticks state and generate the appropriate events
+ ///
+ ////////////////////////////////////////////////////////////
+ void processJoystickEvents();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Read the sensors state and generate the appropriate events
+ ///
+ ////////////////////////////////////////////////////////////
+ void processSensorEvents();
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ std::queue<Event> m_events; ///< Queue of available events
+ JoystickState m_joystickStates[Joystick::Count]; ///< Previous state of the joysticks
+ Vector3f m_sensorValue[Sensor::Count]; ///< Previous value of the sensors
+ float m_joystickThreshold; ///< Joystick threshold (minimum motion for "move" event to be generated)
+ float m_previousAxes[Joystick::Count][Joystick::AxisCount]; ///< Position of each axis last time a move event triggered, in range [-100, 100]
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPL_HPP
diff --git a/src/SFML/Window/iOS/ClipboardImpl.hpp b/src/SFML/Window/iOS/ClipboardImpl.hpp
new file mode 100644
index 0000000..f89d5a9
--- /dev/null
+++ b/src/SFML/Window/iOS/ClipboardImpl.hpp
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CLIPBOARDIMPLIOS_HPP
+#define SFML_CLIPBOARDIMPLIOS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/String.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+/// \brief Give access to the system clipboard
+///
+////////////////////////////////////////////////////////////
+class ClipboardImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the content of the clipboard as string data
+ ///
+ /// This function returns the content of the clipboard
+ /// as a string. If the clipboard does not contain string
+ /// it returns an empty sf::String object.
+ ///
+ /// \return Current content of the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static String getString();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the content of the clipboard as string data
+ ///
+ /// This function sets the content of the clipboard as a
+ /// string.
+ ///
+ /// \param text sf::String object containing the data to be sent
+ /// to the clipboard
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setString(const String& text);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_CLIPBOARDIMPLIOS_HPP
+
diff --git a/src/SFML/Window/iOS/ClipboardImpl.mm b/src/SFML/Window/iOS/ClipboardImpl.mm
new file mode 100644
index 0000000..641e16c
--- /dev/null
+++ b/src/SFML/Window/iOS/ClipboardImpl.mm
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/ClipboardImpl.hpp>
+
+#import <UIKit/UIKit.h>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+String ClipboardImpl::getString()
+{
+ UIPasteboard* pboard = [UIPasteboard generalPasteboard];
+ if (pboard.hasStrings)
+ {
+ NSString* data = pboard.string;
+
+ char const* utf8 = [data cStringUsingEncoding:NSUTF8StringEncoding];
+ NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ return String::fromUtf8(utf8, utf8 + length);
+ }
+ else
+ {
+ return String();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void ClipboardImpl::setString(const String& text)
+{
+ std::basic_string<Uint8> utf8 = text.toUtf8();
+ NSString* data = [[NSString alloc] initWithBytes:utf8.data()
+ length:utf8.length()
+ encoding:NSUTF8StringEncoding];
+
+ UIPasteboard* pboard = [UIPasteboard generalPasteboard];
+ pboard.string = data;
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/iOS/CursorImpl.cpp b/src/SFML/Window/iOS/CursorImpl.cpp
new file mode 100644
index 0000000..a886f32
--- /dev/null
+++ b/src/SFML/Window/iOS/CursorImpl.cpp
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/CursorImpl.hpp>
+
+namespace sf
+{
+namespace priv
+{
+
+////////////////////////////////////////////////////////////
+CursorImpl::CursorImpl()
+{
+ // Nothing.
+}
+
+
+////////////////////////////////////////////////////////////
+CursorImpl::~CursorImpl()
+{
+ // Nothing.
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
+{
+ // Not supported
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool CursorImpl::loadFromSystem(Cursor::Type type)
+{
+ // Not supported
+ return false;
+}
+
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/iOS/CursorImpl.hpp b/src/SFML/Window/iOS/CursorImpl.hpp
new file mode 100644
index 0000000..9d1dbfc
--- /dev/null
+++ b/src/SFML/Window/iOS/CursorImpl.hpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_CURSORIMPLIOS_HPP
+#define SFML_CURSORIMPLIOS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Cursor.hpp>
+#include <SFML/System/NonCopyable.hpp>
+#include <SFML/System/Vector2.hpp>
+
+
+namespace sf
+{
+
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS implementation of Cursor
+///
+/// This is a typical "not supported" implementation.
+///
+////////////////////////////////////////////////////////////
+class CursorImpl : NonCopyable
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor
+ ///
+ /// Refer to sf::Cursor::Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ /// Refer to sf::Cursor::~Cursor().
+ ///
+ ////////////////////////////////////////////////////////////
+ ~CursorImpl();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a cursor with the provided image
+ ///
+ /// Returns false.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a native system cursor
+ ///
+ /// Returns false.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool loadFromSystem(Cursor::Type type);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_CURSORIMPLIOS_HPP
diff --git a/src/SFML/Window/iOS/EaglContext.hpp b/src/SFML/Window/iOS/EaglContext.hpp
new file mode 100644
index 0000000..7121f2e
--- /dev/null
+++ b/src/SFML/Window/iOS/EaglContext.hpp
@@ -0,0 +1,167 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_EAGLCONTEXT_HPP
+#define SFML_EAGLCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+#include <SFML/Window/iOS/ObjCType.hpp>
+#include <SFML/System/Vector2.hpp>
+#include <SFML/System/Clock.hpp>
+#include <OpenGLES/ES1/gl.h>
+
+
+SFML_DECLARE_OBJC_CLASS(EAGLContext);
+SFML_DECLARE_OBJC_CLASS(SFView);
+
+namespace sf
+{
+namespace priv
+{
+class WindowImplUIKit;
+
+////////////////////////////////////////////////////////////
+/// \brief iOS (EAGL) implementation of OpenGL contexts
+///
+////////////////////////////////////////////////////////////
+class EaglContext : public GlContext
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context, not associated to a window
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ EaglContext(EaglContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ EaglContext(EaglContext* shared, const ContextSettings& settings,
+ const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ EaglContext(EaglContext* shared, const ContextSettings& settings,
+ unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~EaglContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Recreate the render buffers of the context
+ ///
+ /// This function must be called whenever the containing view
+ /// changes (typically after an orientation change)
+ ///
+ /// \param glView: Container of the context
+ ///
+ ////////////////////////////////////////////////////////////
+ void recreateRenderBuffers(SFView* glView);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \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).
+ ///
+ /// \param enabled: True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate the context as the current target
+ /// for rendering
+ ///
+ /// \param current Whether to make the context current or no longer current
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent(bool current);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ /// \param window Window to attach the context to (can be NULL)
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Creation parameters
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(EaglContext* shared,
+ const WindowImplUIKit* window,
+ unsigned int bitsPerPixel,
+ const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ EAGLContext* m_context; ///< The internal context
+ GLuint m_framebuffer; ///< Frame buffer associated to the context
+ GLuint m_colorbuffer; ///< Color render buffer
+ GLuint m_depthbuffer; ///< Depth render buffer
+ bool m_vsyncEnabled; ///< Vertical sync activation flag
+ Clock m_clock; ///< Measures the elapsed time for the fake v-sync implementation
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_EAGLCONTEXT_HPP
diff --git a/src/SFML/Window/iOS/EaglContext.mm b/src/SFML/Window/iOS/EaglContext.mm
new file mode 100644
index 0000000..9fd6b83
--- /dev/null
+++ b/src/SFML/Window/iOS/EaglContext.mm
@@ -0,0 +1,256 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/EaglContext.hpp>
+#include <SFML/Window/iOS/WindowImplUIKit.hpp>
+#include <SFML/Window/iOS/SFView.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Sleep.hpp>
+#include <OpenGLES/EAGL.h>
+#include <OpenGLES/EAGLDrawable.h>
+#include <OpenGLES/ES1/glext.h>
+#include <QuartzCore/CAEAGLLayer.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+EaglContext::EaglContext(EaglContext* shared) :
+m_context (nil),
+m_framebuffer (0),
+m_colorbuffer (0),
+m_depthbuffer (0),
+m_vsyncEnabled(false),
+m_clock ()
+{
+ // Create the context
+ if (shared)
+ m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]];
+ else
+ m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+}
+
+
+////////////////////////////////////////////////////////////
+EaglContext::EaglContext(EaglContext* shared, const ContextSettings& settings,
+ const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_context (nil),
+m_framebuffer (0),
+m_colorbuffer (0),
+m_depthbuffer (0),
+m_vsyncEnabled(false),
+m_clock ()
+{
+ const WindowImplUIKit* window = static_cast<const WindowImplUIKit*>(owner);
+
+ createContext(shared, window, bitsPerPixel, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+EaglContext::EaglContext(EaglContext* shared, const ContextSettings& settings,
+ unsigned int width, unsigned int height) :
+m_context (nil),
+m_framebuffer (0),
+m_colorbuffer (0),
+m_depthbuffer (0),
+m_vsyncEnabled(false),
+m_clock ()
+{
+ // This constructor should never be used by implementation
+ err() << "Calling bad EaglContext constructor, please contact your developer :)" << std::endl;
+}
+
+
+////////////////////////////////////////////////////////////
+EaglContext::~EaglContext()
+{
+ // Notify unshared OpenGL resources of context destruction
+ cleanupUnsharedResources();
+
+ if (m_context)
+ {
+ // Activate the context, so that we can destroy the buffers
+ EAGLContext* previousContext = [EAGLContext currentContext];
+ [EAGLContext setCurrentContext:m_context];
+
+ // Destroy the buffers
+ if (m_framebuffer)
+ glDeleteFramebuffersOES(1, &m_framebuffer);
+ if (m_colorbuffer)
+ glDeleteRenderbuffersOES(1, &m_colorbuffer);
+ if (m_depthbuffer)
+ glDeleteRenderbuffersOES(1, &m_depthbuffer);
+
+ // Restore the previous context
+ [EAGLContext setCurrentContext:previousContext];
+
+ if (m_context == [EAGLContext currentContext])
+ [EAGLContext setCurrentContext:nil];
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void EaglContext::recreateRenderBuffers(SFView* glView)
+{
+ // Activate the context
+ EAGLContext* previousContext = [EAGLContext currentContext];
+ [EAGLContext setCurrentContext:m_context];
+
+ // Bind the frame buffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer);
+
+ // Destroy previous render-buffers
+ if (m_colorbuffer)
+ glDeleteRenderbuffersOES(1, &m_colorbuffer);
+ if (m_depthbuffer)
+ glDeleteRenderbuffersOES(1, &m_depthbuffer);
+
+ // Create the color buffer
+ glGenRenderbuffersOES(1, &m_colorbuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorbuffer);
+ if (glView)
+ [m_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)glView.layer];
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, m_colorbuffer);
+
+ // Create a depth buffer if requested
+ if (m_settings.depthBits > 0)
+ {
+ // Find the best internal format
+ GLenum format = m_settings.depthBits > 16
+ ? (m_settings.stencilBits == 0 ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH24_STENCIL8_OES)
+ : GL_DEPTH_COMPONENT16_OES;
+
+ // Get the size of the color-buffer (which fits the current size of the GL view)
+ GLint width, height;
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
+
+ // Create the depth buffer
+ glGenRenderbuffersOES(1, &m_depthbuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthbuffer);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, format, width, height);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthbuffer);
+ if (m_settings.stencilBits > 0)
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthbuffer);
+ }
+
+ // Make sure that everything's ok
+ GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+ if (status != GL_FRAMEBUFFER_COMPLETE_OES)
+ err() << "Failed to create a valid frame buffer (error code: " << status << ")" << std::endl;
+
+ // Restore the previous context
+ [EAGLContext setCurrentContext:previousContext];
+}
+
+
+////////////////////////////////////////////////////////////
+bool EaglContext::makeCurrent(bool current)
+{
+ if (current)
+ return [EAGLContext setCurrentContext:m_context];
+
+ return [EAGLContext setCurrentContext:nil];
+}
+
+
+////////////////////////////////////////////////////////////
+void EaglContext::display()
+{
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorbuffer);
+ [m_context presentRenderbuffer:GL_RENDERBUFFER_OES];
+
+ // The proper way of doing v-sync on iOS would be to use CADisplayLink
+ // notifications, but it is not compatible with the way SFML is designed;
+ // therefore we fake it with a manual framerate limit
+ if (m_vsyncEnabled)
+ {
+ static const Time frameDuration = seconds(1.f / 60.f);
+ sleep(frameDuration - m_clock.getElapsedTime());
+ m_clock.restart();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void EaglContext::setVerticalSyncEnabled(bool enabled)
+{
+ m_vsyncEnabled = enabled;
+}
+
+
+////////////////////////////////////////////////////////////
+void EaglContext::createContext(EaglContext* shared,
+ const WindowImplUIKit* window,
+ unsigned int bitsPerPixel,
+ const ContextSettings& settings)
+{
+ // Save the settings
+ m_settings = settings;
+
+ // Adjust the depth buffer format to those available
+ if (m_settings.depthBits > 16)
+ m_settings.depthBits = 24;
+ else if (m_settings.depthBits > 0)
+ m_settings.depthBits = 16;
+
+ // Create the context
+ if (shared)
+ {
+ [EAGLContext setCurrentContext:nil];
+
+ m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]];
+ }
+ else
+ {
+ m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+ }
+
+ // Activate it
+ makeCurrent(true);
+
+ // Create the framebuffer (this is the only allowed drawable on iOS)
+ glGenFramebuffersOES(1, &m_framebuffer);
+
+ // Create the render buffers
+ recreateRenderBuffers(window->getGlView());
+
+ // Attach the context to the GL view for future updates
+ window->getGlView().context = this;
+
+ // Deactivate it
+ makeCurrent(false);
+}
+
+} // namespace priv
+
+} // namespace sf
+
diff --git a/src/SFML/Window/iOS/InputImpl.hpp b/src/SFML/Window/iOS/InputImpl.hpp
new file mode 100644
index 0000000..0d62071
--- /dev/null
+++ b/src/SFML/Window/iOS/InputImpl.hpp
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_INPUTIMPLIOS_HPP
+#define SFML_INPUTIMPLIOS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \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.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(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.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \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 isTouchDown(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 getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLIOS_HPP
diff --git a/src/SFML/Window/iOS/InputImpl.mm b/src/SFML/Window/iOS/InputImpl.mm
new file mode 100644
index 0000000..bada27d
--- /dev/null
+++ b/src/SFML/Window/iOS/InputImpl.mm
@@ -0,0 +1,116 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/InputImpl.hpp>
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+#include <SFML/Window/VideoMode.hpp>
+#include <SFML/Window/Window.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool visible)
+{
+ [[SFAppDelegate getInstance] setVirtualKeyboardVisible:visible];
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ return Vector2i(0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ (void)relativeTo;
+
+ return getMousePosition();
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int finger)
+{
+ return [[SFAppDelegate getInstance] getTouchPosition:finger] != Vector2i(-1, -1);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger)
+{
+ return [[SFAppDelegate getInstance] getTouchPosition:finger];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger, const Window& relativeTo)
+{
+ (void)relativeTo;
+
+ return getTouchPosition(finger);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/iOS/JoystickImpl.hpp b/src/SFML/Window/iOS/JoystickImpl.hpp
new file mode 100644
index 0000000..e9fc8bd
--- /dev/null
+++ b/src/SFML/Window/iOS/JoystickImpl.hpp
@@ -0,0 +1,114 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_JOYSTICKIMPLIOS_HPP
+#define SFML_JOYSTICKIMPLIOS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLIOS_HPP
diff --git a/src/SFML/Window/iOS/JoystickImpl.mm b/src/SFML/Window/iOS/JoystickImpl.mm
new file mode 100644
index 0000000..47fa8d3
--- /dev/null
+++ b/src/SFML/Window/iOS/JoystickImpl.mm
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // Not implemented
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // Not implemented
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ // Not implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ // Not implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ // Not implemented
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ // Not implemented
+ return JoystickCaps();
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ // Not implemented
+ return Joystick::Identification();
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::update()
+{
+ // Not implemented
+ return JoystickState();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/iOS/ObjCType.hpp b/src/SFML/Window/iOS/ObjCType.hpp
new file mode 100644
index 0000000..5d06c51
--- /dev/null
+++ b/src/SFML/Window/iOS/ObjCType.hpp
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_OBJCTYPE_HPP
+#define SFML_OBJCTYPE_HPP
+
+
+// Forward declare an Objective-C class
+#ifdef __OBJC__
+ #define SFML_DECLARE_OBJC_CLASS(c) @class c
+#else
+ #define SFML_DECLARE_OBJC_CLASS(c) typedef struct objc_object c
+#endif
+
+
+#endif // SFML_OBJCTYPE_HPP
diff --git a/src/SFML/Window/iOS/SFAppDelegate.hpp b/src/SFML/Window/iOS/SFAppDelegate.hpp
new file mode 100644
index 0000000..e389655
--- /dev/null
+++ b/src/SFML/Window/iOS/SFAppDelegate.hpp
@@ -0,0 +1,135 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SFAPPDELEGATE_HPP
+#define SFML_SFAPPDELEGATE_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/WindowImplUIKit.hpp>
+#include <UIKit/UIKit.h>
+#include <CoreMotion/CoreMotion.h>
+
+
+////////////////////////////////////////////////////////////
+/// \brief Our custom application delegate
+///
+/// This class handles global application events.
+///
+////////////////////////////////////////////////////////////
+@interface SFAppDelegate : NSObject<UIApplicationDelegate>
+
+////////////////////////////////////////////////////////////
+/// \brief Return the instance of the application delegate
+///
+////////////////////////////////////////////////////////////
++(SFAppDelegate*)getInstance;
+
+////////////////////////////////////////////////////////////
+/// \brief Show or hide the virtual keyboard
+///
+/// \param visible True to show, false to hide
+///
+////////////////////////////////////////////////////////////
+- (void)setVirtualKeyboardVisible:(bool)visible;
+
+////////////////////////////////////////////////////////////
+/// \brief Get the current touch position for a given finger
+///
+/// \param index Finger index
+///
+/// \return Current touch position, or (-1, -1) if no touch
+///
+////////////////////////////////////////////////////////////
+- (sf::Vector2i)getTouchPosition:(unsigned int)index;
+
+////////////////////////////////////////////////////////////
+/// \brief Receive an external touch begin notification
+///
+/// \param index Finger index
+/// \param position Position of the touch
+///
+////////////////////////////////////////////////////////////
+- (void)notifyTouchBegin:(unsigned int)index atPosition:(sf::Vector2i)position;
+
+////////////////////////////////////////////////////////////
+/// \brief Receive an external touch move notification
+///
+/// \param index Finger index
+/// \param position Position of the touch
+///
+////////////////////////////////////////////////////////////
+- (void)notifyTouchMove:(unsigned int)index atPosition:(sf::Vector2i)position;
+
+////////////////////////////////////////////////////////////
+/// \brief Receive an external touch end notification
+///
+/// \param index Finger index
+/// \param position Position of the touch
+///
+////////////////////////////////////////////////////////////
+- (void)notifyTouchEnd:(unsigned int)index atPosition:(sf::Vector2i)position;
+
+////////////////////////////////////////////////////////////
+/// \brief Receive an external character notification
+///
+/// \param character The typed character
+///
+////////////////////////////////////////////////////////////
+- (void)notifyCharacter:(sf::Uint32)character;
+
+////////////////////////////////////////////////////////////
+/// \brief Tells if the dimensions of the current window must be flipped when switching to a given orientation
+///
+/// \param orientation the device has changed to
+///
+////////////////////////////////////////////////////////////
+- (bool)needsToFlipFrameForOrientation:(UIDeviceOrientation)orientation;
+
+////////////////////////////////////////////////////////////
+/// \brief Tells if app and view support a requested device orientation or not
+///
+/// \param orientation the device has changed to
+///
+////////////////////////////////////////////////////////////
+- (bool)supportsOrientation:(UIDeviceOrientation)orientation;
+
+////////////////////////////////////////////////////////////
+/// \brief Initializes the factor which is required to convert from points to pixels and back
+///
+////////////////////////////////////////////////////////////
+- (void)initBackingScale;
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+@property (nonatomic) sf::priv::WindowImplUIKit* sfWindow; ///< Main window of the application
+@property (readonly, nonatomic) CMMotionManager* motionManager; ///< Instance of the motion manager
+@property (nonatomic) CGFloat backingScaleFactor;
+
+@end
+
+#endif // SFML_SFAPPDELEGATE_HPP
+
diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm
new file mode 100644
index 0000000..ea69f41
--- /dev/null
+++ b/src/SFML/Window/iOS/SFAppDelegate.mm
@@ -0,0 +1,327 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+#include <SFML/Window/iOS/SFMain.hpp>
+#include <vector>
+
+
+namespace
+{
+ // Save the global instance of the delegate
+ SFAppDelegate* delegateInstance = NULL;
+
+ // Current touches positions
+ std::vector<sf::Vector2i> touchPositions;
+}
+
+
+@interface SFAppDelegate()
+
+@property (nonatomic) CMMotionManager* motionManager;
+
+@end
+
+
+@implementation SFAppDelegate
+
+@synthesize sfWindow;
+@synthesize backingScaleFactor;
+
+
+////////////////////////////////////////////////////////////
++ (SFAppDelegate*)getInstance
+{
+ NSAssert(delegateInstance,
+ @"SFAppDelegate instance is nil, this means SFML was not properly initialized. "
+ "Make sure that the file defining your main() function includes <SFML/Main.hpp>");
+
+ return delegateInstance;
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)runUserMain
+{
+ // Arguments intentionally dropped, see comments in main in sfml-main
+ sfmlMain(0, NULL);
+}
+
+
+////////////////////////////////////////////////////////////
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ // Save the delegate instance
+ delegateInstance = self;
+
+ [self initBackingScale];
+
+ // Instantiate the motion manager
+ self.motionManager = [[CMMotionManager alloc] init];
+
+ // Register orientation changes notifications
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object: nil];
+
+ // Change the working directory to the resources directory
+ [[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]];
+
+ // Schedule an indirect call to the user main, so that this call (and the whole
+ // init sequence) can end, and the default splashscreen can be destroyed
+ [self performSelector:@selector(runUserMain) withObject:nil afterDelay:0.0];
+
+ return true;
+}
+
+- (void)initBackingScale
+{
+ id data = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSHighResolutionCapable"];
+ if(data && [data boolValue])
+ backingScaleFactor = [[UIScreen mainScreen] scale];
+ else
+ backingScaleFactor = 1;
+}
+
+////////////////////////////////////////////////////////////
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ // Called when:
+ // - the application is sent to background
+ // - the application is interrupted by a call or message
+
+ // Generate a LostFocus event
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::LostFocus;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+ // Called when the application is sent to background (home button pressed)
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ // Called when:
+ // - the application is sent to foreground
+ // - the application was interrupted by a call or message
+
+ // Generate a GainedFocus event
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::GainedFocus;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+ // Called when the application is sent to foreground (app icon pressed)
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ // Generate a Closed event
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::Closed;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+- (bool)supportsOrientation:(UIDeviceOrientation)orientation
+{
+ if (!self.sfWindow)
+ return false;
+
+ UIViewController* rootViewController = [((__bridge UIWindow*)(self.sfWindow->getSystemHandle())) rootViewController];
+ if (!rootViewController || ![rootViewController shouldAutorotate])
+ return false;
+
+ NSArray *supportedOrientations = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UISupportedInterfaceOrientations"];
+ if (!supportedOrientations)
+ return (1 << orientation) & [rootViewController supportedInterfaceOrientations];
+
+ int appFlags = 0;
+ if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortrait"])
+ appFlags += UIInterfaceOrientationMaskPortrait;
+ if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortraitUpsideDown"])
+ appFlags += UIInterfaceOrientationMaskPortraitUpsideDown;
+ if ([supportedOrientations containsObject:@"UIInterfaceOrientationLandscapeLeft"])
+ appFlags += UIInterfaceOrientationMaskLandscapeLeft;
+ if ([supportedOrientations containsObject:@"UIInterfaceOrientationLandscapeRight"])
+ appFlags += UIInterfaceOrientationMaskLandscapeRight;
+
+ return (1 << orientation) & [rootViewController supportedInterfaceOrientations] & appFlags;
+}
+
+- (bool)needsToFlipFrameForOrientation:(UIDeviceOrientation)orientation
+{
+ sf::Vector2u size = self.sfWindow->getSize();
+ return ((!UIDeviceOrientationIsLandscape(orientation) && size.x > size.y)
+ || (UIDeviceOrientationIsLandscape(orientation) && size.y > size.x));
+}
+
+////////////////////////////////////////////////////////////
+- (void)deviceOrientationDidChange:(NSNotification *)notification
+{
+ if (self.sfWindow)
+ {
+ // Get the new orientation
+ UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
+ // Filter interesting orientations
+ if (UIDeviceOrientationIsValidInterfaceOrientation(orientation))
+ {
+ // Get the new size
+ sf::Vector2u size = self.sfWindow->getSize();
+ // Check if the app can switch to this orientation and if so if the window's size must be adjusted
+ if ([self supportsOrientation:orientation] && [self needsToFlipFrameForOrientation:orientation])
+ std::swap(size.x, size.y);
+
+ // Send a Resized event to the current window
+ sf::Event event;
+ event.type = sf::Event::Resized;
+ event.size.width = size.x;
+ event.size.height = size.y;
+ sfWindow->forwardEvent(event);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////
+- (void)setVirtualKeyboardVisible:(bool)visible
+{
+ if (self.sfWindow)
+ self.sfWindow->setVirtualKeyboardVisible(visible);
+}
+
+
+////////////////////////////////////////////////////////////
+- (sf::Vector2i)getTouchPosition:(unsigned int)index
+{
+ if (index < touchPositions.size())
+ return touchPositions[index];
+ else
+ return sf::Vector2i(-1, -1);
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)notifyTouchBegin:(unsigned int)index atPosition:(sf::Vector2i)position;
+{
+ position.x *= backingScaleFactor;
+ position.y *= backingScaleFactor;
+
+ // save the touch position
+ if (index >= touchPositions.size())
+ touchPositions.resize(index + 1, sf::Vector2i(-1, -1));
+ touchPositions[index] = position;
+
+ // notify the event to the application window
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::TouchBegan;
+ event.touch.finger = index;
+ event.touch.x = position.x;
+ event.touch.y = position.y;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)notifyTouchMove:(unsigned int)index atPosition:(sf::Vector2i)position;
+{
+ position.x *= backingScaleFactor;
+ position.y *= backingScaleFactor;
+
+ // save the touch position
+ if (index >= touchPositions.size())
+ touchPositions.resize(index + 1, sf::Vector2i(-1, -1));
+ touchPositions[index] = position;
+
+ // notify the event to the application window
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::TouchMoved;
+ event.touch.finger = index;
+ event.touch.x = position.x;
+ event.touch.y = position.y;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)notifyTouchEnd:(unsigned int)index atPosition:(sf::Vector2i)position;
+{
+ // clear the touch position
+ if (index < touchPositions.size())
+ touchPositions[index] = sf::Vector2i(-1, -1);
+
+ // notify the event to the application window
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::TouchEnded;
+ event.touch.finger = index;
+ event.touch.x = position.x * backingScaleFactor;
+ event.touch.y = position.y * backingScaleFactor;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)notifyCharacter:(sf::Uint32)character
+{
+ if (self.sfWindow)
+ {
+ sf::Event event;
+ event.type = sf::Event::TextEntered;
+ event.text.unicode = character;
+ sfWindow->forwardEvent(event);
+ }
+}
+
+
+@end
diff --git a/src/SFML/Window/iOS/SFMain.hpp b/src/SFML/Window/iOS/SFMain.hpp
new file mode 100644
index 0000000..4d0b5b4
--- /dev/null
+++ b/src/SFML/Window/iOS/SFMain.hpp
@@ -0,0 +1,35 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SFMAIN_HPP
+#define SFML_SFMAIN_HPP
+
+
+int sfmlMain(int argc, char** argv);
+
+int sfmlMain();
+
+
+#endif // SFML_SFMAIN_HPP
+
diff --git a/src/SFML/Window/iOS/SFMain.mm b/src/SFML/Window/iOS/SFMain.mm
new file mode 100644
index 0000000..4e9910a
--- /dev/null
+++ b/src/SFML/Window/iOS/SFMain.mm
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/SFMain.hpp>
+
+
+// sfmlMain is called by the application delegate (SFAppDelegate).
+//
+// Since we don't know which prototype of main the user
+// defines, we declare both versions of sfmlMain, but with
+// the 'weak' attribute (GCC extension) so that the
+// user-declared one will replace SFML's one at linking stage.
+//
+// If user defines main(argc, argv) then it will be called
+// directly, if he defines main() then it will be called by
+// our placeholder.
+//
+// The sfmlMain() version is never called, it is just defined
+// to avoid a linker error if the user directly defines the
+// version with arguments.
+//
+// See the sfml-main module for the other half of this
+// initialization trick.
+
+
+////////////////////////////////////////////////////////////
+__attribute__((weak)) int sfmlMain(int, char**)
+{
+ return sfmlMain();
+}
+
+
+////////////////////////////////////////////////////////////
+__attribute__((weak)) int sfmlMain()
+{
+ return 0;
+}
diff --git a/src/SFML/Window/iOS/SFView.hpp b/src/SFML/Window/iOS/SFView.hpp
new file mode 100644
index 0000000..f3f4276
--- /dev/null
+++ b/src/SFML/Window/iOS/SFView.hpp
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SFVIEW_HPP
+#define SFML_SFVIEW_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/EaglContext.hpp>
+#include <UIKit/UIKit.h>
+
+
+////////////////////////////////////////////////////////////
+/// \brief Our custom implementation of the window's view
+/// (supports OpenGL and reports events)
+///
+////////////////////////////////////////////////////////////
+@interface SFView : UIView<UIKeyInput>
+
+////////////////////////////////////////////////////////////
+/// \brief Construct the view with its initial size
+///
+/// \param frame Dimensions of the view
+///
+/// \return Id of the view
+///
+////////////////////////////////////////////////////////////
+- (id)initWithFrame:(CGRect)frame andContentScaleFactor:(CGFloat)factor;
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+@property (nonatomic) sf::priv::EaglContext* context; ///< The attached EAGL context
+
+@end
+
+#endif // SFML_SFVIEW_HPP
diff --git a/src/SFML/Window/iOS/SFView.mm b/src/SFML/Window/iOS/SFView.mm
new file mode 100644
index 0000000..940d0a8
--- /dev/null
+++ b/src/SFML/Window/iOS/SFView.mm
@@ -0,0 +1,212 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/SFView.hpp>
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+#include <SFML/System/Utf.hpp>
+#include <QuartzCore/CAEAGLLayer.h>
+#include <cstring>
+
+@interface SFView()
+
+@property (nonatomic) NSMutableArray* touches;
+
+@end
+
+
+@implementation SFView
+
+@synthesize context;
+
+
+////////////////////////////////////////////////////////////
+-(BOOL)canBecomeFirstResponder
+{
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+- (BOOL)hasText
+{
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)deleteBackward
+{
+ [[SFAppDelegate getInstance] notifyCharacter:'\b'];
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)insertText:(NSString*)text
+{
+ // Convert the NSString to UTF-8
+ const char* utf8 = [text UTF8String];
+
+ // Then convert to UTF-32 and notify the application delegate of each new character
+ const char* end = utf8 + std::strlen(utf8);
+ while (utf8 < end)
+ {
+ sf::Uint32 character;
+ utf8 = sf::Utf8::decode(utf8, end, character);
+ [[SFAppDelegate getInstance] notifyCharacter:character];
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ for (UITouch* touch in touches)
+ {
+ // find an empty slot for the new touch
+ NSUInteger index = [self.touches indexOfObject:[NSNull null]];
+ if (index != NSNotFound)
+ {
+ [self.touches replaceObjectAtIndex:index withObject:touch];
+ }
+ else
+ {
+ [self.touches addObject:touch];
+ index = [self.touches count] - 1;
+ }
+
+ // get the touch position
+ CGPoint point = [touch locationInView:self];
+ sf::Vector2i position(static_cast<int>(point.x), static_cast<int>(point.y));
+
+ // notify the application delegate
+ [[SFAppDelegate getInstance] notifyTouchBegin:index atPosition:position];
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ for (UITouch* touch in touches)
+ {
+ // find the touch
+ NSUInteger index = [self.touches indexOfObject:touch];
+ if (index != NSNotFound)
+ {
+ // get the touch position
+ CGPoint point = [touch locationInView:self];
+ sf::Vector2i position(static_cast<int>(point.x), static_cast<int>(point.y));
+
+ // notify the application delegate
+ [[SFAppDelegate getInstance] notifyTouchMove:index atPosition:position];
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ for (UITouch* touch in touches)
+ {
+ // find the touch
+ NSUInteger index = [self.touches indexOfObject:touch];
+ if (index != NSNotFound)
+ {
+ // get the touch position
+ CGPoint point = [touch locationInView:self];
+ sf::Vector2i position(static_cast<int>(point.x), static_cast<int>(point.y));
+
+ // notify the application delegate
+ [[SFAppDelegate getInstance] notifyTouchEnd:index atPosition:position];
+
+ // remove the touch
+ [self.touches replaceObjectAtIndex:index withObject:[NSNull null]];
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
+{
+ // Treat touch cancel events the same way as touch end
+ [self touchesEnded:touches withEvent:event];
+}
+
+
+////////////////////////////////////////////////////////////
+- (void)layoutSubviews
+{
+ // update the attached context's buffers
+ if (self.context)
+ self.context->recreateRenderBuffers(self);
+}
+
+
+////////////////////////////////////////////////////////////
++ (Class)layerClass
+{
+ return [CAEAGLLayer class];
+}
+
+////////////////////////////////////////////////////////////
+- (id)initWithFrame:(CGRect)frame andContentScaleFactor:(CGFloat)factor
+{
+ self = [super initWithFrame:frame];
+
+ self.contentScaleFactor = factor;
+
+ if (self)
+ {
+ self.context = NULL;
+ self.touches = [NSMutableArray array];
+
+ // Configure the EAGL layer
+ CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer;
+ eaglLayer.opaque = YES;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,
+ kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
+ nil];
+
+ // Enable user interactions on the view (multi-touch events)
+ self.userInteractionEnabled = true;
+ self.multipleTouchEnabled = true;
+ }
+
+ return self;
+}
+
+////////////////////////////////////////////////////////////
+- (UITextAutocorrectionType) autocorrectionType
+{
+ return UITextAutocorrectionTypeNo;
+}
+
+
+@end
diff --git a/src/SFML/Window/iOS/SFViewController.hpp b/src/SFML/Window/iOS/SFViewController.hpp
new file mode 100644
index 0000000..2b65d35
--- /dev/null
+++ b/src/SFML/Window/iOS/SFViewController.hpp
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SFVIEWCONTROLLER_HPP
+#define SFML_SFVIEWCONTROLLER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <UIKit/UIKit.h>
+
+
+////////////////////////////////////////////////////////////
+/// \brief The view controller handles the view's orientation
+///
+////////////////////////////////////////////////////////////
+@interface SFViewController : UIViewController
+
+////////////////////////////////////////////////////////////
+/// \brief Tells if the controller supports auto-rotation (iOS < 6)
+///
+/// \param interfaceOrientation Orientation to check
+///
+/// \return True if auto-rotation is supported, false otherwise
+///
+////////////////////////////////////////////////////////////
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
+
+////////////////////////////////////////////////////////////
+/// \brief Tells if the controller supports auto-rotation (iOS >= 6)
+///
+/// \return True if auto-rotation is supported, false otherwise
+///
+////////////////////////////////////////////////////////////
+- (BOOL)shouldAutorotate;
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+@property (nonatomic) bool orientationCanChange; ///< Tells whether the controller's view can rotate or not
+
+@end
+
+#endif // SFML_SFVIEWCONTROLLER_HPP
diff --git a/src/SFML/Window/iOS/SFViewController.mm b/src/SFML/Window/iOS/SFViewController.mm
new file mode 100644
index 0000000..8c23cdc
--- /dev/null
+++ b/src/SFML/Window/iOS/SFViewController.mm
@@ -0,0 +1,49 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/SFViewController.hpp>
+
+
+@implementation SFViewController
+
+@synthesize orientationCanChange;
+
+
+////////////////////////////////////////////////////////////
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return self.orientationCanChange;
+}
+
+
+////////////////////////////////////////////////////////////
+- (BOOL)shouldAutorotate
+{
+ return self.orientationCanChange;
+}
+
+@end
diff --git a/src/SFML/Window/iOS/SensorImpl.hpp b/src/SFML/Window/iOS/SensorImpl.hpp
new file mode 100644
index 0000000..05c6b93
--- /dev/null
+++ b/src/SFML/Window/iOS/SensorImpl.hpp
@@ -0,0 +1,114 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_SENSORIMPLIOS_HPP
+#define SFML_SENSORIMPLIOS_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Sensor.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Sensor::Type m_sensor; ///< Type of the sensor
+ bool m_enabled; ///< Enable state of the sensor
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLIOS_HPP
diff --git a/src/SFML/Window/iOS/SensorImpl.mm b/src/SFML/Window/iOS/SensorImpl.mm
new file mode 100644
index 0000000..249c41a
--- /dev/null
+++ b/src/SFML/Window/iOS/SensorImpl.mm
@@ -0,0 +1,242 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+
+
+namespace
+{
+ unsigned int deviceMotionEnabledCount = 0;
+
+ float toDegrees(float radians)
+ {
+ return radians * 180.f / 3.141592654f;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type sensor)
+{
+ switch (sensor)
+ {
+ case Sensor::Accelerometer:
+ return [SFAppDelegate getInstance].motionManager.accelerometerAvailable;
+
+ case Sensor::Gyroscope:
+ return [SFAppDelegate getInstance].motionManager.gyroAvailable;
+
+ case Sensor::Magnetometer:
+ return [SFAppDelegate getInstance].motionManager.magnetometerAvailable;
+
+ case Sensor::Gravity:
+ case Sensor::UserAcceleration:
+ case Sensor::Orientation:
+ return [SFAppDelegate getInstance].motionManager.deviceMotionAvailable;
+
+ default:
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type sensor)
+{
+ // Store the sensor type
+ m_sensor = sensor;
+
+ // The sensor is disabled by default
+ m_enabled = false;
+
+ // Set the refresh rate (use the maximum allowed)
+ static const NSTimeInterval updateInterval = 1. / 60.;
+ switch (sensor)
+ {
+ case Sensor::Accelerometer:
+ [SFAppDelegate getInstance].motionManager.accelerometerUpdateInterval = updateInterval;
+ break;
+
+ case Sensor::Gyroscope:
+ [SFAppDelegate getInstance].motionManager.gyroUpdateInterval = updateInterval;
+ break;
+
+ case Sensor::Magnetometer:
+ [SFAppDelegate getInstance].motionManager.magnetometerUpdateInterval = updateInterval;
+ break;
+
+ case Sensor::Gravity:
+ case Sensor::UserAcceleration:
+ case Sensor::Orientation:
+ [SFAppDelegate getInstance].motionManager.deviceMotionUpdateInterval = updateInterval;
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ Vector3f value;
+ CMMotionManager* manager = [SFAppDelegate getInstance].motionManager;
+
+ switch (m_sensor)
+ {
+ case Sensor::Accelerometer:
+ // Acceleration is given in G, convert to m/s^2
+ value.x = manager.accelerometerData.acceleration.x * 9.81f;
+ value.y = manager.accelerometerData.acceleration.y * 9.81f;
+ value.z = manager.accelerometerData.acceleration.z * 9.81f;
+ break;
+
+ case Sensor::Gyroscope:
+ // Rotation rates are given in rad/s, convert to deg/s
+ value.x = toDegrees(manager.gyroData.rotationRate.x);
+ value.y = toDegrees(manager.gyroData.rotationRate.y);
+ value.z = toDegrees(manager.gyroData.rotationRate.z);
+ break;
+
+ case Sensor::Magnetometer:
+ // Magnetic field is given in microteslas
+ value.x = manager.magnetometerData.magneticField.x;
+ value.y = manager.magnetometerData.magneticField.y;
+ value.z = manager.magnetometerData.magneticField.z;
+ break;
+
+ case Sensor::UserAcceleration:
+ // User acceleration is given in G, convert to m/s^2
+ value.x = manager.deviceMotion.userAcceleration.x * 9.81f;
+ value.y = manager.deviceMotion.userAcceleration.y * 9.81f;
+ value.z = manager.deviceMotion.userAcceleration.z * 9.81f;
+ break;
+
+ case Sensor::Orientation:
+ // Absolute rotation (Euler) angles are given in radians, convert to degrees
+ value.x = toDegrees(manager.deviceMotion.attitude.yaw);
+ value.y = toDegrees(manager.deviceMotion.attitude.pitch);
+ value.z = toDegrees(manager.deviceMotion.attitude.roll);
+ break;
+
+ default:
+ break;
+ }
+
+ return value;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool enabled)
+{
+ // Don't do anything if the state is the same
+ if (enabled == m_enabled)
+ return;
+
+ switch (m_sensor)
+ {
+ case Sensor::Accelerometer:
+ if (enabled)
+ [[SFAppDelegate getInstance].motionManager startAccelerometerUpdates];
+ else
+ [[SFAppDelegate getInstance].motionManager stopAccelerometerUpdates];
+ break;
+
+ case Sensor::Gyroscope:
+ if (enabled)
+ [[SFAppDelegate getInstance].motionManager startGyroUpdates];
+ else
+ [[SFAppDelegate getInstance].motionManager stopGyroUpdates];
+ break;
+
+ case Sensor::Magnetometer:
+ if (enabled)
+ [[SFAppDelegate getInstance].motionManager startMagnetometerUpdates];
+ else
+ [[SFAppDelegate getInstance].motionManager stopMagnetometerUpdates];
+ break;
+
+ case Sensor::Gravity:
+ case Sensor::UserAcceleration:
+ case Sensor::Orientation:
+ // these 3 sensors all share the same implementation, so we must disable
+ // it only if the three sensors are disabled
+ if (enabled)
+ {
+ if (deviceMotionEnabledCount == 0)
+ [[SFAppDelegate getInstance].motionManager startDeviceMotionUpdates];
+ deviceMotionEnabledCount++;
+ }
+ else
+ {
+ deviceMotionEnabledCount--;
+ if (deviceMotionEnabledCount == 0)
+ [[SFAppDelegate getInstance].motionManager stopDeviceMotionUpdates];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Update the enable state
+ m_enabled = enabled;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/iOS/VideoModeImpl.mm b/src/SFML/Window/iOS/VideoModeImpl.mm
new file mode 100644
index 0000000..7296d9d
--- /dev/null
+++ b/src/SFML/Window/iOS/VideoModeImpl.mm
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+#include <UIKit/UIKit.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ VideoMode desktop = getDesktopMode();
+
+ // Return both portrait and landscape resolutions
+ std::vector<VideoMode> modes;
+ modes.push_back(desktop);
+ modes.push_back(VideoMode(desktop.height, desktop.width, desktop.bitsPerPixel));
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ CGRect bounds = [[UIScreen mainScreen] bounds];
+ float backingScale = [SFAppDelegate getInstance].backingScaleFactor;
+ return VideoMode(bounds.size.width * backingScale, bounds.size.height * backingScale);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/iOS/WindowImplUIKit.hpp b/src/SFML/Window/iOS/WindowImplUIKit.hpp
new file mode 100644
index 0000000..60e0407
--- /dev/null
+++ b/src/SFML/Window/iOS/WindowImplUIKit.hpp
@@ -0,0 +1,242 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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_WINDOWIMPLUIKIT_HPP
+#define SFML_WINDOWIMPLUIKIT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/Window/iOS/ObjCType.hpp>
+
+
+SFML_DECLARE_OBJC_CLASS(UIWindow);
+SFML_DECLARE_OBJC_CLASS(SFView);
+SFML_DECLARE_OBJC_CLASS(SFViewController);
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief iOS (UIKit) implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplUIKit : public WindowImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplUIKit(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style (resizable, fixed, or fullscren)
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplUIKit(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplUIKit();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clips or releases the mouse cursor
+ ///
+ /// \param grabbed True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorGrabbed(bool grabbed);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the displayed cursor to a native system cursor
+ ///
+ /// \param cursor Native system cursor type to display
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursor(const CursorImpl& cursor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Notify an event
+ ///
+ /// \param event Event to forward
+ ///
+ ////////////////////////////////////////////////////////////
+ void forwardEvent(Event event);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the window's view
+ ///
+ /// \return Pointer to the window's view
+ ///
+ ////////////////////////////////////////////////////////////
+ SFView* getGlView() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ void setVirtualKeyboardVisible(bool visible);
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ UIWindow* m_window; ///< Pointer to the internal UIKit window
+ SFView* m_view; ///< OpenGL view of the window
+ SFViewController* m_viewController; ///< Controller attached to the view
+ bool m_hasFocus; ///< Current focus state of the window
+ float m_backingScale; ///< Converts from points to pixels and vice versa
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPLUIKIT_HPP
diff --git a/src/SFML/Window/iOS/WindowImplUIKit.mm b/src/SFML/Window/iOS/WindowImplUIKit.mm
new file mode 100644
index 0000000..35337db
--- /dev/null
+++ b/src/SFML/Window/iOS/WindowImplUIKit.mm
@@ -0,0 +1,251 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2018 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
+////////////////////////////////////////////////////////////
+#include <SFML/Window/iOS/WindowImplUIKit.hpp>
+#include <SFML/Window/iOS/SFView.hpp>
+#include <SFML/Window/iOS/SFViewController.hpp>
+#include <SFML/Window/iOS/SFAppDelegate.hpp>
+#include <SFML/Window/WindowStyle.hpp>
+#include <SFML/System/Err.hpp>
+#include <UIKit/UIKit.h>
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+WindowImplUIKit::WindowImplUIKit(WindowHandle handle)
+{
+ // Not implemented
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplUIKit::WindowImplUIKit(VideoMode mode,
+ const String& title,
+ unsigned long style,
+ const ContextSettings& /*settings*/)
+{
+ m_backingScale = [SFAppDelegate getInstance].backingScaleFactor;
+
+ // Apply the fullscreen flag
+ [UIApplication sharedApplication].statusBarHidden = !(style & Style::Titlebar) || (style & Style::Fullscreen);
+
+ // Set the orientation according to the requested size
+ if (mode.width > mode.height)
+ [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];
+ else
+ [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
+
+ // Create the window
+ CGRect frame = [UIScreen mainScreen].bounds; // Ignore user size, it wouldn't make sense to use something else
+ m_window = [[UIWindow alloc] initWithFrame:frame];
+ m_hasFocus = true;
+
+ // Assign it to the application delegate
+ [SFAppDelegate getInstance].sfWindow = this;
+
+ CGRect viewRect = frame;
+ // if UI-orientation doesn't match window-layout, swap the view size and notify the window about it
+ // iOS 7 and 8 do different stuff here. In iOS 7 frame.x<frame.y always! In iOS 8 it correctly depends on orientation
+ if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
+ if ((mode.width > mode.height) != (frame.size.width > frame.size.height))
+ std::swap(viewRect.size.width, viewRect.size.height);
+
+ // Create the view
+ m_view = [[SFView alloc] initWithFrame:viewRect andContentScaleFactor:m_backingScale];
+ [m_view resignFirstResponder];
+
+ // Create the view controller
+ m_viewController = [SFViewController alloc];
+ m_viewController.view = m_view;
+ m_viewController.orientationCanChange = style & Style::Resize;
+ m_window.rootViewController = m_viewController;
+
+ // Make it the current window
+ [m_window makeKeyAndVisible];
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplUIKit::~WindowImplUIKit()
+{
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::processEvents()
+{
+ while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0001, true) == kCFRunLoopRunHandledSource)
+ ;
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplUIKit::getSystemHandle() const
+{
+ return (__bridge WindowHandle)m_window;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplUIKit::getPosition() const
+{
+ CGPoint origin = m_window.frame.origin;
+ return Vector2i(origin.x * m_backingScale, origin.y * m_backingScale);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setPosition(const Vector2i& position)
+{
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplUIKit::getSize() const
+{
+ auto physicalFrame = m_window.frame;
+ // iOS 7 and 8 do different stuff here. In iOS 7 frame.x<frame.y always! In iOS 8 it correctly depends on orientation
+ if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
+ && UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
+ std::swap(physicalFrame.size.width, physicalFrame.size.height);
+ return Vector2u(physicalFrame.size.width * m_backingScale, physicalFrame.size.height * m_backingScale);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setSize(const Vector2u& size)
+{
+ // @todo ...
+
+ // if these sizes are required one day, don't forget to scale them!
+ // size.x /= m_backingScale;
+ // size.y /= m_backingScale;
+
+ // Set the orientation according to the requested size
+ if (size.x > size.y)
+ [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];
+ else
+ [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setTitle(const String& title)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setMouseCursorVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setMouseCursorGrabbed(bool grabbed)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setMouseCursor(const CursorImpl& cursor)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setKeyRepeatEnabled(bool enabled)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::requestFocus()
+{
+ // To implement
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplUIKit::hasFocus() const
+{
+ return m_hasFocus;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::forwardEvent(Event event)
+{
+ if (event.type == Event::GainedFocus)
+ m_hasFocus = true;
+ else if (event.type == Event::LostFocus)
+ m_hasFocus = false;
+
+ pushEvent(event);
+}
+
+
+////////////////////////////////////////////////////////////
+SFView* WindowImplUIKit::getGlView() const
+{
+ return m_view;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplUIKit::setVirtualKeyboardVisible(bool visible)
+{
+ if (visible)
+ [m_view becomeFirstResponder];
+ else
+ [m_view resignFirstResponder];
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/tools/android/clean_all.sh b/tools/android/clean_all.sh
new file mode 100755
index 0000000..c144387
--- /dev/null
+++ b/tools/android/clean_all.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+rm -rf tmp
+rm -rf build
+rm -rf src
+rm -rf toolchains
diff --git a/tools/android/compile_arm-v7a.sh b/tools/android/compile_arm-v7a.sh
new file mode 100755
index 0000000..b7b883f
--- /dev/null
+++ b/tools/android/compile_arm-v7a.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+DESTDIR=$PWD/tmp/arm-v7a
+
+PATH=$PWD/toolchains/arm/bin:$PATH
+CC=arm-linux-androideabi-gcc
+CXX=arm-linux-androideabi-g++
+CFLAGS="-I$DESTDIR/usr/include -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
+CPPFLAGS="-I$DESTDIR/usr/include -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
+LDFLAGS="-L$DESTDIR/usr/lib -march=armv7-a -Wl,--fix-cortex-a8"
+
+./compile_libs.sh arm-v7a $PATH $CC $CXX "$CFLAGS" "$CPPFLAGS" "$LDFLAGS"
diff --git a/tools/android/compile_arm.sh b/tools/android/compile_arm.sh
new file mode 100755
index 0000000..ee30109
--- /dev/null
+++ b/tools/android/compile_arm.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+DESTDIR=$PWD/tmp/arm
+
+PATH=$PWD/toolchains/arm/bin:$PATH
+CC=arm-linux-androideabi-gcc
+CXX=arm-linux-androideabi-g++
+CFLAGS=-I$DESTDIR/usr/include
+CPPFLAGS=-I$DESTDIR/usr/include
+LDFLAGS=-L$DESTDIR/usr/lib
+
+./compile_libs.sh arm $PATH $CC $CXX $CFLAGS $CPPFLAGS $LDFLAGS
diff --git a/tools/android/compile_libs.sh b/tools/android/compile_libs.sh
new file mode 100755
index 0000000..deadac5
--- /dev/null
+++ b/tools/android/compile_libs.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+DESTDIR=$PWD/tmp
+LOCALDIR=$PWD
+
+OPATH=$PATH
+
+export PATH=$2
+export CC=$3
+export CXX=$4
+export CFLAGS=$5
+export CPPFLAGS=$6
+export LDFLAGS=$7
+
+if [ "$1" = "arm" ]
+then
+ ARCH=arm-linux
+ ANDROID_ABI=armeabi
+
+elif [ "$1" = "arm-v7a" ]
+then
+ ARCH=arm-linux
+ ANDROID_ABI=armeabi-v7a
+
+elif [ "$1" = "x86" ]
+then
+ ARCH=i686-linux
+ ANDROID_ABI=x86
+
+elif [ "$1" = "mips" ]
+then
+ ARCH=mips-linux
+ ANDROID_ABI=mips
+fi
+
+HOST="--host=$ARCH"
+PREFIX="--prefix=$DESTDIR/$1/usr need_version=no"
+
+# Compile OGG
+cd $LOCALDIR/build/libogg-* && sed -i 's/-version-info/-avoid-version/g' src/Makefile.in src/Makefile.am && ./configure $HOST $PREFIX --enable-shared=no && make && make install
+rm $DESTDIR/$1/usr/lib/libogg*.so*
+
+# Compile FLAC
+cd $LOCALDIR/build/flac-* && sed -i 's/-version-info/-avoid-version/g' src/libFLAC/Makefile.in src/libFLAC/Makefile.am && ./configure $HOST $PREFIX --enable-shared=no && make && make install
+rm $DESTDIR/$1/usr/lib/libFLAC*.so*
+
+# Compile VORBIS
+cd $LOCALDIR/build/libvorbis-* && sed -i 's/-version-info/-avoid-version/g' lib/Makefile.in lib/Makefile.am && ./configure $HOST $PREFIX --enable-shared=no && make && make install
+rm $DESTDIR/$1/usr/lib/libvorbis*.so*
+
+# Compile freetype
+cd $LOCALDIR/build/freetype-* && sed -i 's/-version-info/-avoid-version/g' builds/unix/unix-cc.in && ./configure $HOST $PREFIX && make && make install
+
+# Compile OpenAL-Soft
+cd $LOCALDIR/build/openal-soft-android-master && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_CMAKE_TOOLCHAIN -DANDROID_ABI=$ANDROID_ABI -DANDROID_NATIVE_API_LEVEL=android-9 -DANDROID_USE_STLPORT=1 .. && make openal && mv libopenal.so $DESTDIR/$1/usr/lib
+
+export PATH=$OPATH
diff --git a/tools/android/compile_mips.sh b/tools/android/compile_mips.sh
new file mode 100755
index 0000000..96985b9
--- /dev/null
+++ b/tools/android/compile_mips.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+DESTDIR=$PWD/tmp/mips
+
+PATH=$PWD/toolchains/mips/bin:$PATH
+CC=mipsel-linux-android-gcc
+CXX=mipsel-linux-android-g++
+CFLAGS=-I$DESTDIR/usr/include
+CPPFLAGS=-I$DESTDIR/usr/include
+LDFLAGS=-L$DESTDIR/usr/lib
+
+./compile_libs.sh mips $PATH $CC $CXX $CFLAGS $CPPFLAGS $LDFLAGS
diff --git a/tools/android/compile_x86.sh b/tools/android/compile_x86.sh
new file mode 100755
index 0000000..20f9fbb
--- /dev/null
+++ b/tools/android/compile_x86.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+DESTDIR=$PWD/tmp/x86
+
+PATH=$PWD/toolchains/x86/bin:$PATH
+CC=i686-linux-android-gcc
+CXX=i686-linux-android-g++
+CFLAGS=-I$DESTDIR/usr/include
+CPPFLAGS=-I$DESTDIR/usr/include
+LDFLAGS=-L$DESTDIR/usr/lib
+
+./compile_libs.sh x86 $PATH $CC $CXX $CFLAGS $CPPFLAGS $LDFLAGS
diff --git a/tools/android/create_toolchains.sh b/tools/android/create_toolchains.sh
new file mode 100755
index 0000000..635d788
--- /dev/null
+++ b/tools/android/create_toolchains.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+create_toolchain () {
+
+ # abort if already created
+ if [ -d "$PWD/toolchains/$2" ]
+ then
+ return
+ fi
+
+ # save the working directory and move to the NDK directory
+ WORKING_DIRECTORY=$PWD
+ cd $NDK
+
+ # prepare the command according to chosen options
+ PLATFORM=--platform=android-$1
+ DIR=--install-dir=$WORKING_DIRECTORY/toolchains/$2
+ MAKE=$NDK/build/tools/make-standalone-toolchain.sh
+
+ if [ "$2" = "arm" ]
+ then
+ TOOLCHAIN=--toolchain=arm-linux-androideabi-4.8
+ elif [ "$2" = "x86" ]
+ then
+ TOOLCHAIN=--toolchain=x86-4.8
+ elif [ "$2" = "mips" ]
+ then
+ TOOLCHAIN=--toolchain=mipsel-linux-android-4.8
+ else
+ echo "Abort."
+ exit 1
+ fi
+
+ # create the standalone toolchain
+ $MAKE $PLATFORM $TOOLCHAIN $DIR --stl=libc++
+
+ # go back to our working directory
+ cd $WORKING_DIRECTORY
+
+ # move linux/soundcard.h to sys/soundcard.h
+ mv $PWD/toolchains/$2/sysroot/usr/include/linux/soundcard.h $PWD/toolchains/$2/sysroot/usr/include/sys
+}
+
+create_toolchain 9 arm
+create_toolchain 9 x86
+create_toolchain 9 mips
diff --git a/tools/android/download_sources.sh b/tools/android/download_sources.sh
new file mode 100755
index 0000000..27c75eb
--- /dev/null
+++ b/tools/android/download_sources.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+FLAC_VERSION=1.2.1
+VORBIS_VERSION=1.3.3
+OGG_VERSION=1.3.1
+
+FLAC=flac-$FLAC_VERSION
+VORBIS=libvorbis-$VORBIS_VERSION
+OGG=libogg-$OGG_VERSION
+
+SNDFILE_VERSION=1.0.25
+SNDFILE=libsndfile-$SNDFILE_VERSION
+
+FREETYPE_VERSION=2.4.0
+FREETYPE=freetype-$FREETYPE_VERSION
+
+mkdir build
+
+wget -nc -P src http://downloads.xiph.org/releases/flac/$FLAC.tar.gz
+if [ ! -d "$PWD/tmp/$FLAC" ]
+then
+ tar -C build -xf src/$FLAC.tar.gz
+fi
+
+wget -nc -P src http://downloads.xiph.org/releases/vorbis/$VORBIS.tar.gz
+if [ ! -d "$PWD/tmp/$VORBIS" ]
+then
+ tar -C build -xf src/$VORBIS.tar.gz
+fi
+
+wget -nc -P src http://downloads.xiph.org/releases/ogg/$OGG.tar.gz
+if [ ! -d "$PWD/tmp/$OGG" ]
+then
+ tar -C build -xf src/$OGG.tar.gz
+fi
+
+wget -nc -P src http://download.savannah.gnu.org/releases/freetype/$FREETYPE.tar.gz
+if [ ! -d "$PWD/tmp/$FREETYPE" ]
+then
+ tar -C build -xf src/$FREETYPE.tar.gz
+fi
+
+wget -nc -P src https://github.com/AerialX/openal-soft-android/archive/master.tar.gz
+if [ ! -d "$PWD/tmp/openal-soft-android-master" ]
+then
+ tar -C build -xf src/master.tar.gz
+fi
+
+patch build/openal-soft-android-master/CMakeLists.txt patches/remove-so-version-suffix.diff
diff --git a/tools/android/make_all.sh b/tools/android/make_all.sh
new file mode 100755
index 0000000..d7d3517
--- /dev/null
+++ b/tools/android/make_all.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Abort if no known installation of NDK
+if [ "$NDK" == "" ]
+then
+ echo "Where is the NDK location ?"
+ echo -n "NDK: "; read NDK
+ export NDK=$NDK
+fi
+
+export ANDROID_NDK=$NDK
+
+# Abort if we don't know the Android CMake toolchain location
+if [ "$ANDROID_CMAKE_TOOLCHAIN" == "" ]
+then
+ echo "Where is the Android CMake toolchain ?"
+ echo -n "ANDROID_CMAKE_TOOLCHAIN: "; read ANDROID_CMAKE_TOOLCHAIN
+ export ANDROID_CMAKE_TOOLCHAIN=$ANDROID_CMAKE_TOOLCHAIN
+fi
+
+./clean_all.sh
+
+./create_toolchains.sh
+
+./download_sources.sh
+./compile_arm.sh
+
+rm -r $PWD/build
+./download_sources.sh
+./compile_x86.sh
+
+rm -r $PWD/build
+./download_sources.sh
+./compile_mips.sh
+
+rm -r $PWD/build
+./download_sources.sh
+./compile_arm-v7a.sh
diff --git a/tools/android/patches/remove-so-version-suffix.diff b/tools/android/patches/remove-so-version-suffix.diff
new file mode 100644
index 0000000..60b9805
--- /dev/null
+++ b/tools/android/patches/remove-so-version-suffix.diff
@@ -0,0 +1,13 @@
+--- CMakeLists.txt.orig 2013-09-21 15:23:49.305453804 +0200
++++ CMakeLists.txt 2013-09-21 15:24:08.621454210 +0200
+@@ -717,9 +717,7 @@
+ # Build a library
+ ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
+ SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES DEFINE_SYMBOL AL_BUILD_LIBRARY
+- COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES
+- VERSION ${LIB_VERSION}.0
+- SOVERSION ${LIB_MAJOR_VERSION})
++ COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES)
+ IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
+ SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
+ ENDIF()
diff --git a/tools/android/readme.txt b/tools/android/readme.txt
new file mode 100644
index 0000000..23949d1
--- /dev/null
+++ b/tools/android/readme.txt
@@ -0,0 +1,27 @@
+Compiling external libraries for Android can be a tedious task, especially for
+those who aren't familiar with the NDK, that's why we provide these scripts.
+
+IMPORTANT: Please, be careful when using these scripts! They are unpolished at
+the moment and you'll have to respect a simple rule: call these scripts from
+where they are. So, in that case, head yourself to tools/android, then call
+./make_all.sh.
+
+Feel free to improve them or send patches.
+
+HOW-TO-USE:
+-----------
+1) Some of these scripts need an environement variable to work ($NDK) as well
+as the Android CMake toolchain you'll find in cmake/toolchains (android.toolchain.cmake)
+export NDK=/path/to/your/ndk
+export ANDROID_CMAKE_TOOLCHAIN=/path/to/android.toolchain.cmake
+
+2) You'll need to make them executable, so:
+chmod +x *.sh
+
+3) Type: ./make_all.sh which should create standalone toolchains, download the
+external libraries and compile them.
+
+These scripts will be improved over time. Meanwhile, you'll have to play with
+them if you want a customized behavior.
+
+Good luck!
diff --git a/tools/pkg-config/sfml-all.pc.in b/tools/pkg-config/sfml-all.pc.in
new file mode 100644
index 0000000..dd2d4c3
--- /dev/null
+++ b/tools/pkg-config/sfml-all.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-all
+Description: The Simple and Fast Multimedia Library, all modules.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Requires: sfml-system, sfml-window, sfml-graphics, sfml-audio, sfml-network
diff --git a/tools/pkg-config/sfml-audio.pc.in b/tools/pkg-config/sfml-audio.pc.in
new file mode 100644
index 0000000..0d7a3ce
--- /dev/null
+++ b/tools/pkg-config/sfml-audio.pc.in
@@ -0,0 +1,15 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-audio
+Description: The Simple and Fast Multimedia Library, audio module.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Requires: sfml-system
+Requires.private: openal, vorbisenc, vorbisfile, vorbis, ogg, flac
+Libs: -L${libdir} -lsfml-audio
+# openal may be a system framework
+Libs.private: @OPENAL_LIBRARY@
+Cflags: -I${includedir}
diff --git a/tools/pkg-config/sfml-graphics.pc.in b/tools/pkg-config/sfml-graphics.pc.in
new file mode 100644
index 0000000..b138160
--- /dev/null
+++ b/tools/pkg-config/sfml-graphics.pc.in
@@ -0,0 +1,15 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-graphics
+Description: The Simple and Fast Multimedia Library, graphics module.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Requires: sfml-window
+Requires.private: sfml-system, freetype2
+Libs: -L${libdir} -lsfml-graphics
+# gl may not be in pkg-config
+Libs.private: @OPENGL_gl_LIBRARY@ @OPENGL_glu_LIBRARY@
+Cflags: -I${includedir}
diff --git a/tools/pkg-config/sfml-network.pc.in b/tools/pkg-config/sfml-network.pc.in
new file mode 100644
index 0000000..4381ca0
--- /dev/null
+++ b/tools/pkg-config/sfml-network.pc.in
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-network
+Description: The Simple and Fast Multimedia Library, network module.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Requires: sfml-system
+Libs: -L${libdir} -lsfml-network
+Cflags: -I${includedir}
diff --git a/tools/pkg-config/sfml-system.pc.in b/tools/pkg-config/sfml-system.pc.in
new file mode 100644
index 0000000..647ab53
--- /dev/null
+++ b/tools/pkg-config/sfml-system.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-system
+Description: The Simple and Fast Multimedia Library, system module.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Libs: -L${libdir} -lsfml-system
+Cflags: -I${includedir}
diff --git a/tools/pkg-config/sfml-window.pc.in b/tools/pkg-config/sfml-window.pc.in
new file mode 100644
index 0000000..93bf344
--- /dev/null
+++ b/tools/pkg-config/sfml-window.pc.in
@@ -0,0 +1,14 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+Name: SFML-window
+Description: The Simple and Fast Multimedia Library, window module.
+URL: http://www.sfml-dev.org
+Version: @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+Requires: sfml-system
+Libs: -L${libdir} -lsfml-window
+# gl may not be in pkg-config
+Libs.private: @OPENGL_gl_LIBRARY@ @OPENGL_glu_LIBRARY@
+Cflags: -I${includedir}