Repository: Is-Daouda/is-Engine
Branch: 4.0.x
Commit: 318bbfb6a711
Files: 1788
Total size: 181.0 MB
Directory structure:
gitextract_09tg11nt/
├── .gradle/
│ ├── 5.1.1/
│ │ └── gc.properties
│ ├── buildOutputCleanup/
│ │ └── cache.properties
│ └── vcs-1/
│ └── gc.properties
├── .idea/
│ ├── .gitignore
│ ├── caches/
│ │ └── build_file_checksums.ser
│ ├── codeStyles/
│ │ └── Project.xml
│ ├── compiler.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── is-Engine.iml
│ ├── jarRepositories.xml
│ ├── misc.xml
│ ├── modules/
│ │ ├── app/
│ │ │ └── is-Engine.app.iml
│ │ └── is-Engine.iml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── CMakeLists.txt
├── LICENSE.md
├── README.md
├── app/
│ ├── CMakeLists.txt
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── .vs/
│ │ └── vs-sfml/
│ │ ├── FileContentIndex/
│ │ │ ├── 27af3472-9fff-485a-80f6-a98dd9f34d58.vsidx
│ │ │ ├── 4d722eb7-4652-467b-a888-40e24ffc613c.vsidx
│ │ │ └── 9cbe5ebd-1110-46d2-a43c-740b2c898a99.vsidx
│ │ └── v17/
│ │ ├── .suo
│ │ ├── DocumentLayout.json
│ │ └── ipch/
│ │ └── AutoPCH/
│ │ ├── ee33401603bb6f9/
│ │ │ └── HELLOSCENE.ipch
│ │ └── f64c3c32af64e908/
│ │ └── BASICSFMLMAIN.ipch
│ ├── .vscode/
│ │ ├── _keybindings.json
│ │ ├── c_cpp_properties.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── AndroidManifest.xml
│ ├── CMakeLists.txt
│ ├── Makefile
│ ├── Makefile-vscode
│ ├── SDL2 Template.aps
│ ├── SDL2 Template.rc
│ ├── SDL2_SFML.sln
│ ├── SDL2_SFML.vcxproj
│ ├── SDL2_SFML.vcxproj.filters
│ ├── SDL2_SFML.vcxproj.user
│ ├── build.sh
│ ├── cmake/
│ │ ├── app_src.cmake
│ │ ├── isengine.cmake
│ │ └── resource.rc
│ ├── codeblocks/
│ │ └── resource.rc
│ ├── copy_assets.cmd
│ ├── cpp/
│ │ ├── GameDialog.cpp
│ │ ├── GameDisplay.cpp
│ │ ├── GameEngine.cpp
│ │ ├── GameFunction.cpp
│ │ ├── GameKeyData.cpp
│ │ ├── GameSlider.cpp
│ │ ├── GameSystem.cpp
│ │ ├── GameSystemExtended.cpp
│ │ ├── GameTime.cpp
│ │ ├── Main.hpp
│ │ ├── MainObject.cpp
│ │ ├── PCH.hpp
│ │ ├── SDL_android_main.c
│ │ ├── TransitionEffect.cpp
│ │ ├── app_src/
│ │ │ ├── activity/
│ │ │ │ └── GameActivity.h
│ │ │ ├── config/
│ │ │ │ ├── ExtraConfig.h
│ │ │ │ └── GameConfig.h
│ │ │ ├── gamesystem_ext/
│ │ │ │ └── GameSystemExtended.h
│ │ │ ├── language/
│ │ │ │ └── GameLanguage.h
│ │ │ ├── levels/
│ │ │ │ └── Level.h
│ │ │ ├── objects/
│ │ │ │ ├── HelloWorld.h
│ │ │ │ └── widgets/
│ │ │ │ └── GameDialog.h
│ │ │ └── scenes/
│ │ │ └── HelloScene/
│ │ │ └── HelloScene.h
│ │ ├── b2BlockAllocator.cpp
│ │ ├── b2Body.cpp
│ │ ├── b2BroadPhase.cpp
│ │ ├── b2ChainAndCircleContact.cpp
│ │ ├── b2ChainAndPolygonContact.cpp
│ │ ├── b2ChainShape.cpp
│ │ ├── b2CircleContact.cpp
│ │ ├── b2CircleShape.cpp
│ │ ├── b2CollideCircle.cpp
│ │ ├── b2CollideEdge.cpp
│ │ ├── b2CollidePolygon.cpp
│ │ ├── b2Collision.cpp
│ │ ├── b2Contact.cpp
│ │ ├── b2ContactManager.cpp
│ │ ├── b2ContactSolver.cpp
│ │ ├── b2Distance.cpp
│ │ ├── b2DistanceJoint.cpp
│ │ ├── b2Draw.cpp
│ │ ├── b2DynamicTree.cpp
│ │ ├── b2EdgeAndCircleContact.cpp
│ │ ├── b2EdgeAndPolygonContact.cpp
│ │ ├── b2EdgeShape.cpp
│ │ ├── b2Fixture.cpp
│ │ ├── b2FrictionJoint.cpp
│ │ ├── b2GearJoint.cpp
│ │ ├── b2Island.cpp
│ │ ├── b2Joint.cpp
│ │ ├── b2Math.cpp
│ │ ├── b2MotorJoint.cpp
│ │ ├── b2MouseJoint.cpp
│ │ ├── b2PolygonAndCircleContact.cpp
│ │ ├── b2PolygonContact.cpp
│ │ ├── b2PolygonShape.cpp
│ │ ├── b2PrismaticJoint.cpp
│ │ ├── b2PulleyJoint.cpp
│ │ ├── b2RevoluteJoint.cpp
│ │ ├── b2Rope.cpp
│ │ ├── b2RopeJoint.cpp
│ │ ├── b2Settings.cpp
│ │ ├── b2StackAllocator.cpp
│ │ ├── b2TimeOfImpact.cpp
│ │ ├── b2Timer.cpp
│ │ ├── b2WeldJoint.cpp
│ │ ├── b2WheelJoint.cpp
│ │ ├── b2World.cpp
│ │ ├── b2WorldCallbacks.cpp
│ │ ├── basicSFMLmain.cpp
│ │ ├── isEngine/
│ │ │ ├── core/
│ │ │ │ ├── ActivityController.h
│ │ │ │ └── GameEngine.h
│ │ │ ├── ext_lib/
│ │ │ │ ├── Box2D/
│ │ │ │ │ ├── Box2D.h
│ │ │ │ │ ├── Collision/
│ │ │ │ │ │ ├── Shapes/
│ │ │ │ │ │ │ ├── b2ChainShape.h
│ │ │ │ │ │ │ ├── b2CircleShape.h
│ │ │ │ │ │ │ ├── b2EdgeShape.h
│ │ │ │ │ │ │ ├── b2PolygonShape.h
│ │ │ │ │ │ │ └── b2Shape.h
│ │ │ │ │ │ ├── b2BroadPhase.h
│ │ │ │ │ │ ├── b2Collision.h
│ │ │ │ │ │ ├── b2Distance.h
│ │ │ │ │ │ ├── b2DynamicTree.h
│ │ │ │ │ │ └── b2TimeOfImpact.h
│ │ │ │ │ ├── Common/
│ │ │ │ │ │ ├── b2BlockAllocator.h
│ │ │ │ │ │ ├── b2Draw.h
│ │ │ │ │ │ ├── b2GrowableStack.h
│ │ │ │ │ │ ├── b2Math.h
│ │ │ │ │ │ ├── b2Settings.h
│ │ │ │ │ │ ├── b2StackAllocator.h
│ │ │ │ │ │ └── b2Timer.h
│ │ │ │ │ ├── Dynamics/
│ │ │ │ │ │ ├── Contacts/
│ │ │ │ │ │ │ ├── b2ChainAndCircleContact.h
│ │ │ │ │ │ │ ├── b2ChainAndPolygonContact.h
│ │ │ │ │ │ │ ├── b2CircleContact.h
│ │ │ │ │ │ │ ├── b2Contact.h
│ │ │ │ │ │ │ ├── b2ContactSolver.h
│ │ │ │ │ │ │ ├── b2EdgeAndCircleContact.h
│ │ │ │ │ │ │ ├── b2EdgeAndPolygonContact.h
│ │ │ │ │ │ │ ├── b2PolygonAndCircleContact.h
│ │ │ │ │ │ │ └── b2PolygonContact.h
│ │ │ │ │ │ ├── Joints/
│ │ │ │ │ │ │ ├── b2DistanceJoint.h
│ │ │ │ │ │ │ ├── b2FrictionJoint.h
│ │ │ │ │ │ │ ├── b2GearJoint.h
│ │ │ │ │ │ │ ├── b2Joint.h
│ │ │ │ │ │ │ ├── b2MotorJoint.h
│ │ │ │ │ │ │ ├── b2MouseJoint.h
│ │ │ │ │ │ │ ├── b2PrismaticJoint.h
│ │ │ │ │ │ │ ├── b2PulleyJoint.h
│ │ │ │ │ │ │ ├── b2RevoluteJoint.h
│ │ │ │ │ │ │ ├── b2RopeJoint.h
│ │ │ │ │ │ │ ├── b2WeldJoint.h
│ │ │ │ │ │ │ └── b2WheelJoint.h
│ │ │ │ │ │ ├── b2Body.h
│ │ │ │ │ │ ├── b2ContactManager.h
│ │ │ │ │ │ ├── b2Fixture.h
│ │ │ │ │ │ ├── b2Island.h
│ │ │ │ │ │ ├── b2TimeStep.h
│ │ │ │ │ │ ├── b2World.h
│ │ │ │ │ │ └── b2WorldCallbacks.h
│ │ │ │ │ └── Rope/
│ │ │ │ │ └── b2Rope.h
│ │ │ │ ├── TMXLite/
│ │ │ │ │ ├── Config.hpp
│ │ │ │ │ ├── FreeFuncs.cpp
│ │ │ │ │ ├── FreeFuncs.hpp
│ │ │ │ │ ├── ImageLayer.cpp
│ │ │ │ │ ├── ImageLayer.hpp
│ │ │ │ │ ├── Layer.hpp
│ │ │ │ │ ├── LayerGroup.cpp
│ │ │ │ │ ├── LayerGroup.hpp
│ │ │ │ │ ├── Map.cpp
│ │ │ │ │ ├── Map.hpp
│ │ │ │ │ ├── Object.cpp
│ │ │ │ │ ├── Object.hpp
│ │ │ │ │ ├── ObjectGroup.cpp
│ │ │ │ │ ├── ObjectGroup.hpp
│ │ │ │ │ ├── Property.cpp
│ │ │ │ │ ├── Property.hpp
│ │ │ │ │ ├── TileLayer.cpp
│ │ │ │ │ ├── TileLayer.hpp
│ │ │ │ │ ├── Tileset.cpp
│ │ │ │ │ ├── Tileset.hpp
│ │ │ │ │ ├── Types.hpp
│ │ │ │ │ ├── Types.inl
│ │ │ │ │ ├── detail/
│ │ │ │ │ │ ├── Android.hpp
│ │ │ │ │ │ ├── Log.hpp
│ │ │ │ │ │ ├── pugiconfig.hpp
│ │ │ │ │ │ ├── pugixml.LICENSE
│ │ │ │ │ │ ├── pugixml.cpp
│ │ │ │ │ │ └── pugixml.hpp
│ │ │ │ │ ├── miniz.c
│ │ │ │ │ └── miniz.h
│ │ │ │ └── TinyFileDialogs/
│ │ │ │ ├── TinyDialogBox.h
│ │ │ │ ├── tinyfiledialogs.cpp
│ │ │ │ └── tinyfiledialogs.h
│ │ │ └── system/
│ │ │ ├── display/
│ │ │ │ ├── GameDisplay.h
│ │ │ │ ├── SDM.h
│ │ │ │ └── SDMBlitSDLSprite.h
│ │ │ ├── entity/
│ │ │ │ ├── Background.h
│ │ │ │ ├── Button.h
│ │ │ │ ├── Form.h
│ │ │ │ ├── MainObject.h
│ │ │ │ └── parents/
│ │ │ │ ├── DepthObject.h
│ │ │ │ ├── Destructible.h
│ │ │ │ ├── FilePath.h
│ │ │ │ ├── Health.h
│ │ │ │ ├── HurtEffect.h
│ │ │ │ ├── Name.h
│ │ │ │ ├── ScorePoint.h
│ │ │ │ ├── Step.h
│ │ │ │ ├── Type.h
│ │ │ │ └── Visibilty.h
│ │ │ ├── function/
│ │ │ │ ├── GameFunction.h
│ │ │ │ ├── GameKeyData.h
│ │ │ │ ├── GameKeyName.h
│ │ │ │ ├── GameSlider.h
│ │ │ │ ├── GameSystem.h
│ │ │ │ └── GameTime.h
│ │ │ ├── graphic/
│ │ │ │ ├── GRM.h
│ │ │ │ ├── GameFont.h
│ │ │ │ ├── GameTexture.h
│ │ │ │ └── TransitionEffect.h
│ │ │ ├── islibconnect/
│ │ │ │ ├── isEngineSDLWrapper.h
│ │ │ │ ├── isEngineVector2Wrapper.inl
│ │ │ │ ├── isEngineWrapper.h
│ │ │ │ └── isLibConnect.h
│ │ │ └── sound/
│ │ │ ├── GSM.h
│ │ │ ├── GameMusic.h
│ │ │ └── GameSound.h
│ │ ├── isEngineSDLWrapper.cpp
│ │ ├── isEngineWrapper.cpp
│ │ ├── main.cpp
│ │ ├── resource.h
│ │ └── vscode/
│ │ ├── Linux/
│ │ │ ├── LinuxHelper.cpp
│ │ │ └── LinuxHelper.hpp
│ │ ├── MacOS/
│ │ │ ├── MacHelper.cpp
│ │ │ └── MacHelper.hpp
│ │ ├── Utility/
│ │ │ └── Types.hpp
│ │ └── Win32/
│ │ ├── Icon.h
│ │ ├── Icon.rc
│ │ ├── WindowsHelper.cpp
│ │ └── WindowsHelper.hpp
│ ├── env/
│ │ ├── .all.mk
│ │ ├── .debug.mk
│ │ ├── .release.mk
│ │ ├── linux/
│ │ │ └── exec.desktop
│ │ ├── linux.all.mk
│ │ ├── osx/
│ │ │ ├── Info.plist.json
│ │ │ └── dmg.applescript
│ │ ├── osx.all.mk
│ │ ├── osx.debug.mk
│ │ ├── rpi.release.mk
│ │ ├── windows/
│ │ │ ├── win-make_icon_from256.sh
│ │ │ └── win-make_icon_from_all.sh
│ │ ├── windows.all.mk
│ │ ├── windows.debug.mk
│ │ └── windows.release.mk
│ ├── external/
│ │ └── SFML/
│ │ ├── include/
│ │ │ └── SFML/
│ │ │ ├── Audio/
│ │ │ │ ├── AlResource.hpp
│ │ │ │ ├── Export.hpp
│ │ │ │ ├── InputSoundFile.hpp
│ │ │ │ ├── Listener.hpp
│ │ │ │ ├── Music.hpp
│ │ │ │ ├── OutputSoundFile.hpp
│ │ │ │ ├── Sound.hpp
│ │ │ │ ├── SoundBuffer.hpp
│ │ │ │ ├── SoundBufferRecorder.hpp
│ │ │ │ ├── SoundFileFactory.hpp
│ │ │ │ ├── SoundFileFactory.inl
│ │ │ │ ├── SoundFileReader.hpp
│ │ │ │ ├── SoundFileWriter.hpp
│ │ │ │ ├── SoundRecorder.hpp
│ │ │ │ ├── SoundSource.hpp
│ │ │ │ └── SoundStream.hpp
│ │ │ ├── Audio.hpp
│ │ │ ├── Config.hpp
│ │ │ ├── GpuPreference.hpp
│ │ │ ├── Graphics/
│ │ │ │ ├── BlendMode.hpp
│ │ │ │ ├── CircleShape.hpp
│ │ │ │ ├── Color.hpp
│ │ │ │ ├── ConvexShape.hpp
│ │ │ │ ├── Drawable.hpp
│ │ │ │ ├── Export.hpp
│ │ │ │ ├── Font.hpp
│ │ │ │ ├── Glsl.hpp
│ │ │ │ ├── Glsl.inl
│ │ │ │ ├── Glyph.hpp
│ │ │ │ ├── Image.hpp
│ │ │ │ ├── PrimitiveType.hpp
│ │ │ │ ├── Rect.hpp
│ │ │ │ ├── Rect.inl
│ │ │ │ ├── RectangleShape.hpp
│ │ │ │ ├── RenderStates.hpp
│ │ │ │ ├── RenderTarget.hpp
│ │ │ │ ├── RenderTexture.hpp
│ │ │ │ ├── RenderWindow.hpp
│ │ │ │ ├── Shader.hpp
│ │ │ │ ├── Shape.hpp
│ │ │ │ ├── Sprite.hpp
│ │ │ │ ├── Text.hpp
│ │ │ │ ├── Texture.hpp
│ │ │ │ ├── Transform.hpp
│ │ │ │ ├── Transformable.hpp
│ │ │ │ ├── Vertex.hpp
│ │ │ │ ├── VertexArray.hpp
│ │ │ │ ├── VertexBuffer.hpp
│ │ │ │ └── View.hpp
│ │ │ ├── Graphics.hpp
│ │ │ ├── Main.hpp
│ │ │ ├── Network/
│ │ │ │ ├── Export.hpp
│ │ │ │ ├── Ftp.hpp
│ │ │ │ ├── Http.hpp
│ │ │ │ ├── IpAddress.hpp
│ │ │ │ ├── Packet.hpp
│ │ │ │ ├── Socket.hpp
│ │ │ │ ├── SocketHandle.hpp
│ │ │ │ ├── SocketSelector.hpp
│ │ │ │ ├── TcpListener.hpp
│ │ │ │ ├── TcpSocket.hpp
│ │ │ │ └── UdpSocket.hpp
│ │ │ ├── Network.hpp
│ │ │ ├── OpenGL.hpp
│ │ │ ├── System/
│ │ │ │ ├── Clock.hpp
│ │ │ │ ├── Err.hpp
│ │ │ │ ├── Export.hpp
│ │ │ │ ├── FileInputStream.hpp
│ │ │ │ ├── InputStream.hpp
│ │ │ │ ├── Lock.hpp
│ │ │ │ ├── MemoryInputStream.hpp
│ │ │ │ ├── Mutex.hpp
│ │ │ │ ├── NativeActivity.hpp
│ │ │ │ ├── NonCopyable.hpp
│ │ │ │ ├── Sleep.hpp
│ │ │ │ ├── String.hpp
│ │ │ │ ├── String.inl
│ │ │ │ ├── Thread.hpp
│ │ │ │ ├── Thread.inl
│ │ │ │ ├── ThreadLocal.hpp
│ │ │ │ ├── ThreadLocalPtr.hpp
│ │ │ │ ├── ThreadLocalPtr.inl
│ │ │ │ ├── Time.hpp
│ │ │ │ ├── Utf.hpp
│ │ │ │ ├── Utf.inl
│ │ │ │ ├── Vector2.hpp
│ │ │ │ ├── Vector2.inl
│ │ │ │ ├── Vector3.hpp
│ │ │ │ └── Vector3.inl
│ │ │ ├── System.hpp
│ │ │ ├── Window/
│ │ │ │ ├── Clipboard.hpp
│ │ │ │ ├── Context.hpp
│ │ │ │ ├── ContextSettings.hpp
│ │ │ │ ├── Cursor.hpp
│ │ │ │ ├── Event.hpp
│ │ │ │ ├── Export.hpp
│ │ │ │ ├── GlResource.hpp
│ │ │ │ ├── Joystick.hpp
│ │ │ │ ├── Keyboard.hpp
│ │ │ │ ├── Mouse.hpp
│ │ │ │ ├── Sensor.hpp
│ │ │ │ ├── Touch.hpp
│ │ │ │ ├── VideoMode.hpp
│ │ │ │ ├── Vulkan.hpp
│ │ │ │ ├── Window.hpp
│ │ │ │ ├── WindowBase.hpp
│ │ │ │ ├── WindowHandle.hpp
│ │ │ │ └── WindowStyle.hpp
│ │ │ └── Window.hpp
│ │ └── lib/
│ │ ├── Debug/
│ │ │ ├── sfml-audio-s-d.pdb
│ │ │ ├── sfml-audio-s.pdb
│ │ │ ├── sfml-audio.pdb
│ │ │ ├── sfml-graphics-s-d.pdb
│ │ │ ├── sfml-graphics-s.pdb
│ │ │ ├── sfml-graphics.pdb
│ │ │ ├── sfml-main-d.pdb
│ │ │ ├── sfml-main-s.pdb
│ │ │ ├── sfml-network-s-d.pdb
│ │ │ ├── sfml-network-s.pdb
│ │ │ ├── sfml-network.pdb
│ │ │ ├── sfml-system-s-d.pdb
│ │ │ ├── sfml-system-s.pdb
│ │ │ ├── sfml-system.pdb
│ │ │ ├── sfml-window-s-d.pdb
│ │ │ ├── sfml-window-s.pdb
│ │ │ └── sfml-window.pdb
│ │ ├── cmake/
│ │ │ └── SFML/
│ │ │ ├── SFMLConfig.cmake
│ │ │ ├── SFMLConfigDependencies.cmake
│ │ │ ├── SFMLConfigVersion.cmake
│ │ │ ├── SFMLSharedTargets-debug.cmake
│ │ │ ├── SFMLSharedTargets-release.cmake
│ │ │ ├── SFMLSharedTargets.cmake
│ │ │ ├── SFMLStaticTargets-debug.cmake
│ │ │ ├── SFMLStaticTargets-release.cmake
│ │ │ └── SFMLStaticTargets.cmake
│ │ ├── flac.lib
│ │ ├── freetype.lib
│ │ ├── ogg.lib
│ │ ├── openal32.lib
│ │ ├── sfml-audio-d.lib
│ │ ├── sfml-audio-s-d.lib
│ │ ├── sfml-audio-s.lib
│ │ ├── sfml-audio.lib
│ │ ├── sfml-graphics-d.lib
│ │ ├── sfml-graphics-s-d.lib
│ │ ├── sfml-graphics-s.lib
│ │ ├── sfml-graphics.lib
│ │ ├── sfml-main-d.lib
│ │ ├── sfml-main.lib
│ │ ├── sfml-network-d.lib
│ │ ├── sfml-network-s-d.lib
│ │ ├── sfml-network-s.lib
│ │ ├── sfml-network.lib
│ │ ├── sfml-system-d.lib
│ │ ├── sfml-system-s-d.lib
│ │ ├── sfml-system-s.lib
│ │ ├── sfml-system.lib
│ │ ├── sfml-window-d.lib
│ │ ├── sfml-window-s-d.lib
│ │ ├── sfml-window-s.lib
│ │ ├── sfml-window.lib
│ │ ├── vorbis.lib
│ │ ├── vorbisenc.lib
│ │ └── vorbisfile.lib
│ ├── is-Engine-linux-SDL2.cbp
│ ├── is-Engine-linux.cbp
│ ├── is-Engine-windows-SDL2.cbp
│ ├── is-Engine-windows.cbp
│ ├── java/
│ │ └── com/
│ │ └── author/
│ │ └── isengine/
│ │ └── SDLActivity.java
│ ├── lib/
│ │ └── catch2/
│ │ └── catch.hpp
│ ├── qt/
│ │ ├── is-Engine.pro
│ │ └── is-Engine.pro.user
│ ├── res/
│ │ └── values/
│ │ └── strings.xml
│ ├── vs-sfml.sln
│ ├── vs-sfml.vcxproj
│ ├── vs-sfml.vcxproj.filters
│ ├── vs-sfml.vcxproj.user
│ └── web/
│ ├── index.html
│ ├── scripts/
│ │ └── main.js
│ ├── styles/
│ │ └── index.css
│ └── sw.js
├── build.gradle
├── doc/
│ ├── isEngine_api_doc_eng.html
│ └── isEngine_api_doc_fr.html
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── libs/
│ ├── SDL2/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2.dir/
│ │ │ └── src/
│ │ │ ├── SDL.c.o
│ │ │ ├── SDL_assert.c.o
│ │ │ ├── SDL_error.c.o
│ │ │ ├── SDL_hints.c.o
│ │ │ ├── SDL_log.c.o
│ │ │ ├── atomic/
│ │ │ │ ├── SDL_atomic.c.o
│ │ │ │ └── SDL_spinlock.c.o
│ │ │ ├── audio/
│ │ │ │ ├── SDL_audio.c.o
│ │ │ │ ├── SDL_audiocvt.c.o
│ │ │ │ ├── SDL_audiodev.c.o
│ │ │ │ ├── SDL_audiotypecvt.c.o
│ │ │ │ ├── SDL_mixer.c.o
│ │ │ │ ├── SDL_wave.c.o
│ │ │ │ ├── android/
│ │ │ │ │ └── SDL_androidaudio.c.o
│ │ │ │ ├── dummy/
│ │ │ │ │ └── SDL_dummyaudio.c.o
│ │ │ │ └── paudio/
│ │ │ │ └── SDL_paudio.c.o
│ │ │ ├── core/
│ │ │ │ └── android/
│ │ │ │ └── SDL_android.c.o
│ │ │ ├── cpuinfo/
│ │ │ │ └── SDL_cpuinfo.c.o
│ │ │ ├── dynapi/
│ │ │ │ └── SDL_dynapi.c.o
│ │ │ ├── events/
│ │ │ │ ├── SDL_clipboardevents.c.o
│ │ │ │ ├── SDL_dropevents.c.o
│ │ │ │ ├── SDL_events.c.o
│ │ │ │ ├── SDL_gesture.c.o
│ │ │ │ ├── SDL_keyboard.c.o
│ │ │ │ ├── SDL_mouse.c.o
│ │ │ │ ├── SDL_quit.c.o
│ │ │ │ ├── SDL_touch.c.o
│ │ │ │ └── SDL_windowevents.c.o
│ │ │ ├── file/
│ │ │ │ └── SDL_rwops.c.o
│ │ │ ├── filesystem/
│ │ │ │ └── android/
│ │ │ │ └── SDL_sysfilesystem.c.o
│ │ │ ├── haptic/
│ │ │ │ ├── SDL_haptic.c.o
│ │ │ │ └── dummy/
│ │ │ │ └── SDL_syshaptic.c.o
│ │ │ ├── joystick/
│ │ │ │ ├── SDL_gamecontroller.c.o
│ │ │ │ ├── SDL_joystick.c.o
│ │ │ │ └── android/
│ │ │ │ └── SDL_sysjoystick.c.o
│ │ │ ├── libm/
│ │ │ │ ├── e_atan2.c.o
│ │ │ │ ├── e_log.c.o
│ │ │ │ ├── e_pow.c.o
│ │ │ │ ├── e_rem_pio2.c.o
│ │ │ │ ├── e_sqrt.c.o
│ │ │ │ ├── k_cos.c.o
│ │ │ │ ├── k_rem_pio2.c.o
│ │ │ │ ├── k_sin.c.o
│ │ │ │ ├── k_tan.c.o
│ │ │ │ ├── s_atan.c.o
│ │ │ │ ├── s_copysign.c.o
│ │ │ │ ├── s_cos.c.o
│ │ │ │ ├── s_fabs.c.o
│ │ │ │ ├── s_floor.c.o
│ │ │ │ ├── s_scalbn.c.o
│ │ │ │ ├── s_sin.c.o
│ │ │ │ └── s_tan.c.o
│ │ │ ├── loadso/
│ │ │ │ └── dlopen/
│ │ │ │ └── SDL_sysloadso.c.o
│ │ │ ├── power/
│ │ │ │ ├── SDL_power.c.o
│ │ │ │ └── android/
│ │ │ │ └── SDL_syspower.c.o
│ │ │ ├── render/
│ │ │ │ ├── SDL_d3dmath.c.o
│ │ │ │ ├── SDL_render.c.o
│ │ │ │ ├── SDL_yuv_mmx.c.o
│ │ │ │ ├── SDL_yuv_sw.c.o
│ │ │ │ ├── opengl/
│ │ │ │ │ ├── SDL_render_gl.c.o
│ │ │ │ │ └── SDL_shaders_gl.c.o
│ │ │ │ ├── opengles/
│ │ │ │ │ └── SDL_render_gles.c.o
│ │ │ │ ├── opengles2/
│ │ │ │ │ ├── SDL_render_gles2.c.o
│ │ │ │ │ └── SDL_shaders_gles2.c.o
│ │ │ │ ├── psp/
│ │ │ │ │ └── SDL_render_psp.c.o
│ │ │ │ └── software/
│ │ │ │ ├── SDL_blendfillrect.c.o
│ │ │ │ ├── SDL_blendline.c.o
│ │ │ │ ├── SDL_blendpoint.c.o
│ │ │ │ ├── SDL_drawline.c.o
│ │ │ │ ├── SDL_drawpoint.c.o
│ │ │ │ ├── SDL_render_sw.c.o
│ │ │ │ └── SDL_rotate.c.o
│ │ │ ├── stdlib/
│ │ │ │ ├── SDL_getenv.c.o
│ │ │ │ ├── SDL_iconv.c.o
│ │ │ │ ├── SDL_malloc.c.o
│ │ │ │ ├── SDL_qsort.c.o
│ │ │ │ ├── SDL_stdlib.c.o
│ │ │ │ └── SDL_string.c.o
│ │ │ ├── test/
│ │ │ │ ├── SDL_test_assert.c.o
│ │ │ │ ├── SDL_test_common.c.o
│ │ │ │ ├── SDL_test_compare.c.o
│ │ │ │ ├── SDL_test_crc32.c.o
│ │ │ │ ├── SDL_test_font.c.o
│ │ │ │ ├── SDL_test_fuzzer.c.o
│ │ │ │ ├── SDL_test_harness.c.o
│ │ │ │ ├── SDL_test_imageBlit.c.o
│ │ │ │ ├── SDL_test_imageBlitBlend.c.o
│ │ │ │ ├── SDL_test_imageFace.c.o
│ │ │ │ ├── SDL_test_imagePrimitives.c.o
│ │ │ │ ├── SDL_test_imagePrimitivesBlend.c.o
│ │ │ │ ├── SDL_test_log.c.o
│ │ │ │ ├── SDL_test_md5.c.o
│ │ │ │ └── SDL_test_random.c.o
│ │ │ ├── thread/
│ │ │ │ ├── SDL_thread.c.o
│ │ │ │ └── pthread/
│ │ │ │ ├── SDL_syscond.c.o
│ │ │ │ ├── SDL_sysmutex.c.o
│ │ │ │ ├── SDL_syssem.c.o
│ │ │ │ ├── SDL_systhread.c.o
│ │ │ │ └── SDL_systls.c.o
│ │ │ ├── timer/
│ │ │ │ ├── SDL_timer.c.o
│ │ │ │ └── unix/
│ │ │ │ └── SDL_systimer.c.o
│ │ │ └── video/
│ │ │ ├── SDL_RLEaccel.c.o
│ │ │ ├── SDL_blit.c.o
│ │ │ ├── SDL_blit_0.c.o
│ │ │ ├── SDL_blit_1.c.o
│ │ │ ├── SDL_blit_A.c.o
│ │ │ ├── SDL_blit_N.c.o
│ │ │ ├── SDL_blit_auto.c.o
│ │ │ ├── SDL_blit_copy.c.o
│ │ │ ├── SDL_blit_slow.c.o
│ │ │ ├── SDL_bmp.c.o
│ │ │ ├── SDL_clipboard.c.o
│ │ │ ├── SDL_egl.c.o
│ │ │ ├── SDL_fillrect.c.o
│ │ │ ├── SDL_pixels.c.o
│ │ │ ├── SDL_rect.c.o
│ │ │ ├── SDL_shape.c.o
│ │ │ ├── SDL_stretch.c.o
│ │ │ ├── SDL_surface.c.o
│ │ │ ├── SDL_video.c.o
│ │ │ └── android/
│ │ │ ├── SDL_androidclipboard.c.o
│ │ │ ├── SDL_androidevents.c.o
│ │ │ ├── SDL_androidgl.c.o
│ │ │ ├── SDL_androidkeyboard.c.o
│ │ │ ├── SDL_androidmessagebox.c.o
│ │ │ ├── SDL_androidmouse.c.o
│ │ │ ├── SDL_androidtouch.c.o
│ │ │ ├── SDL_androidvideo.c.o
│ │ │ └── SDL_androidwindow.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── SDL.h
│ │ │ ├── SDL_assert.h
│ │ │ ├── SDL_atomic.h
│ │ │ ├── SDL_audio.h
│ │ │ ├── SDL_bits.h
│ │ │ ├── SDL_blendmode.h
│ │ │ ├── SDL_clipboard.h
│ │ │ ├── SDL_config.h
│ │ │ ├── SDL_config.h.cmake
│ │ │ ├── SDL_config.h.in
│ │ │ ├── SDL_config_android.h
│ │ │ ├── SDL_config_iphoneos.h
│ │ │ ├── SDL_config_macosx.h
│ │ │ ├── SDL_config_minimal.h
│ │ │ ├── SDL_config_pandora.h
│ │ │ ├── SDL_config_psp.h
│ │ │ ├── SDL_config_windows.h
│ │ │ ├── SDL_config_winrt.h
│ │ │ ├── SDL_config_wiz.h
│ │ │ ├── SDL_copying.h
│ │ │ ├── SDL_cpuinfo.h
│ │ │ ├── SDL_egl.h
│ │ │ ├── SDL_endian.h
│ │ │ ├── SDL_error.h
│ │ │ ├── SDL_events.h
│ │ │ ├── SDL_filesystem.h
│ │ │ ├── SDL_gamecontroller.h
│ │ │ ├── SDL_gesture.h
│ │ │ ├── SDL_haptic.h
│ │ │ ├── SDL_hints.h
│ │ │ ├── SDL_joystick.h
│ │ │ ├── SDL_keyboard.h
│ │ │ ├── SDL_keycode.h
│ │ │ ├── SDL_loadso.h
│ │ │ ├── SDL_log.h
│ │ │ ├── SDL_main.h
│ │ │ ├── SDL_messagebox.h
│ │ │ ├── SDL_mouse.h
│ │ │ ├── SDL_mutex.h
│ │ │ ├── SDL_name.h
│ │ │ ├── SDL_opengl.h
│ │ │ ├── SDL_opengl_glext.h
│ │ │ ├── SDL_opengles.h
│ │ │ ├── SDL_opengles2.h
│ │ │ ├── SDL_opengles2_gl2.h
│ │ │ ├── SDL_opengles2_gl2ext.h
│ │ │ ├── SDL_opengles2_gl2platform.h
│ │ │ ├── SDL_opengles2_khrplatform.h
│ │ │ ├── SDL_pixels.h
│ │ │ ├── SDL_platform.h
│ │ │ ├── SDL_power.h
│ │ │ ├── SDL_quit.h
│ │ │ ├── SDL_rect.h
│ │ │ ├── SDL_render.h
│ │ │ ├── SDL_revision.h
│ │ │ ├── SDL_rwops.h
│ │ │ ├── SDL_scancode.h
│ │ │ ├── SDL_shape.h
│ │ │ ├── SDL_stdinc.h
│ │ │ ├── SDL_surface.h
│ │ │ ├── SDL_system.h
│ │ │ ├── SDL_syswm.h
│ │ │ ├── SDL_test.h
│ │ │ ├── SDL_test_assert.h
│ │ │ ├── SDL_test_common.h
│ │ │ ├── SDL_test_compare.h
│ │ │ ├── SDL_test_crc32.h
│ │ │ ├── SDL_test_font.h
│ │ │ ├── SDL_test_fuzzer.h
│ │ │ ├── SDL_test_harness.h
│ │ │ ├── SDL_test_images.h
│ │ │ ├── SDL_test_log.h
│ │ │ ├── SDL_test_md5.h
│ │ │ ├── SDL_test_random.h
│ │ │ ├── SDL_thread.h
│ │ │ ├── SDL_timer.h
│ │ │ ├── SDL_touch.h
│ │ │ ├── SDL_types.h
│ │ │ ├── SDL_version.h
│ │ │ ├── SDL_video.h
│ │ │ ├── begin_code.h
│ │ │ └── close_code.h
│ │ └── src/
│ │ ├── SDL.c
│ │ ├── SDL_assert.c
│ │ ├── SDL_assert_c.h
│ │ ├── SDL_error.c
│ │ ├── SDL_error_c.h
│ │ ├── SDL_hints.c
│ │ ├── SDL_internal.h
│ │ ├── SDL_log.c
│ │ ├── atomic/
│ │ │ ├── SDL_atomic.c
│ │ │ └── SDL_spinlock.c
│ │ ├── audio/
│ │ │ ├── SDL_audio.c
│ │ │ ├── SDL_audio_c.h
│ │ │ ├── SDL_audiocvt.c
│ │ │ ├── SDL_audiodev.c
│ │ │ ├── SDL_audiodev_c.h
│ │ │ ├── SDL_audiotypecvt.c
│ │ │ ├── SDL_mixer.c
│ │ │ ├── SDL_sysaudio.h
│ │ │ ├── SDL_wave.c
│ │ │ ├── SDL_wave.h
│ │ │ ├── android/
│ │ │ │ ├── SDL_androidaudio.c
│ │ │ │ └── SDL_androidaudio.h
│ │ │ ├── dummy/
│ │ │ │ ├── SDL_dummyaudio.c
│ │ │ │ └── SDL_dummyaudio.h
│ │ │ ├── paudio/
│ │ │ │ ├── SDL_paudio.c
│ │ │ │ └── SDL_paudio.h
│ │ │ └── sdlgenaudiocvt.pl
│ │ ├── core/
│ │ │ └── android/
│ │ │ ├── SDL_android.c
│ │ │ └── SDL_android.h
│ │ ├── cpuinfo/
│ │ │ └── SDL_cpuinfo.c
│ │ ├── dynapi/
│ │ │ ├── SDL_dynapi.c
│ │ │ ├── SDL_dynapi.h
│ │ │ ├── SDL_dynapi_overrides.h
│ │ │ ├── SDL_dynapi_procs.h
│ │ │ └── gendynapi.pl
│ │ ├── events/
│ │ │ ├── SDL_clipboardevents.c
│ │ │ ├── SDL_clipboardevents_c.h
│ │ │ ├── SDL_dropevents.c
│ │ │ ├── SDL_dropevents_c.h
│ │ │ ├── SDL_events.c
│ │ │ ├── SDL_events_c.h
│ │ │ ├── SDL_gesture.c
│ │ │ ├── SDL_gesture_c.h
│ │ │ ├── SDL_keyboard.c
│ │ │ ├── SDL_keyboard_c.h
│ │ │ ├── SDL_mouse.c
│ │ │ ├── SDL_mouse_c.h
│ │ │ ├── SDL_quit.c
│ │ │ ├── SDL_sysevents.h
│ │ │ ├── SDL_touch.c
│ │ │ ├── SDL_touch_c.h
│ │ │ ├── SDL_windowevents.c
│ │ │ ├── SDL_windowevents_c.h
│ │ │ ├── blank_cursor.h
│ │ │ ├── default_cursor.h
│ │ │ ├── scancodes_darwin.h
│ │ │ ├── scancodes_linux.h
│ │ │ ├── scancodes_windows.h
│ │ │ └── scancodes_xfree86.h
│ │ ├── file/
│ │ │ └── SDL_rwops.c
│ │ ├── filesystem/
│ │ │ └── android/
│ │ │ └── SDL_sysfilesystem.c
│ │ ├── haptic/
│ │ │ ├── SDL_haptic.c
│ │ │ ├── SDL_haptic_c.h
│ │ │ ├── SDL_syshaptic.h
│ │ │ └── dummy/
│ │ │ └── SDL_syshaptic.c
│ │ ├── joystick/
│ │ │ ├── SDL_gamecontroller.c
│ │ │ ├── SDL_gamecontrollerdb.h
│ │ │ ├── SDL_joystick.c
│ │ │ ├── SDL_joystick_c.h
│ │ │ ├── SDL_sysjoystick.h
│ │ │ ├── android/
│ │ │ │ ├── SDL_sysjoystick.c
│ │ │ │ └── SDL_sysjoystick_c.h
│ │ │ └── sort_controllers.py
│ │ ├── libm/
│ │ │ ├── e_atan2.c
│ │ │ ├── e_log.c
│ │ │ ├── e_pow.c
│ │ │ ├── e_rem_pio2.c
│ │ │ ├── e_sqrt.c
│ │ │ ├── k_cos.c
│ │ │ ├── k_rem_pio2.c
│ │ │ ├── k_sin.c
│ │ │ ├── k_tan.c
│ │ │ ├── math_libm.h
│ │ │ ├── math_private.h
│ │ │ ├── s_atan.c
│ │ │ ├── s_copysign.c
│ │ │ ├── s_cos.c
│ │ │ ├── s_fabs.c
│ │ │ ├── s_floor.c
│ │ │ ├── s_scalbn.c
│ │ │ ├── s_sin.c
│ │ │ └── s_tan.c
│ │ ├── loadso/
│ │ │ └── dlopen/
│ │ │ └── SDL_sysloadso.c
│ │ ├── power/
│ │ │ ├── SDL_power.c
│ │ │ └── android/
│ │ │ └── SDL_syspower.c
│ │ ├── render/
│ │ │ ├── SDL_d3dmath.c
│ │ │ ├── SDL_d3dmath.h
│ │ │ ├── SDL_render.c
│ │ │ ├── SDL_sysrender.h
│ │ │ ├── SDL_yuv_mmx.c
│ │ │ ├── SDL_yuv_sw.c
│ │ │ ├── SDL_yuv_sw_c.h
│ │ │ ├── mmx.h
│ │ │ ├── opengl/
│ │ │ │ ├── SDL_glfuncs.h
│ │ │ │ ├── SDL_render_gl.c
│ │ │ │ ├── SDL_shaders_gl.c
│ │ │ │ └── SDL_shaders_gl.h
│ │ │ ├── opengles/
│ │ │ │ ├── SDL_glesfuncs.h
│ │ │ │ └── SDL_render_gles.c
│ │ │ ├── opengles2/
│ │ │ │ ├── SDL_gles2funcs.h
│ │ │ │ ├── SDL_render_gles2.c
│ │ │ │ ├── SDL_shaders_gles2.c
│ │ │ │ └── SDL_shaders_gles2.h
│ │ │ ├── psp/
│ │ │ │ └── SDL_render_psp.c
│ │ │ └── software/
│ │ │ ├── SDL_blendfillrect.c
│ │ │ ├── SDL_blendfillrect.h
│ │ │ ├── SDL_blendline.c
│ │ │ ├── SDL_blendline.h
│ │ │ ├── SDL_blendpoint.c
│ │ │ ├── SDL_blendpoint.h
│ │ │ ├── SDL_draw.h
│ │ │ ├── SDL_drawline.c
│ │ │ ├── SDL_drawline.h
│ │ │ ├── SDL_drawpoint.c
│ │ │ ├── SDL_drawpoint.h
│ │ │ ├── SDL_render_sw.c
│ │ │ ├── SDL_render_sw_c.h
│ │ │ ├── SDL_rotate.c
│ │ │ └── SDL_rotate.h
│ │ ├── stdlib/
│ │ │ ├── SDL_getenv.c
│ │ │ ├── SDL_iconv.c
│ │ │ ├── SDL_malloc.c
│ │ │ ├── SDL_qsort.c
│ │ │ ├── SDL_stdlib.c
│ │ │ └── SDL_string.c
│ │ ├── test/
│ │ │ ├── SDL_test_assert.c
│ │ │ ├── SDL_test_common.c
│ │ │ ├── SDL_test_compare.c
│ │ │ ├── SDL_test_crc32.c
│ │ │ ├── SDL_test_font.c
│ │ │ ├── SDL_test_fuzzer.c
│ │ │ ├── SDL_test_harness.c
│ │ │ ├── SDL_test_imageBlit.c
│ │ │ ├── SDL_test_imageBlitBlend.c
│ │ │ ├── SDL_test_imageFace.c
│ │ │ ├── SDL_test_imagePrimitives.c
│ │ │ ├── SDL_test_imagePrimitivesBlend.c
│ │ │ ├── SDL_test_log.c
│ │ │ ├── SDL_test_md5.c
│ │ │ └── SDL_test_random.c
│ │ ├── thread/
│ │ │ ├── SDL_systhread.h
│ │ │ ├── SDL_thread.c
│ │ │ ├── SDL_thread_c.h
│ │ │ └── pthread/
│ │ │ ├── SDL_syscond.c
│ │ │ ├── SDL_sysmutex.c
│ │ │ ├── SDL_sysmutex_c.h
│ │ │ ├── SDL_syssem.c
│ │ │ ├── SDL_systhread.c
│ │ │ ├── SDL_systhread_c.h
│ │ │ └── SDL_systls.c
│ │ ├── timer/
│ │ │ ├── SDL_timer.c
│ │ │ ├── SDL_timer_c.h
│ │ │ └── unix/
│ │ │ └── SDL_systimer.c
│ │ └── video/
│ │ ├── SDL_RLEaccel.c
│ │ ├── SDL_RLEaccel_c.h
│ │ ├── SDL_blit.c
│ │ ├── SDL_blit.h
│ │ ├── SDL_blit_0.c
│ │ ├── SDL_blit_1.c
│ │ ├── SDL_blit_A.c
│ │ ├── SDL_blit_N.c
│ │ ├── SDL_blit_auto.c
│ │ ├── SDL_blit_auto.h
│ │ ├── SDL_blit_copy.c
│ │ ├── SDL_blit_copy.h
│ │ ├── SDL_blit_slow.c
│ │ ├── SDL_blit_slow.h
│ │ ├── SDL_bmp.c
│ │ ├── SDL_clipboard.c
│ │ ├── SDL_egl.c
│ │ ├── SDL_egl_c.h
│ │ ├── SDL_fillrect.c
│ │ ├── SDL_pixels.c
│ │ ├── SDL_pixels_c.h
│ │ ├── SDL_rect.c
│ │ ├── SDL_rect_c.h
│ │ ├── SDL_shape.c
│ │ ├── SDL_shape_internals.h
│ │ ├── SDL_stretch.c
│ │ ├── SDL_surface.c
│ │ ├── SDL_sysvideo.h
│ │ ├── SDL_video.c
│ │ ├── android/
│ │ │ ├── SDL_androidclipboard.c
│ │ │ ├── SDL_androidclipboard.h
│ │ │ ├── SDL_androidevents.c
│ │ │ ├── SDL_androidevents.h
│ │ │ ├── SDL_androidgl.c
│ │ │ ├── SDL_androidkeyboard.c
│ │ │ ├── SDL_androidkeyboard.h
│ │ │ ├── SDL_androidmessagebox.c
│ │ │ ├── SDL_androidmessagebox.h
│ │ │ ├── SDL_androidmouse.c
│ │ │ ├── SDL_androidmouse.h
│ │ │ ├── SDL_androidtouch.c
│ │ │ ├── SDL_androidtouch.h
│ │ │ ├── SDL_androidvideo.c
│ │ │ ├── SDL_androidvideo.h
│ │ │ ├── SDL_androidwindow.c
│ │ │ └── SDL_androidwindow.h
│ │ └── sdlgenblit.pl
│ ├── SDL2_gfx/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_gfx.dir/
│ │ │ └── src/
│ │ │ ├── SDL2_framerate.c.o
│ │ │ ├── SDL2_gfxPrimitives.c.o
│ │ │ ├── SDL2_imageFilter.c.o
│ │ │ └── SDL2_rotozoom.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── SDL2_framerate.h
│ │ │ ├── SDL2_gfxPrimitives.h
│ │ │ ├── SDL2_gfxPrimitives_font.h
│ │ │ ├── SDL2_imageFilter.h
│ │ │ └── SDL2_rotozoom.h
│ │ └── src/
│ │ ├── SDL2_framerate.c
│ │ ├── SDL2_gfxPrimitives.c
│ │ ├── SDL2_imageFilter.c
│ │ └── SDL2_rotozoom.c
│ ├── SDL2_image/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_image.dir/
│ │ │ └── src/
│ │ │ ├── IMG.c.o
│ │ │ ├── IMG_bmp.c.o
│ │ │ ├── IMG_gif.c.o
│ │ │ ├── IMG_jpg.c.o
│ │ │ ├── IMG_lbm.c.o
│ │ │ ├── IMG_pcx.c.o
│ │ │ ├── IMG_png.c.o
│ │ │ ├── IMG_pnm.c.o
│ │ │ ├── IMG_tga.c.o
│ │ │ ├── IMG_tif.c.o
│ │ │ ├── IMG_webp.c.o
│ │ │ ├── IMG_xcf.c.o
│ │ │ ├── IMG_xpm.c.o
│ │ │ ├── IMG_xv.c.o
│ │ │ ├── IMG_xxx.c.o
│ │ │ └── showimage.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── SDL_image.h
│ │ │ └── miniz.h
│ │ └── src/
│ │ ├── IMG.c
│ │ ├── IMG_bmp.c
│ │ ├── IMG_gif.c
│ │ ├── IMG_jpg.c
│ │ ├── IMG_lbm.c
│ │ ├── IMG_pcx.c
│ │ ├── IMG_png.c
│ │ ├── IMG_pnm.c
│ │ ├── IMG_tga.c
│ │ ├── IMG_tif.c
│ │ ├── IMG_webp.c
│ │ ├── IMG_xcf.c
│ │ ├── IMG_xpm.c
│ │ ├── IMG_xv.c
│ │ ├── IMG_xxx.c
│ │ └── showimage.c
│ ├── SDL2_jpeg/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_jpeg.dir/
│ │ │ └── src/
│ │ │ ├── cdjpeg.c.o
│ │ │ ├── jaricom.c.o
│ │ │ ├── jcapimin.c.o
│ │ │ ├── jcapistd.c.o
│ │ │ ├── jcarith.c.o
│ │ │ ├── jccoefct.c.o
│ │ │ ├── jccolor.c.o
│ │ │ ├── jcdctmgr.c.o
│ │ │ ├── jchuff.c.o
│ │ │ ├── jcinit.c.o
│ │ │ ├── jcmainct.c.o
│ │ │ ├── jcmarker.c.o
│ │ │ ├── jcmaster.c.o
│ │ │ ├── jcomapi.c.o
│ │ │ ├── jcparam.c.o
│ │ │ ├── jcprepct.c.o
│ │ │ ├── jcsample.c.o
│ │ │ ├── jctrans.c.o
│ │ │ ├── jdapimin.c.o
│ │ │ ├── jdapistd.c.o
│ │ │ ├── jdarith.c.o
│ │ │ ├── jdatadst.c.o
│ │ │ ├── jdatasrc.c.o
│ │ │ ├── jdcoefct.c.o
│ │ │ ├── jdcolor.c.o
│ │ │ ├── jddctmgr.c.o
│ │ │ ├── jdhuff.c.o
│ │ │ ├── jdinput.c.o
│ │ │ ├── jdmainct.c.o
│ │ │ ├── jdmarker.c.o
│ │ │ ├── jdmaster.c.o
│ │ │ ├── jdmerge.c.o
│ │ │ ├── jdpostct.c.o
│ │ │ ├── jdsample.c.o
│ │ │ ├── jdtrans.c.o
│ │ │ ├── jerror.c.o
│ │ │ ├── jfdctflt.c.o
│ │ │ ├── jfdctfst.c.o
│ │ │ ├── jfdctint.c.o
│ │ │ ├── jidctflt.c.o
│ │ │ ├── jidctfst.c.o
│ │ │ ├── jidctint.c.o
│ │ │ ├── jmem-android.c.o
│ │ │ ├── jmemmgr.c.o
│ │ │ ├── jquant1.c.o
│ │ │ ├── jquant2.c.o
│ │ │ ├── jutils.c.o
│ │ │ ├── rdbmp.c.o
│ │ │ ├── rdcolmap.c.o
│ │ │ ├── rdgif.c.o
│ │ │ ├── rdppm.c.o
│ │ │ ├── rdrle.c.o
│ │ │ ├── rdswitch.c.o
│ │ │ ├── rdtarga.c.o
│ │ │ ├── transupp.c.o
│ │ │ ├── wrbmp.c.o
│ │ │ ├── wrgif.c.o
│ │ │ ├── wrjpgcom.c.o
│ │ │ ├── wrppm.c.o
│ │ │ ├── wrrle.c.o
│ │ │ └── wrtarga.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── cderror.h
│ │ │ ├── cdjpeg.h
│ │ │ ├── jconfig.h
│ │ │ ├── jdct.h
│ │ │ ├── jerror.h
│ │ │ ├── jinclude.h
│ │ │ ├── jmemsys.h
│ │ │ ├── jmorecfg.h
│ │ │ ├── jpegint.h
│ │ │ ├── jpeglib.h
│ │ │ ├── jversion.h
│ │ │ └── transupp.h
│ │ └── src/
│ │ ├── cdjpeg.c
│ │ ├── cjpeg.c
│ │ ├── ckconfig.c
│ │ ├── djpeg.c
│ │ ├── example.c
│ │ ├── jaricom.c
│ │ ├── jcapimin.c
│ │ ├── jcapistd.c
│ │ ├── jcarith.c
│ │ ├── jccoefct.c
│ │ ├── jccolor.c
│ │ ├── jcdctmgr.c
│ │ ├── jchuff.c
│ │ ├── jcinit.c
│ │ ├── jcmainct.c
│ │ ├── jcmarker.c
│ │ ├── jcmaster.c
│ │ ├── jcomapi.c
│ │ ├── jcparam.c
│ │ ├── jcprepct.c
│ │ ├── jcsample.c
│ │ ├── jctrans.c
│ │ ├── jdapimin.c
│ │ ├── jdapistd.c
│ │ ├── jdarith.c
│ │ ├── jdatadst.c
│ │ ├── jdatasrc.c
│ │ ├── jdcoefct.c
│ │ ├── jdcolor.c
│ │ ├── jddctmgr.c
│ │ ├── jdhuff.c
│ │ ├── jdinput.c
│ │ ├── jdmainct.c
│ │ ├── jdmarker.c
│ │ ├── jdmaster.c
│ │ ├── jdmerge.c
│ │ ├── jdpostct.c
│ │ ├── jdsample.c
│ │ ├── jdtrans.c
│ │ ├── jerror.c
│ │ ├── jfdctflt.c
│ │ ├── jfdctfst.c
│ │ ├── jfdctint.c
│ │ ├── jidctflt.c
│ │ ├── jidctfst.c
│ │ ├── jidctint.c
│ │ ├── jmem-android.c
│ │ ├── jmemansi.c
│ │ ├── jmemdos.c
│ │ ├── jmemmac.c
│ │ ├── jmemmgr.c
│ │ ├── jmemname.c
│ │ ├── jmemnobs.c
│ │ ├── jpegtran.c
│ │ ├── jquant1.c
│ │ ├── jquant2.c
│ │ ├── jutils.c
│ │ ├── rdbmp.c
│ │ ├── rdcolmap.c
│ │ ├── rdgif.c
│ │ ├── rdjpgcom.c
│ │ ├── rdppm.c
│ │ ├── rdrle.c
│ │ ├── rdswitch.c
│ │ ├── rdtarga.c
│ │ ├── transupp.c
│ │ ├── wrbmp.c
│ │ ├── wrgif.c
│ │ ├── wrjpgcom.c
│ │ ├── wrppm.c
│ │ ├── wrrle.c
│ │ └── wrtarga.c
│ ├── SDL2_mixer/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_mixer.dir/
│ │ │ └── src/
│ │ │ ├── dynamic_flac.c.o
│ │ │ ├── dynamic_fluidsynth.c.o
│ │ │ ├── dynamic_mod.c.o
│ │ │ ├── dynamic_modplug.c.o
│ │ │ ├── dynamic_mp3.c.o
│ │ │ ├── dynamic_ogg.c.o
│ │ │ ├── effect_position.c.o
│ │ │ ├── effect_stereoreverse.c.o
│ │ │ ├── effects_internal.c.o
│ │ │ ├── fluidsynth.c.o
│ │ │ ├── load_aiff.c.o
│ │ │ ├── load_flac.c.o
│ │ │ ├── load_mp3.c.o
│ │ │ ├── load_ogg.c.o
│ │ │ ├── load_voc.c.o
│ │ │ ├── mixer.c.o
│ │ │ ├── music.c.o
│ │ │ ├── music_cmd.c.o
│ │ │ ├── music_flac.c.o
│ │ │ ├── music_mad.c.o
│ │ │ ├── music_mod.c.o
│ │ │ ├── music_modplug.c.o
│ │ │ ├── music_ogg.c.o
│ │ │ ├── playmus.c.o
│ │ │ └── wavestream.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── SDL_mixer.h
│ │ │ ├── dynamic_flac.h
│ │ │ ├── dynamic_fluidsynth.h
│ │ │ ├── dynamic_mod.h
│ │ │ ├── dynamic_modplug.h
│ │ │ ├── dynamic_mp3.h
│ │ │ ├── dynamic_ogg.h
│ │ │ ├── effects_internal.h
│ │ │ ├── fluidsynth.h
│ │ │ ├── load_aiff.h
│ │ │ ├── load_flac.h
│ │ │ ├── load_mp3.h
│ │ │ ├── load_ogg.h
│ │ │ ├── load_voc.h
│ │ │ ├── music_cmd.h
│ │ │ ├── music_flac.h
│ │ │ ├── music_mad.h
│ │ │ ├── music_mod.h
│ │ │ ├── music_modplug.h
│ │ │ ├── music_ogg.h
│ │ │ └── wavestream.h
│ │ └── src/
│ │ ├── dynamic_flac.c
│ │ ├── dynamic_fluidsynth.c
│ │ ├── dynamic_mod.c
│ │ ├── dynamic_modplug.c
│ │ ├── dynamic_mp3.c
│ │ ├── dynamic_ogg.c
│ │ ├── effect_position.c
│ │ ├── effect_stereoreverse.c
│ │ ├── effects_internal.c
│ │ ├── fluidsynth.c
│ │ ├── load_aiff.c
│ │ ├── load_flac.c
│ │ ├── load_mp3.c
│ │ ├── load_ogg.c
│ │ ├── load_voc.c
│ │ ├── mixer.c
│ │ ├── music.c
│ │ ├── music_cmd.c
│ │ ├── music_flac.c
│ │ ├── music_mad.c
│ │ ├── music_mod.c
│ │ ├── music_modplug.c
│ │ ├── music_ogg.c
│ │ ├── playmus.c
│ │ ├── playwave.c
│ │ └── wavestream.c
│ ├── SDL2_png/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_png.dir/
│ │ │ └── src/
│ │ │ ├── png.c.o
│ │ │ ├── pngerror.c.o
│ │ │ ├── pngget.c.o
│ │ │ ├── pngmem.c.o
│ │ │ ├── pngpread.c.o
│ │ │ ├── pngread.c.o
│ │ │ ├── pngrio.c.o
│ │ │ ├── pngrtran.c.o
│ │ │ ├── pngrutil.c.o
│ │ │ ├── pngset.c.o
│ │ │ ├── pngtrans.c.o
│ │ │ ├── pngwio.c.o
│ │ │ ├── pngwrite.c.o
│ │ │ ├── pngwtran.c.o
│ │ │ └── pngwutil.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ ├── config.h
│ │ │ ├── png.h
│ │ │ ├── pngconf.h
│ │ │ ├── pngdebug.h
│ │ │ ├── pnginfo.h
│ │ │ ├── pnglibconf.h
│ │ │ ├── pngprefix.h
│ │ │ ├── pngpriv.h
│ │ │ └── pngstruct.h
│ │ └── src/
│ │ ├── png.c
│ │ ├── pngerror.c
│ │ ├── pngget.c
│ │ ├── pngmem.c
│ │ ├── pngpread.c
│ │ ├── pngread.c
│ │ ├── pngrio.c
│ │ ├── pngrtran.c
│ │ ├── pngrutil.c
│ │ ├── pngset.c
│ │ ├── pngtest.c
│ │ ├── pngtrans.c
│ │ ├── pngwio.c
│ │ ├── pngwrite.c
│ │ ├── pngwtran.c
│ │ └── pngwutil.c
│ ├── SDL2_ttf/
│ │ ├── CMakeFiles/
│ │ │ └── SDL2_ttf.dir/
│ │ │ └── src/
│ │ │ ├── SDL_ttf.c.o
│ │ │ └── glfont.c.o
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── cmake_install.cmake
│ │ ├── include/
│ │ │ └── SDL_ttf.h
│ │ └── src/
│ │ ├── SDL_ttf.c
│ │ ├── glfont.c
│ │ └── showfont.c
│ └── freetype/
│ ├── CMakeFiles/
│ │ └── freetype.dir/
│ │ └── src/
│ │ ├── base/
│ │ │ ├── ftapi.c.o
│ │ │ ├── ftbase.c.o
│ │ │ ├── ftbbox.c.o
│ │ │ ├── ftbdf.c.o
│ │ │ ├── ftbitmap.c.o
│ │ │ ├── ftcid.c.o
│ │ │ ├── ftdebug.c.o
│ │ │ ├── ftfstype.c.o
│ │ │ ├── ftgasp.c.o
│ │ │ ├── ftglyph.c.o
│ │ │ ├── ftgxval.c.o
│ │ │ ├── ftinit.c.o
│ │ │ ├── ftlcdfil.c.o
│ │ │ ├── ftmm.c.o
│ │ │ ├── ftotval.c.o
│ │ │ ├── ftpatent.c.o
│ │ │ ├── ftpfr.c.o
│ │ │ ├── ftstroke.c.o
│ │ │ ├── ftsynth.c.o
│ │ │ ├── ftsystem.c.o
│ │ │ ├── fttype1.c.o
│ │ │ ├── ftwinfnt.c.o
│ │ │ ├── ftxf86.c.o
│ │ │ └── md5.c.o
│ │ ├── bzip2/
│ │ │ └── ftbzip2.c.o
│ │ ├── raster/
│ │ │ ├── ftraster.c.o
│ │ │ ├── ftrend1.c.o
│ │ │ └── rastpic.c.o
│ │ ├── sfnt/
│ │ │ ├── sfdriver.c.o
│ │ │ ├── sfntpic.c.o
│ │ │ ├── sfobjs.c.o
│ │ │ ├── ttbdf.c.o
│ │ │ ├── ttcmap.c.o
│ │ │ ├── ttkern.c.o
│ │ │ ├── ttload.c.o
│ │ │ ├── ttmtx.c.o
│ │ │ ├── ttpost.c.o
│ │ │ └── ttsbit.c.o
│ │ ├── smooth/
│ │ │ ├── ftgrays.c.o
│ │ │ ├── ftsmooth.c.o
│ │ │ └── ftspic.c.o
│ │ └── truetype/
│ │ ├── ttdriver.c.o
│ │ ├── ttgload.c.o
│ │ ├── ttgxvar.c.o
│ │ ├── ttinterp.c.o
│ │ ├── ttobjs.c.o
│ │ ├── ttpic.c.o
│ │ ├── ttpload.c.o
│ │ └── ttsubpix.c.o
│ ├── CMakeLists.txt
│ ├── build.gradle
│ ├── cmake_install.cmake
│ ├── include/
│ │ ├── freetype/
│ │ │ ├── config/
│ │ │ │ ├── ftconfig.h
│ │ │ │ ├── ftheader.h
│ │ │ │ ├── ftmodule.h
│ │ │ │ ├── ftoption.h
│ │ │ │ └── ftstdlib.h
│ │ │ ├── freetype.h
│ │ │ ├── ftadvanc.h
│ │ │ ├── ftautoh.h
│ │ │ ├── ftbbox.h
│ │ │ ├── ftbdf.h
│ │ │ ├── ftbitmap.h
│ │ │ ├── ftbzip2.h
│ │ │ ├── ftcache.h
│ │ │ ├── ftcffdrv.h
│ │ │ ├── ftchapters.h
│ │ │ ├── ftcid.h
│ │ │ ├── fterrdef.h
│ │ │ ├── fterrors.h
│ │ │ ├── ftgasp.h
│ │ │ ├── ftglyph.h
│ │ │ ├── ftgxval.h
│ │ │ ├── ftgzip.h
│ │ │ ├── ftimage.h
│ │ │ ├── ftincrem.h
│ │ │ ├── ftlcdfil.h
│ │ │ ├── ftlist.h
│ │ │ ├── ftlzw.h
│ │ │ ├── ftmac.h
│ │ │ ├── ftmm.h
│ │ │ ├── ftmodapi.h
│ │ │ ├── ftmoderr.h
│ │ │ ├── ftotval.h
│ │ │ ├── ftoutln.h
│ │ │ ├── ftpfr.h
│ │ │ ├── ftrender.h
│ │ │ ├── ftsizes.h
│ │ │ ├── ftsnames.h
│ │ │ ├── ftstroke.h
│ │ │ ├── ftsynth.h
│ │ │ ├── ftsystem.h
│ │ │ ├── fttrigon.h
│ │ │ ├── fttypes.h
│ │ │ ├── ftwinfnt.h
│ │ │ ├── ftxf86.h
│ │ │ ├── internal/
│ │ │ │ ├── autohint.h
│ │ │ │ ├── ftcalc.h
│ │ │ │ ├── ftdebug.h
│ │ │ │ ├── ftdriver.h
│ │ │ │ ├── ftgloadr.h
│ │ │ │ ├── ftmemory.h
│ │ │ │ ├── ftobjs.h
│ │ │ │ ├── ftpic.h
│ │ │ │ ├── ftrfork.h
│ │ │ │ ├── ftserv.h
│ │ │ │ ├── ftstream.h
│ │ │ │ ├── fttrace.h
│ │ │ │ ├── ftvalid.h
│ │ │ │ ├── internal.h
│ │ │ │ ├── psaux.h
│ │ │ │ ├── pshints.h
│ │ │ │ ├── services/
│ │ │ │ │ ├── svbdf.h
│ │ │ │ │ ├── svcid.h
│ │ │ │ │ ├── svgldict.h
│ │ │ │ │ ├── svgxval.h
│ │ │ │ │ ├── svkern.h
│ │ │ │ │ ├── svmm.h
│ │ │ │ │ ├── svotval.h
│ │ │ │ │ ├── svpfr.h
│ │ │ │ │ ├── svpostnm.h
│ │ │ │ │ ├── svprop.h
│ │ │ │ │ ├── svpscmap.h
│ │ │ │ │ ├── svpsinfo.h
│ │ │ │ │ ├── svsfnt.h
│ │ │ │ │ ├── svttcmap.h
│ │ │ │ │ ├── svtteng.h
│ │ │ │ │ ├── svttglyf.h
│ │ │ │ │ ├── svwinfnt.h
│ │ │ │ │ └── svxf86nm.h
│ │ │ │ ├── sfnt.h
│ │ │ │ ├── t1types.h
│ │ │ │ └── tttypes.h
│ │ │ ├── t1tables.h
│ │ │ ├── ttnameid.h
│ │ │ ├── tttables.h
│ │ │ ├── tttags.h
│ │ │ └── ttunpat.h
│ │ ├── ft2build.h
│ │ ├── ftconfig.h
│ │ └── ftmodule.h
│ └── src/
│ ├── Jamfile
│ ├── autofit/
│ │ ├── Jamfile
│ │ ├── afangles.c
│ │ ├── afangles.h
│ │ ├── afcjk.c
│ │ ├── afcjk.h
│ │ ├── afdummy.c
│ │ ├── afdummy.h
│ │ ├── aferrors.h
│ │ ├── afglobal.c
│ │ ├── afglobal.h
│ │ ├── afhints.c
│ │ ├── afhints.h
│ │ ├── afindic.c
│ │ ├── afindic.h
│ │ ├── aflatin.c
│ │ ├── aflatin.h
│ │ ├── aflatin2.c
│ │ ├── aflatin2.h
│ │ ├── afloader.c
│ │ ├── afloader.h
│ │ ├── afmodule.c
│ │ ├── afmodule.h
│ │ ├── afpic.c
│ │ ├── afpic.h
│ │ ├── aftypes.h
│ │ ├── afwarp.c
│ │ ├── afwarp.h
│ │ ├── autofit.c
│ │ ├── module.mk
│ │ └── rules.mk
│ ├── base/
│ │ ├── Jamfile
│ │ ├── basepic.c
│ │ ├── basepic.h
│ │ ├── ftadvanc.c
│ │ ├── ftapi.c
│ │ ├── ftbase.c
│ │ ├── ftbase.h
│ │ ├── ftbbox.c
│ │ ├── ftbdf.c
│ │ ├── ftbitmap.c
│ │ ├── ftcalc.c
│ │ ├── ftcid.c
│ │ ├── ftdbgmem.c
│ │ ├── ftdebug.c
│ │ ├── ftfstype.c
│ │ ├── ftgasp.c
│ │ ├── ftgloadr.c
│ │ ├── ftglyph.c
│ │ ├── ftgxval.c
│ │ ├── ftinit.c
│ │ ├── ftlcdfil.c
│ │ ├── ftmac.c
│ │ ├── ftmm.c
│ │ ├── ftobjs.c
│ │ ├── ftotval.c
│ │ ├── ftoutln.c
│ │ ├── ftpatent.c
│ │ ├── ftpfr.c
│ │ ├── ftpic.c
│ │ ├── ftrfork.c
│ │ ├── ftsnames.c
│ │ ├── ftstream.c
│ │ ├── ftstroke.c
│ │ ├── ftsynth.c
│ │ ├── ftsystem.c
│ │ ├── fttrigon.c
│ │ ├── fttype1.c
│ │ ├── ftutil.c
│ │ ├── ftwinfnt.c
│ │ ├── ftxf86.c
│ │ ├── md5.c
│ │ ├── md5.h
│ │ └── rules.mk
│ ├── bdf/
│ │ ├── Jamfile
│ │ ├── README
│ │ ├── bdf.c
│ │ ├── bdf.h
│ │ ├── bdfdrivr.c
│ │ ├── bdfdrivr.h
│ │ ├── bdferror.h
│ │ ├── bdflib.c
│ │ ├── module.mk
│ │ └── rules.mk
│ ├── bzip2/
│ │ ├── Jamfile
│ │ ├── ftbzip2.c
│ │ └── rules.mk
│ ├── cache/
│ │ ├── Jamfile
│ │ ├── ftcache.c
│ │ ├── ftcbasic.c
│ │ ├── ftccache.c
│ │ ├── ftccache.h
│ │ ├── ftccback.h
│ │ ├── ftccmap.c
│ │ ├── ftcerror.h
│ │ ├── ftcglyph.c
│ │ ├── ftcglyph.h
│ │ ├── ftcimage.c
│ │ ├── ftcimage.h
│ │ ├── ftcmanag.c
│ │ ├── ftcmanag.h
│ │ ├── ftcmru.c
│ │ ├── ftcmru.h
│ │ ├── ftcsbits.c
│ │ ├── ftcsbits.h
│ │ └── rules.mk
│ ├── cff/
│ │ ├── Jamfile
│ │ ├── cf2arrst.c
│ │ ├── cf2arrst.h
│ │ ├── cf2blues.c
│ │ ├── cf2blues.h
│ │ ├── cf2error.c
│ │ ├── cf2error.h
│ │ ├── cf2fixed.h
│ │ ├── cf2font.c
│ │ ├── cf2font.h
│ │ ├── cf2ft.c
│ │ ├── cf2ft.h
│ │ ├── cf2glue.h
│ │ ├── cf2hints.c
│ │ ├── cf2hints.h
│ │ ├── cf2intrp.c
│ │ ├── cf2intrp.h
│ │ ├── cf2read.c
│ │ ├── cf2read.h
│ │ ├── cf2stack.c
│ │ ├── cf2stack.h
│ │ ├── cf2types.h
│ │ ├── cff.c
│ │ ├── cffcmap.c
│ │ ├── cffcmap.h
│ │ ├── cffdrivr.c
│ │ ├── cffdrivr.h
│ │ ├── cfferrs.h
│ │ ├── cffgload.c
│ │ ├── cffgload.h
│ │ ├── cffload.c
│ │ ├── cffload.h
│ │ ├── cffobjs.c
│ │ ├── cffobjs.h
│ │ ├── cffparse.c
│ │ ├── cffparse.h
│ │ ├── cffpic.c
│ │ ├── cffpic.h
│ │ ├── cfftoken.h
│ │ ├── cfftypes.h
│ │ ├── module.mk
│ │ └── rules.mk
│ ├── cid/
│ │ ├── Jamfile
│ │ ├── ciderrs.h
│ │ ├── cidgload.c
│ │ ├── cidgload.h
│ │ ├── cidload.c
│ │ ├── cidload.h
│ │ ├── cidobjs.c
│ │ ├── cidobjs.h
│ │ ├── cidparse.c
│ │ ├── cidparse.h
│ │ ├── cidriver.c
│ │ ├── cidriver.h
│ │ ├── cidtoken.h
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ └── type1cid.c
│ ├── gxvalid/
│ │ ├── Jamfile
│ │ ├── README
│ │ ├── gxvalid.c
│ │ ├── gxvalid.h
│ │ ├── gxvbsln.c
│ │ ├── gxvcommn.c
│ │ ├── gxvcommn.h
│ │ ├── gxverror.h
│ │ ├── gxvfeat.c
│ │ ├── gxvfeat.h
│ │ ├── gxvfgen.c
│ │ ├── gxvjust.c
│ │ ├── gxvkern.c
│ │ ├── gxvlcar.c
│ │ ├── gxvmod.c
│ │ ├── gxvmod.h
│ │ ├── gxvmort.c
│ │ ├── gxvmort.h
│ │ ├── gxvmort0.c
│ │ ├── gxvmort1.c
│ │ ├── gxvmort2.c
│ │ ├── gxvmort4.c
│ │ ├── gxvmort5.c
│ │ ├── gxvmorx.c
│ │ ├── gxvmorx.h
│ │ ├── gxvmorx0.c
│ │ ├── gxvmorx1.c
│ │ ├── gxvmorx2.c
│ │ ├── gxvmorx4.c
│ │ ├── gxvmorx5.c
│ │ ├── gxvopbd.c
│ │ ├── gxvprop.c
│ │ ├── gxvtrak.c
│ │ ├── module.mk
│ │ └── rules.mk
│ ├── gzip/
│ │ ├── Jamfile
│ │ ├── adler32.c
│ │ ├── ftgzip.c
│ │ ├── infblock.c
│ │ ├── infblock.h
│ │ ├── infcodes.c
│ │ ├── infcodes.h
│ │ ├── inffixed.h
│ │ ├── inflate.c
│ │ ├── inftrees.c
│ │ ├── inftrees.h
│ │ ├── infutil.c
│ │ ├── infutil.h
│ │ ├── rules.mk
│ │ ├── zconf.h
│ │ ├── zlib.h
│ │ ├── zutil.c
│ │ └── zutil.h
│ ├── lzw/
│ │ ├── Jamfile
│ │ ├── ftlzw.c
│ │ ├── ftzopen.c
│ │ ├── ftzopen.h
│ │ └── rules.mk
│ ├── otvalid/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── otvalid.c
│ │ ├── otvalid.h
│ │ ├── otvbase.c
│ │ ├── otvcommn.c
│ │ ├── otvcommn.h
│ │ ├── otverror.h
│ │ ├── otvgdef.c
│ │ ├── otvgpos.c
│ │ ├── otvgpos.h
│ │ ├── otvgsub.c
│ │ ├── otvjstf.c
│ │ ├── otvmath.c
│ │ ├── otvmod.c
│ │ ├── otvmod.h
│ │ └── rules.mk
│ ├── pcf/
│ │ ├── Jamfile
│ │ ├── README
│ │ ├── module.mk
│ │ ├── pcf.c
│ │ ├── pcf.h
│ │ ├── pcfdrivr.c
│ │ ├── pcfdrivr.h
│ │ ├── pcferror.h
│ │ ├── pcfread.c
│ │ ├── pcfread.h
│ │ ├── pcfutil.c
│ │ ├── pcfutil.h
│ │ └── rules.mk
│ ├── pfr/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── pfr.c
│ │ ├── pfrcmap.c
│ │ ├── pfrcmap.h
│ │ ├── pfrdrivr.c
│ │ ├── pfrdrivr.h
│ │ ├── pfrerror.h
│ │ ├── pfrgload.c
│ │ ├── pfrgload.h
│ │ ├── pfrload.c
│ │ ├── pfrload.h
│ │ ├── pfrobjs.c
│ │ ├── pfrobjs.h
│ │ ├── pfrsbit.c
│ │ ├── pfrsbit.h
│ │ ├── pfrtypes.h
│ │ └── rules.mk
│ ├── psaux/
│ │ ├── Jamfile
│ │ ├── afmparse.c
│ │ ├── afmparse.h
│ │ ├── module.mk
│ │ ├── psaux.c
│ │ ├── psauxerr.h
│ │ ├── psauxmod.c
│ │ ├── psauxmod.h
│ │ ├── psconv.c
│ │ ├── psconv.h
│ │ ├── psobjs.c
│ │ ├── psobjs.h
│ │ ├── rules.mk
│ │ ├── t1cmap.c
│ │ ├── t1cmap.h
│ │ ├── t1decode.c
│ │ └── t1decode.h
│ ├── pshinter/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── pshalgo.c
│ │ ├── pshalgo.h
│ │ ├── pshglob.c
│ │ ├── pshglob.h
│ │ ├── pshinter.c
│ │ ├── pshmod.c
│ │ ├── pshmod.h
│ │ ├── pshnterr.h
│ │ ├── pshpic.c
│ │ ├── pshpic.h
│ │ ├── pshrec.c
│ │ ├── pshrec.h
│ │ └── rules.mk
│ ├── psnames/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── psmodule.c
│ │ ├── psmodule.h
│ │ ├── psnamerr.h
│ │ ├── psnames.c
│ │ ├── pspic.c
│ │ ├── pspic.h
│ │ ├── pstables.h
│ │ └── rules.mk
│ ├── raster/
│ │ ├── Jamfile
│ │ ├── ftmisc.h
│ │ ├── ftraster.c
│ │ ├── ftraster.h
│ │ ├── ftrend1.c
│ │ ├── ftrend1.h
│ │ ├── module.mk
│ │ ├── raster.c
│ │ ├── rasterrs.h
│ │ ├── rastpic.c
│ │ ├── rastpic.h
│ │ └── rules.mk
│ ├── sfnt/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ ├── sfdriver.c
│ │ ├── sfdriver.h
│ │ ├── sferrors.h
│ │ ├── sfnt.c
│ │ ├── sfntpic.c
│ │ ├── sfntpic.h
│ │ ├── sfobjs.c
│ │ ├── sfobjs.h
│ │ ├── ttbdf.c
│ │ ├── ttbdf.h
│ │ ├── ttcmap.c
│ │ ├── ttcmap.h
│ │ ├── ttcmapc.h
│ │ ├── ttkern.c
│ │ ├── ttkern.h
│ │ ├── ttload.c
│ │ ├── ttload.h
│ │ ├── ttmtx.c
│ │ ├── ttmtx.h
│ │ ├── ttpost.c
│ │ ├── ttpost.h
│ │ ├── ttsbit.c
│ │ ├── ttsbit.h
│ │ └── ttsbit0.c
│ ├── smooth/
│ │ ├── Jamfile
│ │ ├── ftgrays.c
│ │ ├── ftgrays.h
│ │ ├── ftsmerrs.h
│ │ ├── ftsmooth.c
│ │ ├── ftsmooth.h
│ │ ├── ftspic.c
│ │ ├── ftspic.h
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ └── smooth.c
│ ├── tools/
│ │ ├── Jamfile
│ │ ├── apinames.c
│ │ ├── chktrcmp.py
│ │ ├── cordic.py
│ │ ├── docmaker/
│ │ │ ├── content.py
│ │ │ ├── docbeauty.py
│ │ │ ├── docmaker.py
│ │ │ ├── formatter.py
│ │ │ ├── sources.py
│ │ │ ├── tohtml.py
│ │ │ └── utils.py
│ │ ├── ftrandom/
│ │ │ ├── Makefile
│ │ │ ├── README
│ │ │ └── ftrandom.c
│ │ ├── glnames.py
│ │ ├── test_afm.c
│ │ ├── test_bbox.c
│ │ └── test_trig.c
│ ├── truetype/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ ├── truetype.c
│ │ ├── ttdriver.c
│ │ ├── ttdriver.h
│ │ ├── tterrors.h
│ │ ├── ttgload.c
│ │ ├── ttgload.h
│ │ ├── ttgxvar.c
│ │ ├── ttgxvar.h
│ │ ├── ttinterp.c
│ │ ├── ttinterp.h
│ │ ├── ttobjs.c
│ │ ├── ttobjs.h
│ │ ├── ttpic.c
│ │ ├── ttpic.h
│ │ ├── ttpload.c
│ │ ├── ttpload.h
│ │ ├── ttsubpix.c
│ │ └── ttsubpix.h
│ ├── type1/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ ├── t1afm.c
│ │ ├── t1afm.h
│ │ ├── t1driver.c
│ │ ├── t1driver.h
│ │ ├── t1errors.h
│ │ ├── t1gload.c
│ │ ├── t1gload.h
│ │ ├── t1load.c
│ │ ├── t1load.h
│ │ ├── t1objs.c
│ │ ├── t1objs.h
│ │ ├── t1parse.c
│ │ ├── t1parse.h
│ │ ├── t1tokens.h
│ │ └── type1.c
│ ├── type42/
│ │ ├── Jamfile
│ │ ├── module.mk
│ │ ├── rules.mk
│ │ ├── t42drivr.c
│ │ ├── t42drivr.h
│ │ ├── t42error.h
│ │ ├── t42objs.c
│ │ ├── t42objs.h
│ │ ├── t42parse.c
│ │ ├── t42parse.h
│ │ ├── t42types.h
│ │ └── type42.c
│ └── winfonts/
│ ├── Jamfile
│ ├── fnterrs.h
│ ├── module.mk
│ ├── rules.mk
│ ├── winfnt.c
│ └── winfnt.h
├── local.properties
├── open_codeblocks.bat
├── open_codeblocks_sdl.bat
├── open_qt_creator.bat
├── open_vscode.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gradle/5.1.1/gc.properties
================================================
================================================
FILE: .gradle/buildOutputCleanup/cache.properties
================================================
#Tue Mar 02 01:28:27 UTC 2021
gradle.version=5.1.1
================================================
FILE: .gradle/vcs-1/gc.properties
================================================
================================================
FILE: .idea/.gitignore
================================================
# Default ignored files
/shelf/
/workspace.xml
================================================
FILE: .idea/codeStyles/Project.xml
================================================
.*:id
http://schemas.android.com/apk/res/android
.*:name
http://schemas.android.com/apk/res/android
.*
http://schemas.android.com/apk/res/android
ANDROID_ATTRIBUTE_ORDER
================================================
FILE: .idea/compiler.xml
================================================
================================================
FILE: .idea/encodings.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/is-Engine.iml
================================================
================================================
FILE: .idea/jarRepositories.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/modules/app/is-Engine.app.iml
================================================
generateDebugSources
================================================
FILE: .idea/modules/is-Engine.iml
================================================
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required (VERSION 3.1)
project(isengine)
set(ISENGINE_PC true) # This confirms that we are using is::Engine to develop on PC (Windows / Linux)
set(ISENGINE_MAIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app/src/main")
set(ISENGINE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app/src/main/cpp")
set(ISENGINE_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app/src/main/cmake")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
# SFML on Windows OS
if (WIN32)
set (SFML_DIR "C:/SFML/lib/cmake/SFML")
set(SFML_STATIC_LIBRARIES TRUE)
# OpenAL lib
file(COPY "C:/SFML/bin/openal32.dll" DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
endif()
# Find SFML
find_package(SFML REQUIRED COMPONENTS system window graphics network audio)
include(${ISENGINE_CMAKE_DIR}/isengine.cmake)
include(${ISENGINE_CMAKE_DIR}/app_src.cmake)
# game resources files (image, sound, music, ...)
file(COPY ${ISENGINE_MAIN_DIR}/assets DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
add_executable(isengine
${isengine}
${app_src}
${ISENGINE_CMAKE_DIR}/resource.rc # application icon
)
target_include_directories(isengine PRIVATE include)
target_link_libraries(isengine sfml-system sfml-window sfml-graphics sfml-network sfml-audio)
================================================
FILE: LICENSE.md
================================================
# zlib license
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
================================================
FILE: README.md
================================================

----------------------------
# is::Engine (Infinity Solutions::Engine) 4.0.1
Open source C++ framework which uses the mechanisms of **SFML 2** and which also allows to develop with several libraries at the same time **(SDL 2, Emscripten)** in order to easily export your games / applications on the **Nintendo Switch, Web (HTML 5), Mobile** and **PC (Windows, Linux, macOS)**.
## Contents
- [Features](#features)
- [What's new in this version](#whats-new-in-this-version)
- [Extras](#extras)
- [Game Engine User Guide and Youtube Tutorial](#game-engine-user-guide-and-youtube-tutorial)
- [Example of a project created with the engine](#example-of-a-project-created-with-the-engine)
- [Hello Scene Example](#hello-scene-example)
- [Prerequisites](#prerequisites)
- [How to use is::Engine with the different development tools](#how-to-use-isengine-with-the-different-development-tools)
- [Description of the project structure](#description-of-the-project-structure)
- [How to update an is::Engine project](#how-to-update-an-isengine-project)
- [Special things to know about the engine](#special-things-to-know-about-the-engine)
- [How to activate the use of Admob](#how-to-activate-the-use-of-admob)
- [Contribute](#contribute)
##
[](https://www.sfml-dev.org) [](https://www.libsdl.org/)  [](https://github.com/erincatto/box2d) [](https://www.mapeditor.org) [](https://admob.google.com/) [](https://github.com/native-toolkit/tinyfiledialogs) [](https://visualstudio.microsoft.com/fr/vs/community/)
## Features
- Run SFML game / application on SDL 2 (Like an Emulator)
- Language manager (English and French language support by default)
- Scene System
- Automatic management of a window
- Multi support for development tools ([Nintendo-Switch](#-nintendo-switch),
[Android Studio](#-android-studio),
[Qt](#-qt),
[CMake](#-cmake),
[Emscripten](#-web-html-5---css-3),
[Visual Studio Code](#-visual-studio-code),
[Code::Block](#-codeblocks),
[Visual Studio](#-visual-studio)
- [is::LibConnect](#islibconnect)
- [Web Push Notification](#-web-push-notification)
- SDM (Step and Draw Manager)
- GSM (Game Sound Manager)
- GRM (Graphics Resources Manager)
- CFF (CMake Files Fusion)
- [TMX Lite](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-TMXLite)
- [TMX Loader (Old version)](https://github.com/Is-Daouda/is-Engine-TMXLoader)
- Entity system
- Object Event System
- [Button System](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-TinyFileDialog)
- Background System
- [Game Slider](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-GameSlider)
- [Sprite Animation](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-GameSlider)
- Basic collision engine
- [2D physic engine (Box 2D)](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-Box2D)
- Message Box System (Modifiable appearance via Sprites and Font)
- Dialog Box System (as for RPG games)
- [[Windows, Linux] Tiny File Dialogs to manage the dialog boxes of type: Message, File Save, Load File, Folder Selection](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-TinyFileDialog)
- [Game Configuration System (sound, music, language, keyboard key, file path, ...)](./app/src/main/cpp/app_src/config/GameConfig.h)
- Game Save System
- [[Android] Virtual Game Pad with 6 keys (multi directional cross and A - B button)](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-VirtualGamePad)
- [[Android] Virtual Game Pad Configuration (Adjust Position, transparency, ...)](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-VirtualGamePad)
- [[Android] Show Ad Banner](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-Admob)
- [[Android] Show Reward Video](https://github.com/Is-Daouda/is-Engine-Example-Pack/tree/main/is-Engine-Admob)
## What's new in this version
- [Using Visual Studio and SDL 2 to develop with SFML.](#-visual-studio-sdl-2)
- Bug Fixes
### 4.0.1
- Nintendo Switch Support
- The **[Demo](https://github.com/Is-Daouda/is-Engine-Demo)** and **[tutorials](https://github.com/Is-Daouda/is-Engine-Tutorial)** are compatible with the Nintendo Switch.
- Visual Studio 2022 can be used with all projects.
- Vertex Arrays support (Simulation with SDL 2).
When you want to use a texture with vertices, you must set the optional parameter **useWithVertices** to **true** in the **loadFromFile()** function, which is necessary when using SFML with SDL2.
```cpp
sf::Texture texture;
texture.loadFromFile("image.png", true);
```
## Extras
- Here is a **Web Game : Arkanoid** created thanks to the **[game engine tutorial](https://youtu.be/wo2-ofNB7Hw)**.
**It's a Web Game so it's playable on PC and mobile.**
[](https://is-daouda.github.io/)
- The engine comes with a **[Demo (2D Platform Game)](https://github.com/Is-Daouda/is-Engine-Demo)** that uses only the functions of the engine, in order to show you its power and how to use it. Now imagine what you can do when you use Box 2D and the other tools!
[](https://github.com/Is-Daouda/is-Engine-Demo)
- [Example Pack](https://github.com/Is-Daouda/is-Engine-Example-Pack) that show how to use the various features of the game engine.
## Game Engine User Guide and Youtube Tutorial
- [English version](./doc/isEngine_api_doc_eng.html)
- [French version](./doc/isEngine_api_doc_fr.html)
- [Youtube tutorial : How to import an SFML project into is::Engine](https://youtu.be/x_YQLHoPMbc)
- [Youtube tutorial : How to create a game (Arkanoid) with the game engine](https://youtu.be/wo2-ofNB7Hw)
## Example of a project created with the engine
- [I Can Transform](https://www.gamepix.com/play/i-can-transform)
- [GravytX The Gravytoid](https://www.gamepix.com/play/Gravytx-the-gravytoid)
## Hello Scene Example
Here is an example code of a Scene (the place where the game objects come to life).
**In less than 50 lines of code, the engine allows to:**
- Change the language of the game (English / French)
- Display an RPG type message with interaction
- Animate an **[object](./app/src/main/cpp/app_src/objects/HelloWorld.h)** with the possibility of interacting with it (by clicking / touching it)
- Load resources (Textures, Music)
- Play music
- Display a background that scrolls vertically and horizontally with a speed
- Manages the display depth of each object
- Automatically manages the game window (closing confirmation, events, ...)
- Change the background color of the window (scene color)
```cpp
class HelloScene : public is::GameDisplay {
public:
HelloScene(is::GameSystemExtended &gameSysExt):
GameDisplay(gameSysExt, sf::Color::White /* => scene color*/) {}
void loadResources() {
m_gameSysExt.m_gameLanguage = is::lang::ENGLISH; // set default game language
// uncomment to change English language in French
// m_gameSysExt.m_gameLanguage = is::lang::FRANCAIS;
// load font and texture
GameDisplay::loadParentResources(); // allows to load system resource (very important never forgot to call him)
GRMaddTexture("hello_world", is::GameConfig::SPRITES_DIR + "hello_world.png");
auto &texBg = GRMaddTexture("background", is::GameConfig::TILES_DIR + "background.png");
auto &texDialog = GRMaddTexture("dialog_box", is::GameConfig::GUI_DIR + "dialog_box.png");
// add a background to the position x = 0, y = 0 which will fill the scene and which will be scrolled (scrolling speed = 0.5)
SDMaddSceneObject(std::make_shared(texBg, 0.f, 0.f, this, 0.5f, -0.5f, false, false));
// add an object at position x = 0, y = 0 which will be updated and displayed in the scene
SDMaddSceneObject(std::make_shared(0.f, 0.f, this));
// add RPG style game dialog
auto gameDialog = std::make_shared(texDialog, GRMgetFont("font_msg"), this);
gameDialog->setDepth(-2); // the display depth (make it appear on all objects. The object with the smallest value appears on the others)
gameDialog->setDialog(is::GameDialog::DialogIndex::DIALOG_HELLO); // set the corresponding dialog (See GameDialog.h and GameLanguage.h for more details on creating a message for dialogue)
SDMaddSceneObject(gameDialog);
GSMaddSound("game_music", is::GameConfig::MUSIC_DIR + "game_music.wav"); // add music
GSMplaySound("game_music"); // play music
}
};
```
## Prerequisites
- [SFML Library (2.4 +)](https://www.sfml-dev.org/download.php)
- [SDL 2 (2.0.12 +)]()
- GCC Compiler (7.3 +)
---
## How to use is::Engine with the different development tools:
##  Nintendo Switch
This project uses the template of **[carstene1ns](https://github.com/carstene1ns/switch-sdl2-demo)**.
**1. Prerequisites**
- DevkitPro with MSYS2
##  Very important
- Not affiliated with Nintendo.
- All your source files (only .cpp or .c) must be located in the root of the **[cpp](./app/src/main/cpp/)** folder otherwise the compiler will not find them!
- The Switch uses the same touch functions as Android.
- The engine has been configured so that you can use the PC functions **keyIsPressed(is::GameConfig::KEY_UP)** or **keyIsPressed(is::GameConfig::KEY_A), etc.** on the Switch.
- Some SFML functions like: **Render Texture** are not yet supported. These additions will be made soon!
**2. Installation**
##### Windows
1. Download [devkitPro](https://github.com/devkitPro/installer/releases/download/v3.0.3/devkitProUpdater-3.0.3.exe) and install it in **C:/devkitPro/**.
2. During installation:
- Check "devkitA64" (for Switch)
- Check "MSYS2 Base System"
- Check "portlibs" if available
3. Once installed, open the MSYS2 terminal (C:\devkitPro\msys2\msys2.exe)
4. Enter these commands in the console to download libraries:
```bash
pacman -Syu
pacman -S switch-sdl2 switch-sdl2_image switch-sdl2_mixer switch-sdl2_net switch-sdl2_ttf
```
6. Move the **is-Engine** project to your **C:/ (C:/is-Engine)**.
7. Run the file **[copy_assets.cmd](./app/src/main/copy_assets.cmd)** so that it transfers your resources which are in the **[assets](./app/src/main/assets) folder** to romfs (this folder will be created when executing the copy_assets.cmd file) necessary for the compilation.
8. Enter these commands in the console:
```bash
cd c:/is-Engine/app/src/main/
make
```
If all goes well you will have a **main.nro file** in the [main](./app/src/main/) folder that you can launch via Nintendo Switch emulators (Yuzu, Ryujinx, ...).

**Enjoy!**
---
##  Android Studio
This project uses the template of **[Georgik](https://github.com/georgik/sdl2-android-example)** and **[Lauchmelder23](https://github.com/Lauchmelder23/SDLU)**.
**1. Prerequisites**
- Android Studio (4.0.1 +)
- Android SDK and NDK (r20b)
##  Very important
- On Android SFML games run with SDL library. If you want to use SDL functions in your source code, use the **IS_ENGINE_SDL_2 macro**.
- The audio format supported at the moment is **.WAV**
- Some SFML functions like: **Render Texture** are not yet supported. These additions will be made soon!
- **Your help to improve the engine will be welcome!**
- [Please read this](#Contribute).
**2. Installation**
##### Windows
1. Download [Android Studio 3.x](https://developer.android.com/studio) (recommended version 4.0.1).
2. Download the [Android SDK](https://developer.android.com/studio) and install it in **C:/Android/SDK**.
3. Download [Android NDK android-ndk-r20b-windows-x86_64](https://developer.android.com/ndk/downloads/older_releases.html) and create a folder on your disk as follows **C:/Android/NDK** then extract the contents of the zip in this folder.
4. Set the environment variable **ANDROID_NDK** with the path **C:/Android/NDK**.
6. Move the **is-Engine** project to your **C:/ (C:/is-Engine)**.
7. Open the **is-Engine** folder with **Android Studio** and start the compilation.
If all goes well you will have a **Hello World Screen** on your **Android emulator**.

**Enjoy!**
**2. How to replace the package name (com.author.isengine) of the application**
- Follow these steps carefully. A single error and the application will crash wonderfully when launching on emulator / mobile!
1. Replace this line in the [gradle.app](./app/build.gradle#L32) file.
2. Replace this line in the [AndroidManifest.xml](./app/src/main/AndroidManifest.xml#L3) file.
3. Replace this line in the [SDLActivity.java](./app/src/main/java/com/author/isengine/SDLActivity.java#L1) file.
4. Replace the abresence **[com/author/isengine](./app/src/main/java/com/author/isengine/)** in which is the file [SDLActivity.java](./app/src/main/java/com/author/isengine/SDLActivity.java#L1) that you have just modified at the top by yours (example **com/yourname/yourgamename**).
5. Replace this part **..._ com_author_isengine _...** of line [20](./app/src/main/cpp/SDL_android_main.c#L20) and [23](./app/src/main/cpp/SDL_android_main.c#L23) in the file [SDL_android_main.c](./app/src/main/cpp/SDL_android_main.c#L20) by yours (example **com_yourname_yourgamename)**.
6. Replace this part **..._ com_author_isengine _...** on the 23 lines of the file [SDL_android.c](./libs/SDL2/src/core/android/SDL_android.c#L156) by yours (example **com_yourname_yourgamename**).
- **I strongly advise you to use the replace function of your text editor** (on Notepad++ we use Ctrl + F + Replace option).
7. Replace this line in the [GameConfig.h](./app/src/main/cpp/app_src/config/GameConfig.h#L148) file.
- Note that this part is only required if you want to use the game engine data save / load functions.
**3. Adding Source Files**
- So that Android Studio can detect your source files (.cpp) you must include them in the **[app_src.cmake](./app/src/main/cmake/app_src.cmake) or [isengine.cmake](./app/src/main/cmake/isengine.cmake)** file which is located in the **[is-Engine/app/src/main/cmake](./app/src/main/cmake/)** location.
**4. Application location**
- The application can be found in **is-Engine/app/build/outputs/apk**.
---
##  Web (HTML 5 - CSS 3)
If you want to make your SFML project compatible with the Web (Be able to run it in a web browser), please watch this **[video tutorial](https://youtu.be/x_YQLHoPMbc)**.
 Now you can put texts and geometric shapes (Rectangle, Circle) in Outline on the Web **(It was not available in the old versions)**!
**1. Prerequisites**
- Emscripen (1.39.7 +)
- Python (3.8.1 +)
- CMake (3.1 +)
- Java
- SDL 2 **(It is downloaded with the internet connection when executing commands)**
**2. Installation**
##### Windows
1. Download [Emscripten](https://github.com/emscripten-core/emsdk) and install it in **C:/emsdk**, define its path in the environment variable **Path**
2. Download [Python](https://www.python.org/downloads/release/python-381/) after installation, define its path in the environment variable **Path**
3. Download [CMake](https://cmake.org/download/) after installation, define its path in the environment variable **Path**
4. Download [Java](https://www.oracle.com/java/technologies/javase-jre8-downloads.html) after installation, define its path in the environment variable **Path**
5. Move the **is-Engine** project to your **C:/ (C:/is-Engine)**.
6. Execute this command :
```bash
cd c:/is-Engine/app/src/main
mkdir bin-web
cd bin-web
emsdk activate latest
emcmake cmake ..
make -j3
python -m http.server
```
7. Visit this url **localhost:8000** in your **Web Browser**.
If all goes well you will have a **Hello World Screen** on your **Web Browser**.

**Enjoy!**
**3. Adding Source Files**
- In order for CMake to detect your source files (.cpp) you must include them in the **[app_src.cmake](./app/src/main/cmake/app_src.cmake) or [isengine.cmake](./app/src/main/cmake/isengine.cmake)** file which is located in the **[is-Engine/app/src/main/cmake](./app/src/main/cmake/)** location.
##  Very important
- **is::Engine** works on the Web thanks to **SDL 2**.
- These libraries: **TMXLite, TMXLoader, TinyFileDialog** are not supported in the web version of is::Engine.
- If you want to use SDL functions in your source code, use the **IS_ENGINE_SDL_2 macro**.
- Note that some SFML functions like: **Render Texture** are not yet supported. These additions will be made soon!
---
##  Web Push Notification
- If you want to make your SFML project compatible with the Web (Be able to run it in a web browser), please watch this **[video tutorial](https://youtu.be/x_YQLHoPMbc)**.
- 
By default the web push notification has been disabled. Because to make it work you must have an internet connection. In case there is no internet access and it is not well launched, it can prevent the execution of the web program.
To enable it, please modify these lines in **[index.html](./app/src/main/web/index.html)** : **[7](./app/src/main/web/index.html#L7), [23](./app/src/main/web/index.html#L23), [108](./app/src/main/web/index.html#L108)**
#### Installation
- This shows how to test the push notification. Note that normally to use it, you have to associate it with a database (backend). But here we will use it with the **Push Companion** site **(It will serve as a backend for us!)**.
- For more information on Push Notification please see this [page](https://developers.google.com/web/fundamentals/codelabs/push-notifications).
1. Web browser ([preferably Google Chrome](https://www.google.fr/chrome/?brand=CHBD&brand=XXVF&gclid=EAIaIQobChMI7a315b6c7gIVEKSyCh0O8QJjEAAYASABEgJfd_D_BwE&gclsrc=aw.ds))
2. [Web server for Chrome](https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb) or your own web server.
3. Define the **Application Server Keys** in the [main.js](./app/src/main/web/scripts/main.js#L25) file. You can get this keys (We will use the public key) [here](https://web-push-codelab.glitch.me/).
4. Launch the **[web](./app/src/main/web)** or **bin-web folder (generate using emscripten)** via the web server.
5. Click on the **"Enable Push Messaging" button** to activate the sending of Push Notifications. Once done you will have a code (which can be used to send you push notifications).
6. Go to this [site](https://web-push-codelab.glitch.me/) and enter the code in the **"Subscription to Send To" text field** followed by your message in **"Text to Send" text field**. Click on the **"Send Push Message" button**.
7. If all goes well you will have a push notification followed by the message you sent in the console (development tool) of your browser.

#### Configure the Push Notification
1. To change the **information (title, details, ...)** of the Push Notification you must refer to the [sw.js](./app/src/main/web/sw.js#L28) file.
2. To change the **Push Notification image** files, refer to the [images](./app/src/main/web/images) folder.
3. To change the **page that is launched** when you click on the notification, refer to the [sw.js](./app/src/main/web/sw.js#L45) file.
---
##  CMake
**1. Prerequisites**
- CMake (3.1 +)
**2. Installation**
#### Windows
1. Compile SFML with CMake to have **static libraries** and put on **C:/ (C:/SFML)**.
2. Move the **is-Engine** project to your **C:/ (C:/is-Engine)**.
3. Execute this command :
```bash
cmake -S "C:/is-Engine" -B "C:/build"
cd build
make
```
#### Linux
1. Install SFML 2.5.1 on your machine.
2. Move the **is-Engine** project to **/home/user/ (/home/user/is-Engine)**.
3. Execute this command :
```bash
sudo cmake -S "is-Engine" -B "build"
cd build
sudo make
```
**3. After installation**
- You will have a **bin** folder in which the engine demo is located.
**5. Adding Source Files**
- In order for CMake to detect your source files (.cpp) you must include them in the **[app_src.cmake](./app/src/main/cmake/app_src.cmake) or [isengine.cmake](./app/src/main/cmake/isengine.cmake)** file which is located in the **[is-Engine/app/src/main/cmake](./app/src/main/cmake/)** location.
---
##  Visual Studio
**1. Installation**
#### Windows
Download Visual Studio Community 2022 [here](https://visualstudio.microsoft.com/fr/vs/community/) and install it.
**2. Opening the project with the IDE:**
#### Windows
Open the file **vs-sfml.sln** in the location **[is-Engine/app/src/main/](./app/src/main/)**
---
##  Visual Studio SDL 2
**1. Installation**
#### Windows
1. Download Visual Studio Community 2022 [here](https://visualstudio.microsoft.com/fr/vs/community/) and install it.
2. Download this [file](https://github.com/GlowCheese/SDL2-Setup/releases/download/v1.1.0/SDL2.Compiler.zip) and extract it to C:\ (**the location of the folder must be C:\SDL2-2.26.3. Otherwise it will not work.**).
**2. Opening the project with the IDE:**
#### Windows
Open the file **SDL2_SFML.sln** in the location **[is-Engine/app/src/main/](./app/src/main/)**
---
##  Qt
**1. Installation**
#### Windows
1. Download Qt 5.12.9 MinGW [here](http://qtproject.mirror.liquidtelecom.com/archive/qt/5.12/5.12.9/qt-opensource-windows-x86-5.12.9.exe) and install it.
2. Download this [version of SFML](https://github.com/Is-Daouda/SFML_Qt_MinGW) already compiled for Qt 5.12.9 and extract it in **C:/ (C:/SFML_Qt_MinGW)**.
**2. Opening the project with the IDE:**
#### Windows
1. Run the file **open_qt_creator.bat** in the main directory *(Make sure you have included the path to the Qt executable in your PATH environment variable)*.
2. Or open the file **is-Engine.pro** in the location **[is-Engine/app/src/main/qt](./app/src/main/qt/)**
**3. Executable location**
- The compiler files can be found in **is-Engine/app/src/main/bin-Qt**.
---
##  Visual Studio Code
This project uses the template of **andrew-r-king**. For more information on this template [click here](https://github.com/andrew-r-king/sfml-vscode-boilerplate).
**1. Prerequisites**
#### Windows
- [SFML 2.5.1 - GCC 7.3.0 MinGW (DW2) 32-bit](https://www.sfml-dev.org/files/SFML-2.5.1-windows-gcc-7.3.0-mingw-32-bit.zip)
- [GCC 7.3.0 MinGW (DW2) 32-bit](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/7.3.0/threads-posix/dwarf/i686-7.3.0-release-posix-dwarf-rt_v5-rev0.7z/download)
- [Git Bash](https://git-scm.com/downloads)
#### Linux
- Get SFML 2.5.1 from your distro if it has it, or compile from source.
**2. Installation**
#### Windows
1. Download & Extract SFML 2.5.1 to **C:/SFML/** where the bin/lib/include folders are contained within.
2. Download & Extract MinGW to **C:/mingw32/** where the bin/lib/include folders are contained within.
#### Linux
1. Ensure the GCC Toolchain is installed (**sudo apt install build-essential**).
2. Run **sudo apt install libsfml-dev**. The SFML version you got will vary depending on the distro. 2.5.1 is included in [Ubuntu 19.04 Disco Dingo](http://cdimage.ubuntu.com/daily-live/current/HEADER.html) for example.
**3. Opening the project with the IDE:**
- Rename the **Makefile-vscode** file to **Makefile** in **[is-Engine/app/src/main/](./app/src/main/)**.
#### Windows
1. Run the file **open_vscode.bat** in the main directory.
#### Linux
2. Execute this command in the main directory:
```bash
code -n "./app/src/main"
```
#### All
3. Or open the **[is-Engine/app/src/main](./app/src/main/)** folder with **Solution Explorer**.
**4. Executable location**
- The compiler files can be found in **is-Engine/app/src/main/bin-vscode**.
---
##  Code::Blocks
**1. Installation**
#### Windows
1. Download Code::Blocks 20.03 MinGW [here](https://sourceforge.net/projects/codeblocks/files/Binaries/20.03/Windows/codeblocks-20.03mingw-setup.exe/download) and install it.
2. Download this [version of SFML](https://github.com/Is-Daouda/SFML_CB_MinGW) already compiled for Code::Blocks 20.03 and extract it in **C:/ (C:/SFML_CB_MinGW)**.
#### Linux
1. Download Code::Blocks 20.03 and install it.
2. Ensure the GCC Toolchain is installed (**sudo apt install build-essential**).
3. Run **sudo apt install libsfml-dev**. The SFML version you got will vary depending on the distro. 2.5.1 is included in [Ubuntu 19.04 Disco Dingo](http://cdimage.ubuntu.com/daily-live/current/HEADER.html) for example.
**2. Opening the project with the IDE:**
#### Windows
1. Run the file **open_codeblocks.bat** in the main directory *(Make sure you have included the path to the Code::Blocks executable in your PATH environment variable)*.
2. Or open the file **is-Engine-windows.cbp** in the location **[is-Engine/app/src/main](./app/src/main/)**
#### Linux
1. Execute this command in the main directory:
```bash
codeblocks "./app/src/main/is-Engine-linux.cbp"
```
2. Or open the file **is-Engine-linux.cbp** in the location **[is-Engine/app/src/main](./app/src/main/)**.
**3. Executable location**
- The compiler files can be found in **is-Engine/app/src/main/bin-codeblocks**.
---
##  Develop SFML games with SDL 2
**1. Installation**
#### Windows
1. Download Code::Blocks 20.03 MinGW [here](https://sourceforge.net/projects/codeblocks/files/Binaries/20.03/Windows/codeblocks-20.03mingw-setup.exe/download) and install it.
2. Download this [version of SDL 2](https://github.com/Is-Daouda/SDL2) and extract it in **C:/ (C:/SDL2)**.
3. Put the **.dll files** which is in the **bin** folder of SDL2 in the **[main](./app/src/main/)** folder.
#### Linux
1. Download Code::Blocks 20.03 and install it.
2. Ensure the GCC Toolchain is installed (**sudo apt install build-essential**).
3. Run **sudo apt install libsdl2-2.0-0 libsdl2-gfx-1.0-0 libsdl2-image-2.0-0 libsdl2-mixer-2.0-0 libsdl2-net-2.0-0 libsdl2-ttf-2.0-0** to install all SDL 2 libraries.
**2. Opening the project with the IDE:**
#### Windows
1. Run the file **open_codeblocks_sdl.bat** in the main directory *(Make sure you have included the path to the Code::Blocks executable in your PATH environment variable)*.
2. Or open the file **is-Engine-windows-SDL2.cbp** in the location **[is-Engine/app/src/main](./app/src/main/)**
#### Linux
1. Execute this command in the main directory:
```bash
codeblocks "./app/src/main/is-Engine-linux-SDL2.cbp"
```
2. Or open the file **is-Engine-linux-SDL2.cbp** in the location **[is-Engine/app/src/main](./app/src/main/)**.
**3. Executable location**
- The compiler files can be found in **is-Engine/app/src/main/bin-codeblocks**.
##  Very important
- If you want to use SDL functions in your source code, use the **IS_ENGINE_SDL_2 macro**.
- Note that some SFML functions like: **Render Texture** are not yet supported. These additions will be made soon!
---
##  Change application icon:
#### Nintendo Switch
- To change the icon of the application you must go to the location **[is-Engine/app/src/main/](./app/src/main/)**.
#### Android
- To change the icon of the application you must go to the location **[is-Engine/app/src/main/res](./app/src/main/res/)** replace all the images (PNG) which are in the **drawable** subfolders.
#### Web (HTML 5 - CSS 3)
- To change the icon of the application you must go to the location **[is-Engine/app/src/main/web](./app/src/main/web/)**.
#### Windows
- To change the icon of the application you must go to the location **[is-Engine/app/src/main/env/windows](./app/src/main/env/windows)** replace all the images **(Attention CMake uses the same resources).**
#### Linux
- To change the icon of the application you must go to the location **[is-Engine/app/src/main/env/linux](./app/src/main/env/linux)**.
---
## Description of the project structure:

----------------------------
- The source files of the project can be found in the **[is-Engine/app/src/main/cpp](./app/src/main/cpp/)** location.
#### 1. [main.cpp](./app/src/main/cpp/main.cpp) file
Contains the entry point of the program, inside there are two instructions :
- `game.play()`: Launches the engine rendering loop which allows to manage the introduction screen, main menu, level and game over.
- `game.basicSFMLmain()` (disabled by default): Launches the display of a classic SFML window. The implementation is in the **[basicSFMLmain.cpp](./app/src/main/cpp/basicSFMLmain.cpp)** file. *Very useful if you already have a project under development and you want to associate it with the engine. You can also use it to implement your own components to the engine.*
----------------------------
#### 2. [app_src](./app/src/main/cpp/app_src/) folder
Contains the source code of the game.
Description of these sub-directories:
- **[activity](./app/src/main/cpp/app_src/activity/)** : Contains the **[Activity](./app/src/main/cpp/app_src/activity/GameActivity.h)** class which allows the interaction of the different scenes of the game.
- **[config](./app/src/main/cpp/app_src/config/)** : Contains the **[GameConfig.h](./app/src/main/cpp/app_src/config/GameConfig.h)** file which allows to define the general parameters of the game. It also contains the file **[ExtraConfig.h](./app/src/main/cpp/app_src/config/ExtraConfig.h)** which allows to activate / deactivate certain engine functionality (Engine optimization, SDM, Admob, Main Render Loop, ...).
- **[gamesystem_ext](./app/src/main/cpp/app_src/gamesystem_ext/)** : Contains **[GameSystemExtended](./app/src/main/cpp/app_src/gamesystem_ext/GameSystemExtended.h)** a class derived from **[GameSystem](./app/src/main/cpp/isEngine/system/function/GameSystem.h)** which allows to manipulate game data (save, load, ...).
- **[language](./app/src/main/cpp/app_src/language/)** : Contains the **[GameLanguage.h](./app/src/main/cpp/app_src/language/GameLanguage.h)** file which allows to manage everything related to game languages.
- **[levels](./app/src/main/cpp/app_src/levels/)** : Contains game levels and the **[Level.h](./app/src/main/cpp/app_src/levels/Level.h)** file which allows to integrate them into the game.
- **[objects](./app/src/main/cpp/app_src/objects/)** : Contains the objects that will be used in the different scenes.
- **[scenes](./app/src/main/cpp/app_src/scenes/)** : Contains the different scenes of the game (Introduction, Main menu, ...).
----------------------------
#### 3. [assets](./app/src/main/assets/) folder
Contains game resource files (music, sound sfx, image, ...)
----------------------------
#### 4. [isEngine](./app/src/main/cpp/isEngine/) folder
Contains the source code of the game engine
---
## Special things to know about the engine
### is::LibConnect
With the is::LibConnect you can write code for a specific library. Here is how to do it:
```cpp
sf::Text text;
text.setString(
// on PC (Windows / Linux)
#if define(IS_ENGINE_SFML)
"We use SFML 2 library"
// When we develop for the Nintendo Switch
#elif define(IS_ENGINE_SWITCH)
"SFML 2 on Switch"
// on Android or when you use SDL to create SFML games on PC (only for Code::Block at the moment)
#elif define(IS_ENGINE_SDL_2)
"Run SFML 2 with SDL 2"
// When we develop for the web (HTML 5) with Emscripten
#elif define(IS_ENGINE_HTML_5)
"SFML 2 on Web"
#endif
);
```
#### If you have discovered another way to use the game engine, don't hesitate to share it! We will put it in this Special section so that other people can benefit from it!
---
## How to update an is::Engine project
1. First of all the part of is::Engine that changes most often during updates is the [isEngine](./app/src/main/cpp/isEngine/) folder. But it also happens that these files can be modified:
- [GameActivity.h](./app/src/main/cpp/app_src/activity/GameActivity.h)
- [GameConfig.h](./app/src/main/cpp/app_src/language/GameLanguage.h)
- [ExtraConfig.h](./app/src/main/cpp/app_src/config/ExtraConfig.h)
- [GameSystemExtended.h](./app/src/main/cpp/app_src/gamesystem_ext/GameSystemExtended.h)
- [basicSFMLmain.cpp](./app/src/main/cpp/basicSFMLmain.cpp)
- [GameLanguage.h](./app/src/main/cpp/app_src/language/GameLanguage.h)
- And the files which is in [cmake](./app/src/main/cmake) and [web](./app/src/main/web) folder.
-  **So watch them carefully in case you encounter any errors during migration!**
2. To update your old project with a new version of is::Engine: the files (.h and .cpp) you need to move are in [objects](./app/src/main/cpp/app_src/objects/) and [scenes](./app/src/main/cpp/app_src/scenes/). **Note that these folders never change whatever the version!**
---
## How to activate the use of Admob?
Coming soon!
---
## Contribute
- If you want to participate in the development of the project to help me improve the engine, please note that you are welcome! Together we go further!
- One of the objectives of this project is to create a large community that can work on the engine to allow many people around the world to easily realize their dream games / applications!
## Contacts
* For any help please contact me on my [email address](mailto:isdaouda.n@gmail.com)
* You can follow me on Twitter for more informations on my activities [@Is Daouda Games](https://twitter.com/IsDaouda_Games)
================================================
FILE: app/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.4.1)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2/include
# SDL_internal.h is located in src required by SDL_android_main.c bridge
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2/src
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_image/include
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_gfx/include
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_mixer/include
${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_ttf/include
)
set(ISENGINE_ANDROID true) # This confirms that we are using is::Engine to develop on Android
set(ISENGINE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp")
set(ISENGINE_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/main/cmake")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2/ ${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_image/ ${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_image)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_gfx/ ${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_gfx)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_mixer/ ${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_mixer)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_ttf/ ${CMAKE_CURRENT_SOURCE_DIR}/../libs/SDL2_ttf)
#include_directories(${FIREBASE_INCLUDE_DIR})
#link_directories("${FIREBASE_LIBRARY_DIR}${ANDROID_ABI}/c++/")
include(${ISENGINE_CMAKE_DIR}/isengine.cmake)
include(${ISENGINE_CMAKE_DIR}/app_src.cmake)
add_library(
isengine
SHARED
# Provides a relative path to your source file(s).
${isengine}
${app_src}
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
isengine
SDL2
SDL2_image
SDL2_gfx
SDL2_mixer
SDL2_ttf
#admob
#app
${log-lib} )
================================================
FILE: app/build.gradle
================================================
buildscript {
repositories {
google()
mavenLocal()
maven {url 'https://maven.google.com'}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
//classpath 'com.google.gms:google-services:4.0.1'
}
}
apply plugin: 'com.android.application'
/*
def ndkDir = System.getenv("ANDROID_NDK")
def propertiesFile = project.rootProject.file('local.properties')
if (propertiesFile.exists()) {
Properties properties = new Properties()
properties.load(propertiesFile.newDataInputStream())
ndkDir = properties.getProperty('ndk.dir')
}
*/
android {
compileSdkVersion 30
buildToolsVersion '28.0.3'
defaultConfig {
applicationId = 'com.author.isengine'
//Replace this with your real package name (e.g. com.StudioName.GameName)
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
//multiDexEnabled true
externalNativeBuild {
cmake {
cppFlags "-std=c++1z -std=c++14 -std=c++17 -frtti -fexceptions"
arguments "-DANDROID_STL=c++_shared",
"-DANDROID_TOOLCHAIN=clang" //,
//"-DFIREBASE_INCLUDE_DIR=${ndkDir}/sources/firebase_cpp_sdk/include",
//"-DFIREBASE_LIBRARY_DIR=${ndkDir}/sources/firebase_cpp_sdk/libs/android/"
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
}
}
}
buildTypes {
debug {
minifyEnabled false
jniDebuggable true
debuggable false
}
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
//proguardFile file("${ndkDir}/sources/firebase_cpp_sdk/libs/android/app.pro")
//proguardFile file("${ndkDir}/sources/firebase_cpp_sdk/libs/android/admob.pro")
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
version "3.10.2"
}
}
/*sourceSets {
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = [
"${ndkDir}/sources/firebase_cpp_sdk/libs/android/"
]
}
}*/
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//implementation 'com.android.support:multidex:1.0.3'
}
================================================
FILE: app/src/main/.vs/vs-sfml/v17/DocumentLayout.json
================================================
{
"Version": 1,
"WorkspaceRootPath": "C:\\is-Engine\\app\\src\\main\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}
================================================
FILE: app/src/main/.vs/vs-sfml/v17/ipch/AutoPCH/ee33401603bb6f9/HELLOSCENE.ipch
================================================
[File too large to display: 72.1 MB]
================================================
FILE: app/src/main/.vs/vs-sfml/v17/ipch/AutoPCH/f64c3c32af64e908/BASICSFMLMAIN.ipch
================================================
[File too large to display: 77.6 MB]
================================================
FILE: app/src/main/.vscode/_keybindings.json
================================================
// Place your key bindings in this file to overwrite the defaults
[
{
"key": "f8",
"command": "-editor.action.marker.next",
"when": "editorFocus && !editorReadonly"
},
{
"key": "f9",
"command": "-editor.debug.action.toggleBreakpoint",
"when": "editorTextFocus"
},
{
"key": "f10",
"command": "-workbench.action.debug.stepOver",
"when": "inDebugMode"
},
{
"key": "shift+f8",
"command": "-editor.action.marker.prev",
"when": "editorFocus && !editorReadonly"
},
{
"key": "shift+f9",
"command": "-editor.debug.action.toggleInlineBreakpoint",
"when": "editorTextFocus"
},
{
"key": "shift+f10",
"command": "-editor.action.showContextMenu",
"when": "editorTextFocus"
},
{
"key": "f8",
"command": "workbench.action.debug.selectandstart"
},
{
"key": "f9",
"command": "workbench.action.tasks.runTask",
"args": "Build & Run: Release"
},
{
"key": "shift+f9",
"command": "workbench.action.tasks.runTask",
"args": "Run: Release"
},
{
"key": "f10",
"command": "workbench.action.tasks.runTask",
"args": "Build & Run: Debug"
},
{
"key": "shift+f10",
"command": "workbench.action.tasks.runTask",
"args": "Run: Debug"
},
]
================================================
FILE: app/src/main/.vscode/c_cpp_properties.json
================================================
{
"configurations": [
{
"name": "Linux",
"intelliSenseMode": "gcc-x64",
"includePath": [
"${workspaceFolder}/cpp",
"${workspaceFolder}/lib",
"${workspaceFolder}/test",
"~/SFML/include",
"/usr/local/include/**",
"/usr/include/**"
],
"defines": [
"_DEBUG"
],
"cStandard": "c11",
"cppStandard": "c++17",
"forcedInclude": [
"${workspaceFolder}/cpp/PCH.hpp"
]
},
{
"name": "Mac",
"intelliSenseMode": "clang-x64",
"compilerPath": "/usr/bin/clang",
"macFrameworkPath": [
"/Library/Frameworks",
"/System/Library/Frameworks"
],
"includePath": [
"${workspaceFolder}/cpp",
"${workspaceFolder}/lib",
"${workspaceFolder}/test",
"/usr/local/include/**"
],
"defines": [
"_DEBUG"
],
"cStandard": "c11",
"cppStandard": "c++17",
"forcedInclude": [
"${workspaceFolder}/cpp/PCH.hpp"
]
},
{
"name": "Win32",
"intelliSenseMode": "gcc-x64",
"compilerPath": "C:/mingw32/bin/gcc.exe",
"includePath": [
"${workspaceFolder}/cpp",
"${workspaceFolder}/lib",
"C:/SFML/include"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"cStandard": "c11",
"cppStandard": "c++17",
"forcedInclude": [
"${workspaceFolder}/cpp/PCH.hpp"
]
}
],
"version": 4
}
================================================
FILE: app/src/main/.vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
"name": "GDB/LLDB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin-vscode/Debug/${workspaceRootFolderName}.exe",
"args": [
"-exec info registers"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build: Debug",
"externalConsole": false,
"internalConsoleOptions": "neverOpen",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:/mingw32/bin/gdb.exe",
"env": {
"Path": "${config:terminal.integrated.env.windows.Path}"
}
},
"linux": {
"program": "${workspaceFolder}/bin-vscode/Debug/${workspaceRootFolderName}",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"env": {
"PATH": "${config:terminal.integrated.env.linux.PATH}",
}
},
"osx": {
"program": "${workspaceFolder}/bin-vscode/Debug/${workspaceRootFolderName}",
"MIMode": "lldb",
"env": {
"PATH": "${config:terminal.integrated.env.osx.PATH}",
}
},
}
]
}
================================================
FILE: app/src/main/.vscode/settings.json
================================================
{
"C_Cpp.autocomplete": "Default",
"C_Cpp.intelliSenseEngine": "Default",
"C_Cpp.dimInactiveRegions": false,
"C_Cpp.preferredPathSeparator": "Forward Slash",
"C_Cpp.loggingLevel": "Warning",
"C_Cpp.workspaceParsingPriority": "highest",
"C_Cpp.enhancedColorization": "Disabled",
"debug.toolBarLocation": "docked",
"editor.fontFamily": "'Ubuntu Mono', 'Courier Prime Code', 'Courier', 'Courier New', Consolas, monospace",
"editor.tabSize": 4,
"editor.insertSpaces": false,
"files.encoding": "utf8",
"files.trimTrailingWhitespace": true,
"files.eol": "\n",
"files.exclude": {
// hide file
"res": true
"save": true
"CMakeLists.txt": true
"AndroidManifest.xml": true
"codeblocks": true
"cmake": true
"bin-codeblocks": true
"bin-vscode": true
"is-Engine-linux.cbp": true
"is-Engine-linux.layout": true
"is-Engine-linux.depend": true
"is-Engine-windows.cbp": true
"is-Engine-windows.layout": true
"is-Engine-windows.depend": true
".vscode/launch.json": true,
"env/windows/*.sh": true,
"env/osx/dmg.applescript": true,
"Makefile": true,
"build.sh": true,
"gmon.out": true,
"bin/": true,
"build/": true,
"**/*.7z": true,
"**/*.rar": true,
"**/Thumbs.db": true
},
"files.associations": {
"*.json": "jsonc",
"*.stats": "cpp",
"*.desktop": "properties",
".clang-format": "yaml"
},
"terminal.integrated.shell.windows": "C:/Program Files/Git/bin/bash.exe",
"terminal.integrated.env.windows": {
"Path": "C:/mingw32/bin;C:/SFML/bin"
},
"terminal.integrated.env.linux": {
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
},
"terminal.integrated.env.osx": {
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
},
"workbench.colorCustomizations": {
"statusBar.background": "#8ac242",
"statusBar.foreground": "#ffffff",
"statusBar.debuggingBackground": "#5e9517",
"statusBar.debuggingForeground": "#ffffff",
"terminal.ansiBrightRed": "#ee3355",
"terminal.ansiBrightYellow": "#ffcc55",
"terminal.ansiBrightGreen": "#a5ea4f",
"terminal.ansiBrightBlue": "#5599ff"
},
"[applescript]": {
"files.encoding": "utf8"
}
}
================================================
FILE: app/src/main/.vscode/tasks.json
================================================
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"windows": {
"options": {
"env": {
"Path": "${config:terminal.integrated.env.windows.Path}"
}
}
},
"linux": {
"options": {
"env": {
"PATH": "${config:terminal.integrated.env.linux.PATH}"
}
}
},
"osx": {
"options": {
"env": {
"PATH": "${config:terminal.integrated.env.osx.PATH}"
}
}
},
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"clear": false,
"showReuseMessage": true
},
"tasks": [
{
"label": "Build & Run: Release",
"command": "bash ./build.sh buildrun Release vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
],
},
{
"label": "Build: Release",
"command": "bash ./build.sh build Release vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Run: Release",
"command": "bash ./build.sh run Release vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Rebuild: Release",
"command": "bash ./build.sh rebuild Release vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Build & Run: Debug",
"command": "bash ./build.sh buildrun Debug vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Build: Debug",
"command": "bash ./build.sh build Debug vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Run: Debug",
"command": "bash ./build.sh run Debug vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Rebuild: Debug",
"command": "bash ./build.sh rebuild Debug vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Profile: Debug",
"command": "bash ./build.sh profile Debug vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Build & Run: Tests",
"command": "bash ./build.sh buildrun Tests vscode '-w NoTests -s'",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Build: Tests",
"command": "bash ./build.sh build Tests vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Run: Tests",
"command": "bash ./build.sh run Tests vscode '-w NoTests -s'",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Rebuild: Tests",
"command": "bash ./build.sh rebuild Tests vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "Build: Production",
"command": "bash ./build.sh buildprod Release vscode",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
}
]
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)
project(isengine)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
if( ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set(USE_FLAGS "-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS=\"['png']\" -s -s USE_SDL_TTF=2 -s USE_SDL_MIXER=2 -s USE_OGG=1 -s USE_VORBIS=1 -s USE_FREETYPE=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${USE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${USE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${USE_FLAGS}")
endif()
include_directories(${CMAKE_SOURCE_DIR}/include ${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS} ${SDL2_TTF_INCLUDE_DIRS} ${SDL2_MIXER_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS})
set(ISENGINE_HTML_5 true) # This confirms that we are using is::Engine to develop on the Web
set(ISENGINE_SRC_DIR "cpp")
set(ISENGINE_CMAKE_DIR "cmake")
add_compile_definitions(IS_ENGINE_HTML_5)
include(${ISENGINE_CMAKE_DIR}/app_src.cmake)
include(${ISENGINE_CMAKE_DIR}/isengine.cmake)
add_executable(isengine
${app_src}
${isengine}
)
target_link_libraries(isengine ${SDL2_LIBRARIES} ${SDL2IMAGE_LIBRARIES} ${SDL2MIXER_LIBRARIES} ${SDL2TTF_LIBRARIES} ${FREETYPE_LIBRARIES} -lidbfs.js)
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " -s ALLOW_MEMORY_GROWTH=1")
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " -s DISABLE_EXCEPTION_CATCHING=2")
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " -s WASM=1")
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " -s TOTAL_MEMORY=134217728")
# Release flags
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " --emrun")
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " -O3")
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " --bind")
# Copy the web files
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/web/index.html ${CMAKE_CURRENT_BINARY_DIR}/index.html COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/web/sw.js ${CMAKE_CURRENT_BINARY_DIR}/sw.js COPYONLY)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/web/images DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/web/scripts DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/web/styles DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
# Allow some files to be fetched.
file(GLOB files "./assets/*" "./assets/*/*")
foreach(file ${files})
file(RELATIVE_PATH relative_file ${CMAKE_SOURCE_DIR} ${file})
set_property(TARGET isengine APPEND_STRING PROPERTY LINK_FLAGS " --preload-file ${file}@/${relative_file}")
endforeach()
================================================
FILE: app/src/main/Makefile
================================================
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - .jpg
# - icon.jpg
# - /default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - .json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := cpp
DATA := data
INCLUDES := cpp
ROMFS := romfs
APP_TITLE := is::Engine
APP_AUTHOR := author
APP_VERSION := 1.0
ICON := icon.jpg
PC_LIBS := SDL2_image SDL2_mixer SDL2_ttf sdl2
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := `$(PREFIX)pkg-config --cflags $(PC_LIBS)` \
-g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__ -DIS_ENGINE_SWITCH
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 -std=gnu++17
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := `$(PREFIX)pkg-config --libs $(PC_LIBS)` \
-lnx -lm -lstdc++
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(APP_JSON)),)
all : $(OUTPUT).nro
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
else
all : $(OUTPUT).nsp
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
$(OUTPUT).nso : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
================================================
FILE: app/src/main/Makefile-vscode
================================================
.SUFFIXES:
SUFFIXES =
.SUFFIXES: .c .cpp .h .hpp .rc .res .inl .o .d .asm
#==============================================================================
MAKEFLAGS += --no-print-directory
#==============================================================================
# Build platform
PLATFORM?=linux
# Build description (Primarily uses Debug/Release)
BUILD?=Release
_BUILDL := $(shell echo $(BUILD) | tr A-Z a-z)
ifeq ($(BUILD),Tests)
_BUILDL := release
endif
# The sub-folder containing the target source files
SRC_TARGET?=
ifneq ($(SRC_TARGET),)
_SRC_TARGET := /$(SRC_TARGET)
endif
# Maximum parallel jobs during build process
MAX_PARALLEL_JOBS?=8
# Dump assembly?
DUMP_ASSEMBLY?=false
# Clean output?
CLEAN_OUTPUT?=true
# If dll, build as a static library?
BUILD_STATIC?=false
# Platform specific environment variables
-include env/.all.mk
-include env/.$(_BUILDL).mk
-include env/$(PLATFORM).all.mk
-include env/$(PLATFORM).$(_BUILDL).mk
# Target specific variables
ifneq ($(SRC_TARGET),)
-include env/$(SRC_TARGET)/.all.mk
-include env/$(SRC_TARGET)/.$(_BUILDL).mk
-include env/$(SRC_TARGET)/$(PLATFORM).all.mk
-include env/$(SRC_TARGET)/$(PLATFORM).$(_BUILDL).mk
endif
#==============================================================================
# File/Folder dependencies for the production build recipe (makeproduction)
PRODUCTION_DEPENDENCIES?=
# Extensions to exclude from production builds
PRODUCTION_EXCLUDE?=
# Folder location (relative or absolute) to place the production build into
PRODUCTION_FOLDER?=build
PRODUCTION_FOLDER_RESOURCES := $(PRODUCTION_FOLDER)
#==============================================================================
# Library directories (separated by spaces)
LIB_DIRS?=
INCLUDE_DIRS?=
# Link libraries (separated by spaces)
LINK_LIBRARIES?=
# Precompiled header filename (no extension)
# This file will be excluded from Rebuild, but if the bin/(build) directory is removed, it will be as well.
PRECOMPILED_HEADER?=
# Build-specific preprocessor macros
BUILD_MACROS?=
# Build-specific compiler flags to be appended to the final build step (with prefix)
BUILD_FLAGS?=
# Build dependencies to copy into the bin/(build) folder - example: openal32.dll
BUILD_DEPENDENCIES?=
# NAME should always be passed as an argument from tasks.json as the root folder name, but uses a fallback of "game.exe"
# This is used for the output filename (game.exe)
NAME?=game.exe
#==============================================================================
# The source file directory
SRC_DIR := cpp$(_SRC_TARGET)
LIB_DIR := lib
# Project .cpp or .rc files (relative to $(SRC_DIR) directory)
SOURCE_FILES := $(patsubst $(SRC_DIR)/%,%,$(shell find $(SRC_DIR) -name '*.cpp' -o -name '*.c' -o -name '*.cc' -o -name '*.rc'))
# Project subdirectories within $(SRC_DIR)/ that contain source files
PROJECT_DIRS := $(patsubst $(SRC_DIR)/%,%,$(shell find $(SRC_DIR) -mindepth 1 -maxdepth 99 -type d))
# Add prefixes to the above variables
_INCLUDE_DIRS := $(patsubst %,-I%,$(SRC_DIR)/ $(LIB_DIR)/ $(INCLUDE_DIRS))
_BUILD_MACROS := $(BUILD_MACROS:%=-D%)
_LINK_LIBRARIES := $(LINK_LIBRARIES:%=-l%)
#==============================================================================
# Unit Testing
TEST_DIR :=
ifeq ($(BUILD),Tests)
TEST_DIR := test
SOURCE_FILES := $(SOURCE_FILES:Main.cpp=)
SOURCE_FILES := $(patsubst $(TEST_DIR)/%,.$(TEST_DIR)/%,$(shell find $(TEST_DIR) -name '*.cpp' -o -name '*.c' -o -name '*.cc' -o -name '*.rc')) $(SOURCE_FILES)
_INCLUDE_DIRS := $(patsubst %,-I%,$(TEST_DIR)/) $(_INCLUDE_DIRS)
PROJECT_DIRS := .$(TEST_DIR) $(PROJECT_DIRS)
BUILD_FLAGS := $(BUILD_FLAGS:-mwindows=)
endif
#==============================================================================
# Linux Specific
PRODUCTION_LINUX_ICON?=icon
# The full working directory
ifeq ($(PLATFORM),linux)
_LINUX_GREP_CWD := $(shell echo $(CURDIR) | sed 's/\//\\\//g')
endif
#==============================================================================
# MacOS Specific
PRODUCTION_MACOS_ICON?=icon
PRODUCTION_MACOS_BUNDLE_COMPANY?=developer
PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME?=App
PRODUCTION_MACOS_BUNDLE_NAME?=App
PRODUCTION_MACOS_MAKE_DMG?=true
PRODUCTION_MACOS_BACKGROUND?=dmg-background
ifeq ($(PLATFORM),osx)
PRODUCTION_MACOS_BUNDLE_COMPANY := '$(PRODUCTION_MACOS_BUNDLE_COMPANY)'
PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME := '$(PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME)'
PRODUCTION_MACOS_BUNDLE_NAME := '$(PRODUCTION_MACOS_BUNDLE_NAME)'
PRODUCTION_FOLDER_MACOS := $(PRODUCTION_FOLDER)
PRODUCTION_FOLDER := $(PRODUCTION_FOLDER)/$(PRODUCTION_MACOS_BUNDLE_NAME).app/Contents
PRODUCTION_FOLDER_RESOURCES := $(PRODUCTION_FOLDER)/Resources
PRODUCTION_DEPENDENCIES := $(PRODUCTION_DEPENDENCIES)
PRODUCTION_MACOS_DYLIBS := $(PRODUCTION_MACOS_DYLIBS:%=%.dylib)
MACOS_FRAMEWORKS?=CoreFoundation
PRODUCTION_MACOS_FRAMEWORKS := $(PRODUCTION_MACOS_FRAMEWORKS:%=%.framework)
PRODUCTION_MACOS_BACKGROUND := env/osx/$(PRODUCTION_MACOS_BACKGROUND)
MACOS_FRAMEWORK_PATHS := $(MACOS_FRAMEWORK_PATHS:%=-F%)
BUILD_FLAGS := $(BUILD_FLAGS) $(MACOS_FRAMEWORK_PATHS) $(MACOS_FRAMEWORKS:%=-framework %)
endif
#==============================================================================
# Directories & Dependencies
BLD_DIR := bin-vscode/$(BUILD)
ifeq ($(BUILD),Tests)
BLD_DIR := bin-vscode/Release
endif
BLD_DIR := $(BLD_DIR:%/=%)
TARGET := $(BLD_DIR)/$(NAME)
_NAMENOEXT := $(NAME:.exe=)
_NAMENOEXT := $(_NAMENOEXT:.dll=)
ifneq ($(SRC_TARGET),)
LIB_DIRS := $(LIB_DIRS) $(BLD_DIR)
endif
_LIB_DIRS := $(LIB_DIR:%=-L%/) $(LIB_DIRS:%=-L%)
_SOURCES_IF_RC := $(if $(filter windows,$(PLATFORM)),$(SOURCE_FILES:.rc=.res),$(SOURCE_FILES:%.rc=))
OBJ_DIR := $(BLD_DIR)/obj$(_SRC_TARGET)
_OBJS := $(_SOURCES_IF_RC:.c=.c.o)
_OBJS := $(_OBJS:.cpp=.cpp.o)
_OBJS := $(_OBJS:.cc=.cc.o)
OBJS := $(_OBJS:%=$(OBJ_DIR)/%)
OBJ_SUBDIRS := $(PROJECT_DIRS:%=$(OBJ_DIR)/%)
DEP_DIR := $(BLD_DIR)/dep$(_SRC_TARGET)
_DEPS := $(_SOURCES_IF_RC)
_DEPS := $(_DEPS:%=%.d)
DEPS := $(_DEPS:%=$(DEP_DIR)/%) $(DEP_DIR)/$(PRECOMPILED_HEADER).d
DEP_SUBDIRS := $(PROJECT_DIRS:%=$(DEP_DIR)/%)
_PCH_HFILE := $(shell find $(SRC_DIR) -name '$(PRECOMPILED_HEADER).hpp' -o -name '$(PRECOMPILED_HEADER).h' -o -name '$(PRECOMPILED_HEADER).hh')
_PCH_HFILE := $(_PCH_HFILE:$(SRC_DIR)/%=%)
_PCH_EXT := $(_PCH_HFILE:$(PRECOMPILED_HEADER).%=%)
_PCH_COMPILER_EXT := $(if $(filter osx,$(PLATFORM)),p,g)ch
_SYMBOLS := $(if $(filter osx,$(PLATFORM)),,$(if $(filter Release,$(BUILD)),-s,))
_PCH := $(_PCH_HFILE:%=$(OBJ_DIR)/%)
ifneq ($(_PCH),)
_PCH_GCH := $(_PCH).$(_PCH_COMPILER_EXT)
endif
ifeq ($(DUMP_ASSEMBLY),true)
ASM_DIR := $(BLD_DIR)/asm$(_SRC_TARGET)
_ASMS := $(_OBJS:%.res=)
_ASMS := $(_ASMS:.o=.o.asm)
ASMS := $(_ASMS:%=$(ASM_DIR)/%)
ASM_SUBDIRS := $(PROJECT_DIRS:%=$(ASM_DIR)/%)
endif
_DIRECTORIES := $(sort bin-vscode $(BLD_DIR) $(OBJ_DIR) $(OBJ_SUBDIRS) $(DEP_DIR) $(DEP_SUBDIRS) $(ASM_DIR) $(ASM_SUBDIRS))
_CLEAN := $(filter true,$(CLEAN_OUTPUT))
# Quiet flag
_Q := $(if $(_CLEAN),@)
#==============================================================================
# Compiler & flags
CC?=g++
RC?=windres.exe
CFLAGS?=-O2 -Wall -fdiagnostics-color=always
CFLAGS_DEPS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.Td
CFLAGS_DEPS_T = -MT $@ -MMD -MP -MF $(DEP_DIR)/.$(TEST_DIR)/$*.Td
PCH_COMPILE = $(CC) $(CFLAGS_DEPS) $(_BUILD_MACROS) $(CFLAGS) $(_INCLUDE_DIRS) -o $@ -c $<
ifneq ($(_PCH),)
_INCLUDE_PCH := -include $(_PCH)
endif
OBJ_COMPILE = $(CC) $(CFLAGS_DEPS) $(_BUILD_MACROS) $(_INCLUDE_DIRS) $(_INCLUDE_PCH) $(CFLAGS) -o $@ -c $<
OBJ_COMPILE_T = $(CC) $(CFLAGS_DEPS_T) $(_BUILD_MACROS) $(_INCLUDE_DIRS) $(_INCLUDE_PCH) $(CFLAGS) -o $@ -c $<
RC_COMPILE = -$(RC) -J rc -O coff -i $< -o $@
ifeq ($(PLATFORM),osx)
ASM_COMPILE = otool -tvV $< | c++filt > $@
else
ASM_COMPILE = objdump -d -C -Mintel $< > $@
endif
POST_COMPILE = mv -f $(DEP_DIR)/$*.Td $(DEP_DIR)/$*.d && touch $@
POST_COMPILE_T = mv -f $(DEP_DIR)/.$(TEST_DIR)/$*.Td $(DEP_DIR)/.$(TEST_DIR)/$*.d && touch $@
#==============================================================================
# Build Scripts
all:
@$(MAKE) makepch
@$(MAKE) -j$(MAX_PARALLEL_JOBS) makebuild
.DELETE_ON_ERROR: all
rebuild: clean all
.PHONY: rebuild
buildprod: all makeproduction
.PHONY: buildprod
#==============================================================================
# Functions
color_reset := @tput setaf 4
define compile_with
$(color_reset)
$(if $(_CLEAN),@echo ' $($(2):$(OBJ_DIR)/%=%)')
$(_Q)$(3) && $(4)
endef
MKDIR := $(_Q)mkdir -p
makepch: $(_PCH_GCH)
@echo > /dev/null
.PHONY: makepch
makebuild: $(TARGET)
$(color_reset)
ifeq ($(SRC_TARGET),)
@echo ' Target is up to date.'
else
@echo ' $(NAME): Target is up to date.'
endif
.PHONY: makebuild
#==============================================================================
# Build Recipes
$(OBJ_DIR)/%.o: $(SRC_DIR)/%
$(OBJ_DIR)/%.o: $(SRC_DIR)/% $(_PCH_GCH) $(DEP_DIR)/%.d | $(_DIRECTORIES)
$(call compile_with,@,<,$(OBJ_COMPILE),$(POST_COMPILE))
$(OBJ_DIR)/.$(TEST_DIR)/%.o: $(TEST_DIR)/%
$(OBJ_DIR)/.$(TEST_DIR)/%.o: $(TEST_DIR)/% $(_PCH_GCH) $(DEP_DIR)/.$(TEST_DIR)/%.d | $(_DIRECTORIES)
$(call compile_with,@,<,$(OBJ_COMPILE_T),$(POST_COMPILE_T))
$(OBJ_DIR)/%.$(_PCH_EXT).$(_PCH_COMPILER_EXT) : $(SRC_DIR)/%.$(_PCH_EXT)
$(OBJ_DIR)/%.$(_PCH_EXT).$(_PCH_COMPILER_EXT) : $(SRC_DIR)/%.$(_PCH_EXT) $(DEP_DIR)/%.d | $(_DIRECTORIES)
$(call compile_with,@,<,$(PCH_COMPILE),$(POST_COMPILE))
$(OBJ_DIR)/%.res: $(SRC_DIR)/%.rc
$(OBJ_DIR)/%.res: $(SRC_DIR)/%.rc $(DEP_DIR)/%.d | $(_DIRECTORIES)
$(color_reset)
$(if $(_CLEAN),@echo " $(<:$(OBJ_DIR)/%=%)")
$(_Q)$(RC_COMPILE)
$(ASM_DIR)/%.o.asm: $(OBJ_DIR)/%.o
@tput setaf 6
$(if $(_CLEAN),@echo " $@")
$(_Q)$(ASM_COMPILE)
$(TARGET): $(_PCH_GCH) $(OBJS) $(ASMS) $(TEST_DIR)
$(color_reset)
$(if $(_CLEAN),@echo; printf '\xE2\x87\x9B'; echo ' Linking: $(TARGET)')
ifeq ($(suffix $(TARGET)),.dll)
ifeq ($(BUILD_STATIC),true)
-$(_Q)rm -rf $(BLD_DIR)/lib$(_NAMENOEXT).a
$(_Q)ar.exe -r -s $(BLD_DIR)/lib$(_NAMENOEXT).a $(OBJS)
else
-$(_Q)rm -rf $(BLD_DIR)/lib$(_NAMENOEXT).def $(BLD_DIR)/lib$(_NAMENOEXT).a
$(_Q)$(CC) -shared -Wl,--output-def="$(BLD_DIR)/lib$(_NAMENOEXT).def" -Wl,--out-implib="$(BLD_DIR)/lib$(_NAMENOEXT).a" -Wl,--dll $(_LIB_DIRS) $(OBJS) -o $@ $(_SYMBOLS) $(_LINK_LIBRARIES) $(BUILD_FLAGS)
endif
else
$(_Q)$(CC) $(_LIB_DIRS) $(_SYMBOLS) -o $@ $(OBJS) $(_LINK_LIBRARIES) $(BUILD_FLAGS)
endif
@echo
ifneq ($(BUILD_DEPENDENCIES),)
$(foreach dep,$(BUILD_DEPENDENCIES),$(call copy_to,$(dep),$(BLD_DIR)))
endif
$(_DIRECTORIES):
$(if $(_CLEAN),,$(color_reset))
$(MKDIR) $@
$(if $(_CLEAN),,@echo)
clean:
$(color_reset)
$(if $(_CLEAN),@echo ' Cleaning old build files & folders...'; echo)
$(_Q)$(RM) $(TARGET) $(DEPS) $(OBJS)
.PHONY: clean
#==============================================================================
# Production recipes
rmprod:
$(color_reset)
@echo
-$(_Q)rm -rf $(if $(filter osx,$(PLATFORM)),$(PRODUCTION_FOLDER_MACOS),$(PRODUCTION_FOLDER))
ifeq ($(PLATFORM),linux)
-$(_Q)rm -rf ~/.local/share/applications/$(NAME).desktop
endif
.PHONY: rmprod
mkdirprod:
$(color_reset)
$(MKDIR) $(PRODUCTION_FOLDER)
.PHONY: mkdirprod
define do_copy_to_clean
@printf "\xE2\x9E\xA6"
@echo " Copying \"$(1)\" to \"$(CURDIR)/$(2)\""
$(shell cp -r $(1) $(2))
endef
define do_copy_to
@echo "cp -r $(1) $(2)"
$(shell cp -r $(1) $(2))
endef
define copy_to
$(if $(wildcard $(2)/$(notdir $(1))),,$(if $(_CLEAN),$(call do_copy_to_clean,$(1),$(2)),$(call do_copy_to,$(1),$(2))))
endef
releasetoprod: $(TARGET)
$(color_reset)
ifeq ($(PLATFORM),osx)
@echo ' Creating the MacOS application bundle...'
@echo
$(MKDIR) $(PRODUCTION_FOLDER)/Resources $(PRODUCTION_FOLDER)/Frameworks $(PRODUCTION_FOLDER)/MacOS
ifeq ($(shell brew ls --versions makeicns),)
brew install makeicns
$(color_reset)
endif
$(_Q)makeicns -in env/osx/$(PRODUCTION_MACOS_ICON).png -out $(PRODUCTION_FOLDER)/Resources/$(PRODUCTION_MACOS_ICON).icns
@echo
$(_Q)plutil -convert binary1 env/osx/Info.plist.json -o $(PRODUCTION_FOLDER)/Info.plist
$(_Q)plutil -replace CFBundleExecutable -string $(NAME) $(PRODUCTION_FOLDER)/Info.plist
$(_Q)plutil -replace CFBundleName -string $(PRODUCTION_MACOS_BUNDLE_NAME) $(PRODUCTION_FOLDER)/Info.plist
$(_Q)plutil -replace CFBundleIconFile -string $(PRODUCTION_MACOS_ICON) $(PRODUCTION_FOLDER)/Info.plist
$(_Q)plutil -replace CFBundleDisplayName -string "$(PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME)" $(PRODUCTION_FOLDER)/Info.plist
$(_Q)plutil -replace CFBundleIdentifier -string com.$(PRODUCTION_MACOS_BUNDLE_DEVELOPER).$(PRODUCTION_MACOS_BUNDLE_NAME) $(PRODUCTION_FOLDER)/Info.plist
$(_Q)cp $(TARGET) $(PRODUCTION_FOLDER)/MacOS
$(_Q)chmod +x $(PRODUCTION_FOLDER)/MacOS/$(NAME)
else ifeq ($(PLATFORM),linux)
$(_Q)cp $(TARGET) $(PRODUCTION_FOLDER)
$(_Q)cp env/linux/$(PRODUCTION_LINUX_ICON).png $(PRODUCTION_FOLDER)/$(PRODUCTION_LINUX_ICON).png
$(_Q)cp env/linux/exec.desktop $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)sed -i 's/^Exec=.*/Exec=$(_LINUX_GREP_CWD)\/$(PRODUCTION_FOLDER)\/$(NAME)/' $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)sed -i 's/^Path=.*/Path=$(_LINUX_GREP_CWD)\/$(PRODUCTION_FOLDER)/' $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)sed -i 's/^Name=.*/Name=$(PRODUCTION_LINUX_APP_NAME)/' $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)sed -i 's/^Comment=.*/Comment=$(PRODUCTION_LINUX_APP_COMMENT)/' $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)sed -i 's/^Icon=.*/Icon=$(_LINUX_GREP_CWD)\/$(PRODUCTION_FOLDER)\/$(PRODUCTION_LINUX_ICON).png/' $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)chmod +x $(PRODUCTION_FOLDER)/$(NAME)
$(_Q)chmod +x $(PRODUCTION_FOLDER)/$(NAME).desktop
$(_Q)cp $(PRODUCTION_FOLDER)/$(NAME).desktop ~/.local/share/applications
else
$(_Q)cp $(TARGET) $(PRODUCTION_FOLDER)
$(if $(_CLEAN),,@echo)
endif
.PHONY: releasetoprod
makeproduction: rmprod mkdirprod releasetoprod
$(color_reset)
ifneq ($(PRODUCTION_DEPENDENCIES),)
@echo ' Adding dynamic libraries & project dependencies...'
@echo
$(foreach dep,$(PRODUCTION_DEPENDENCIES),$(call copy_to,$(dep),$(PRODUCTION_FOLDER_RESOURCES)))
$(foreach excl,$(PRODUCTION_EXCLUDE),$(shell find $(PRODUCTION_FOLDER_RESOURCES) -name '$(excl)' -delete))
endif
ifeq ($(PLATFORM),osx)
$(foreach dylib,$(PRODUCTION_MACOS_DYLIBS),$(call copy_to,$(dylib),$(PRODUCTION_FOLDER)/MacOS))
$(_Q)install_name_tool -add_rpath @executable_path/../Frameworks $(PRODUCTION_FOLDER)/MacOS/$(NAME)
$(_Q)install_name_tool -add_rpath @loader_path/.. $(PRODUCTION_FOLDER)/MacOS/$(NAME)
$(foreach dylib,$(PRODUCTION_MACOS_DYLIBS),$(shell install_name_tool -change $(notdir $(dylib)) @rpath/MacOS/$(notdir $(dylib)) $(PRODUCTION_FOLDER)/MacOS/$(NAME)))
$(foreach framework,$(PRODUCTION_MACOS_FRAMEWORKS),$(call copy_to,$(framework),$(PRODUCTION_FOLDER)/Frameworks))
ifeq ($(PRODUCTION_MACOS_MAKE_DMG),true)
$(shell hdiutil detach /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/ &> /dev/null)
@echo
@echo ' Creating the dmg image for the application...'
@echo
$(_Q)hdiutil create -megabytes 54 -fs HFS+ -volname $(PRODUCTION_MACOS_BUNDLE_NAME) $(PRODUCTION_FOLDER_MACOS)/.tmp.dmg > /dev/null
$(_Q)hdiutil attach $(PRODUCTION_FOLDER_MACOS)/.tmp.dmg > /dev/null
$(_Q)cp -r $(PRODUCTION_FOLDER_MACOS)/$(PRODUCTION_MACOS_BUNDLE_NAME).app /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/
-$(_Q)rm -rf /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/.fseventsd
$(MKDIR) /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/.background
$(_Q)tiffutil -cathidpicheck $(PRODUCTION_MACOS_BACKGROUND).png $(PRODUCTION_MACOS_BACKGROUND)@2x.png -out /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/.background/background.tiff
$(_Q)ln -s /Applications /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/Applications
$(_Q)appName=$(PRODUCTION_MACOS_BUNDLE_NAME) osascript env/osx/dmg.applescript
$(_Q)hdiutil detach /Volumes/$(PRODUCTION_MACOS_BUNDLE_NAME)/ > /dev/null
$(_Q)hdiutil convert $(PRODUCTION_FOLDER_MACOS)/.tmp.dmg -format UDZO -o $(PRODUCTION_FOLDER_MACOS)/$(PRODUCTION_MACOS_BUNDLE_NAME).dmg > /dev/null
$(_Q)rm -f $(PRODUCTION_FOLDER_MACOS)/.tmp.dmg
@echo
@echo ' Created $(PRODUCTION_FOLDER_MACOS)/$(PRODUCTION_MACOS_BUNDLE_NAME).dmg'
endif
endif
.PHONY: makeproduction
#==============================================================================
# Dependency recipes
$(DEP_DIR)/%.d: ;
.PRECIOUS: $(DEP_DIR)/%.d
include $(wildcard $(DEPS))
================================================
FILE: app/src/main/SDL2_SFML.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36408.4 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2_SFML", "SDL2_SFML.vcxproj", "{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Debug|x64.ActiveCfg = Debug|x64
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Debug|x64.Build.0 = Debug|x64
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Debug|x86.ActiveCfg = Debug|Win32
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Debug|x86.Build.0 = Debug|Win32
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Release|x64.ActiveCfg = Release|x64
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Release|x64.Build.0 = Release|x64
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Release|x86.ActiveCfg = Release|Win32
{5F4AA128-1C3B-458F-9B6D-7E140CBE20A5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4BC0C116-C5DF-4722-B40C-C405E183D77F}
EndGlobalSection
EndGlobal
================================================
FILE: app/src/main/SDL2_SFML.vcxproj
================================================
Debug
Win32
Release
Win32
Debug
x64
Release
x64
16.0
Win32Proj
{5f4aa128-1c3b-458f-9b6d-7e140cbe20a5}
SDL2_SFML
10.0
Application
true
v143
Unicode
Application
false
v143
true
Unicode
Application
true
v143
Unicode
Application
false
v143
true
Unicode
Level3
true
IS_ENGINE_SDL_2;IS_ENGINE_VS;_CRT_SECURE_NO_WARNINGS
true
stdcpp20
Console
true
Level3
true
true
true
WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
Console
true
true
true
Level3
true
IS_ENGINE_SDL_2;IS_ENGINE_VS;_CRT_SECURE_NO_WARNINGS
true
C:\SDL2-2.26.3\include;%(AdditionalIncludeDirectories)
stdcpp20
Console
true
C:\SDL2-2.26.3\lib\x64;%(AdditionalLibraryDirectories)
SDL2.lib;SDL2main.lib;SDL2_image.lib;SDL2_mixer.lib;SDL2_ttf.lib;%(AdditionalDependencies)
Level3
true
true
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
Console
true
true
true
================================================
FILE: app/src/main/SDL2_SFML.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
{685a88e6-fbc8-479e-8305-bfd706b9dc45}
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Source Files
Resource Files
================================================
FILE: app/src/main/SDL2_SFML.vcxproj.user
================================================
================================================
FILE: app/src/main/build.sh
================================================
#!/bin/bash
CMD=$1
BUILD=$2
VSCODE=$3
OPTIONS=$4
cwd=${PWD##*/}
export GCC_COLORS="error=01;31:warning=01;33:note=01;36:locus=00;34"
#==============================================================================
# Function declarations
display_styled_symbol() {
tput setaf $1
tput bold
echo "$2 $3"
tput sgr0
}
build_success() {
echo
display_styled_symbol 2 "✔" "Succeeded!"
echo
}
launch() {
display_styled_symbol 2 " " "Launching bin-vscode/$BUILD/$NAME"
echo
}
build_success_launch() {
echo
display_styled_symbol 2 "✔" "Succeeded!"
launch
}
build_fail() {
echo
display_styled_symbol 1 "✘" "Failed!"
display_styled_symbol 1 " " "Review the compile errors above."
echo
tput sgr0
exit 1
}
build_prod_error() {
echo
display_styled_symbol 1 "⭙" "Error: buildprod must be run on Release build."
tput sgr0
exit 1
}
profiler_done() {
echo
display_styled_symbol 2 "⯌" "Profiler Completed: View $PROF_ANALYSIS_FILE for details"
echo
}
profiler_error() {
echo
display_styled_symbol 1 "⭙" "Error: Profiler must be run on Debug build."
tput sgr0
exit 1
}
profiler_osx() {
display_styled_symbol 1 "⭙" "Error: Profiling (with gprof) is not supported on Mac OSX."
tput sgr0
exit 1
}
buildrun() {
display_styled_symbol 3 "⬤" "Build & Run: $BUILD (target: $NAME)"
echo
BLD=$BUILD
if [[ $BUILD == 'Tests' && $1 != 'main' ]]; then
BLD=Release
fi
if $MAKE_EXEC BUILD=$BLD; then
build_success_launch
if [[ $BUILD == 'Tests' ]]; then
bin-vscode/Release/$NAME $OPTIONS
else
bin-vscode/$BUILD/$NAME $OPTIONS
fi
else
build_fail
fi
}
build() {
display_styled_symbol 3 "⬤" "Build: $BUILD (target: $NAME)"
echo
BLD=$BUILD
if [[ $BUILD == 'Tests' && $1 != 'main' ]]; then
BLD=Release
fi
if $MAKE_EXEC BUILD=$BLD; then
build_success
else
build_fail
fi
}
rebuild() {
display_styled_symbol 3 "⬤" "Rebuild: $BUILD (target: $NAME)"
echo
BLD=$BUILD
if [[ $BUILD == 'Tests' && $1 != 'main' ]]; then
BLD=Release
fi
if $MAKE_EXEC BUILD=$BLD rebuild; then
build_success
else
build_fail
fi
}
run() {
display_styled_symbol 3 "⬤" "Run: $BUILD (target: $NAME)"
echo
launch
if [[ $BUILD == 'Tests' ]]; then
bin-vscode/Release/$NAME $OPTIONS
else
bin-vscode/$BUILD/$NAME $OPTIONS
fi
}
buildprod() {
display_styled_symbol 3 "⬤" "Production Build: $BUILD (target: $NAME)"
echo
if [[ $BUILD == 'Release' ]]; then
RECIPE=buildprod
if [[ $1 != 'main' ]]; then
RECIPE=
fi
if $MAKE_EXEC BUILD=$BUILD $RECIPE; then
build_success
else
build_fail
fi
else
build_prod_error
fi
}
profile() {
display_styled_symbol 3 "⬤" "Profile: $BUILD (target: $NAME)"
echo
if [[ $PLATFORM == 'osx' ]]; then
profiler_osx
elif [[ $BUILD == 'Debug' ]]; then
if $MAKE_EXEC BUILD=$BUILD; then
build_success_launch
tput sgr0
bin-vscode/$BUILD/$NAME
tput setaf 4
gprof bin-vscode/Debug/$NAME gmon.out > $PROF_ANALYSIS_FILE 2> /dev/null
profiler_done
else
build_fail
fi
else
profiler_error
fi
}
#==============================================================================
# Environment
if [[ $CMD == '' ]]; then
CMD=buildprod
fi
if [[ $BUILD == '' ]]; then
BUILD=Release
fi
if [[ $OSTYPE == 'linux-gnu'* || $OSTYPE == 'cygwin'* ]]; then
if [[ $OSTYPE == 'linux-gnueabihf' ]]; then
export PLATFORM=rpi
else
export PLATFORM=linux
fi
elif [[ $OSTYPE == 'darwin'* ]]; then
export PLATFORM=osx
elif [[ $OSTYPE == 'msys' || $OSTYPE == 'win32' ]]; then
export PLATFORM=windows
fi
if [[ $VSCODE != 'vscode' ]]; then
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
if [[ $PLATFORM == 'windows' ]]; then
export PATH="/c/SFML/bin:/c/mingw32/bin:$PATH"
else
if [[ $PLATFORM == 'rpi' ]]; then
export PATH="/usr/local/gcc-8.1.0/bin:$PATH"
fi
fi
echo
echo build.sh PATH=$PATH
echo
fi
export MAKE_EXEC=make
if [[ $PLATFORM == 'windows' ]]; then
if [ $(type -P "mingw32-make.exe") ]; then
export MAKE_EXEC=mingw32-make.exe
elif [ $(type -P "make.exe") ]; then
export MAKE_EXEC=make.exe
fi
fi
if [[ $BUILD != "Release" && $BUILD != 'Debug' && $BUILD != 'Tests' ]]; then
BUILD=Release
fi
PROF_EXEC=gprof
PROF_ANALYSIS_FILE=profiler_analysis.stats
#==============================================================================
# Main script
if [[ $BUILD_TARGETS == '' ]]; then
BUILD_TARGETS=main
NO_SRC_TARGET=1
fi
for target in $BUILD_TARGETS; do
if [[ $PLATFORM == 'windows' ]]; then
if [[ $target == 'main' ]]; then
export NAME=$cwd.exe
if [[ $BUILD == 'Tests' ]]; then
NAME=tests_$NAME
fi
else
if [[ $BUILD == 'Debug' ]]; then
export NAME=$target-d.dll
else
export NAME=$target.dll
fi
fi
else
if [[ $target == 'main' ]]; then
export NAME=$cwd
if [[ $BUILD == 'Tests' ]]; then
NAME=tests_$NAME
fi
else
if [[ $BUILD == 'Debug' ]]; then
export NAME=$target-d.so
else
export NAME=$target.so
fi
fi
fi
if [[ $NO_SRC_TARGET != 1 ]]; then
export SRC_TARGET=$target
fi
CHILD_CMD="$CMD $target"
if [[ $CMD == 'buildrun' && $target != 'main' ]]; then
CHILD_CMD=build
fi
tput setaf 4
if $CHILD_CMD ; then
tput sgr0
else
tput setaf 1
tput bold
echo $dec Error: Command \"$CHILD_CMD\" not recognized. $dec
tput sgr0
exit 1
fi
RESULT=$?
if [[ $RESULT != 0 ]]; then
break
fi
done
exit 0
================================================
FILE: app/src/main/cmake/app_src.cmake
================================================
# game source file
set(
app_src
# game system extended
${ISENGINE_SRC_DIR}/GameSystemExtended.cpp
# game scene
# ${ISENGINE_SRC_DIR}/app_src/scenes/...
# game level objects
# ${ISENGINE_SRC_DIR}/app_src/objects/...
# widgets
${ISENGINE_SRC_DIR}/GameDialog.cpp
)
================================================
FILE: app/src/main/cmake/isengine.cmake
================================================
# box 2d source file
set(
box2d_sources
${ISENGINE_SRC_DIR}/b2BroadPhase.cpp
${ISENGINE_SRC_DIR}/b2CollideCircle.cpp
${ISENGINE_SRC_DIR}/b2CollideEdge.cpp
${ISENGINE_SRC_DIR}/b2CollidePolygon.cpp
${ISENGINE_SRC_DIR}/b2Collision.cpp
${ISENGINE_SRC_DIR}/b2Distance.cpp
${ISENGINE_SRC_DIR}/b2DynamicTree.cpp
${ISENGINE_SRC_DIR}/b2TimeOfImpact.cpp
${ISENGINE_SRC_DIR}/b2CircleShape.cpp
${ISENGINE_SRC_DIR}/b2EdgeShape.cpp
${ISENGINE_SRC_DIR}/b2ChainShape.cpp
${ISENGINE_SRC_DIR}/b2PolygonShape.cpp
${ISENGINE_SRC_DIR}/b2BlockAllocator.cpp
${ISENGINE_SRC_DIR}/b2Draw.cpp
${ISENGINE_SRC_DIR}/b2Math.cpp
${ISENGINE_SRC_DIR}/b2Settings.cpp
${ISENGINE_SRC_DIR}/b2StackAllocator.cpp
${ISENGINE_SRC_DIR}/b2Timer.cpp
${ISENGINE_SRC_DIR}/b2Body.cpp
${ISENGINE_SRC_DIR}/b2ContactManager.cpp
${ISENGINE_SRC_DIR}/b2Fixture.cpp
${ISENGINE_SRC_DIR}/b2Island.cpp
${ISENGINE_SRC_DIR}/b2World.cpp
${ISENGINE_SRC_DIR}/b2WorldCallbacks.cpp
${ISENGINE_SRC_DIR}/b2CircleContact.cpp
${ISENGINE_SRC_DIR}/b2Contact.cpp
${ISENGINE_SRC_DIR}/b2ContactSolver.cpp
${ISENGINE_SRC_DIR}/b2PolygonAndCircleContact.cpp
${ISENGINE_SRC_DIR}/b2EdgeAndCircleContact.cpp
${ISENGINE_SRC_DIR}/b2EdgeAndPolygonContact.cpp
${ISENGINE_SRC_DIR}/b2ChainAndCircleContact.cpp
${ISENGINE_SRC_DIR}/b2ChainAndPolygonContact.cpp
${ISENGINE_SRC_DIR}/b2PolygonContact.cpp
${ISENGINE_SRC_DIR}/b2DistanceJoint.cpp
${ISENGINE_SRC_DIR}/b2FrictionJoint.cpp
${ISENGINE_SRC_DIR}/b2GearJoint.cpp
${ISENGINE_SRC_DIR}/b2Joint.cpp
${ISENGINE_SRC_DIR}/b2MotorJoint.cpp
${ISENGINE_SRC_DIR}/b2MouseJoint.cpp
${ISENGINE_SRC_DIR}/b2PrismaticJoint.cpp
${ISENGINE_SRC_DIR}/b2PulleyJoint.cpp
${ISENGINE_SRC_DIR}/b2RevoluteJoint.cpp
${ISENGINE_SRC_DIR}/b2RopeJoint.cpp
${ISENGINE_SRC_DIR}/b2WeldJoint.cpp
${ISENGINE_SRC_DIR}/b2WheelJoint.cpp
)
# engine source file
set(
commun_sources
${ISENGINE_SRC_DIR}/main.cpp
# Basic SFML rendering loop
${ISENGINE_SRC_DIR}/basicSFMLmain.cpp
# core
${ISENGINE_SRC_DIR}/GameEngine.cpp
# islibconnect
${ISENGINE_SRC_DIR}/isEngineWrapper.cpp
${ISENGINE_SRC_DIR}/isEngineSDLWrapper.cpp
# display
${ISENGINE_SRC_DIR}/GameDisplay.cpp
# entity
${ISENGINE_SRC_DIR}/MainObject.cpp
# graphic
${ISENGINE_SRC_DIR}/TransitionEffect.cpp
# function
${ISENGINE_SRC_DIR}/GameFunction.cpp
${ISENGINE_SRC_DIR}/GameKeyData.cpp
${ISENGINE_SRC_DIR}/GameSlider.cpp
${ISENGINE_SRC_DIR}/GameSystem.cpp
${ISENGINE_SRC_DIR}/GameTime.cpp
# box 2d
${box2d_sources}
)
# tmx lite
set(
tmxlite_sources
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/FreeFuncs.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/ImageLayer.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/LayerGroup.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/Map.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/Object.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/ObjectGroup.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/Property.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/TileLayer.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/Tileset.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/detail/pugixml.cpp
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TMXLite/miniz.c
)
# is::Engine Windows & Linux version
if (DEFINED ISENGINE_PC)
set(
isengine
${commun_sources}
${tmxlite_sources}
# tiny file dialogs
${ISENGINE_SRC_DIR}/isEngine/ext_lib/TinyFileDialogs/tinyfiledialogs.cpp
)
# is::Engine Android version
elseif (DEFINED ISENGINE_ANDROID)
set(
isengine
${commun_sources}
${ISENGINE_SRC_DIR}/SDL_android_main.c
#${tmxlite_sources}
)
# is::Engine HTML version
elseif (DEFINED ISENGINE_HTML_5)
set(
isengine
${commun_sources}
)
endif()
================================================
FILE: app/src/main/cmake/resource.rc
================================================
// application icon
MAINICON ICON DISCARDABLE "../env/windows/icon.ico"
================================================
FILE: app/src/main/codeblocks/resource.rc
================================================
// application icon
MAINICON ICON "../env/windows/icon.ico"
================================================
FILE: app/src/main/copy_assets.cmd
================================================
@echo off
setlocal ENABLEEXTENSIONS
REM Define source and destination
set "SOURCE=assets"
set "DEST=romfs"
REM Check if source exists
if not exist "%SOURCE%" (
echo [ERROR] The folder '%SOURCE%' does not exist.
exit /b 1
)
REM Create destination if it doesn't exist
if not exist "%DEST%" (
echo [INFO] The folder '%DEST%' does not exist. Creating it...
mkdir "%DEST%"
)
REM Copy the 'assets' folder itself (and all contents) into 'data'
echo [INFO] Copying the '%SOURCE%' folder into '%DEST%'...
xcopy "%SOURCE%" "%DEST%\%SOURCE%\" /E /I /Y /H >nul
echo [SUCCESS] The folder '%SOURCE%' has been copied to '%DEST%\%SOURCE%\'.
pause
================================================
FILE: app/src/main/cpp/GameDialog.cpp
================================================
#include "app_src/objects/widgets/GameDialog.h"
namespace is
{
GameDialog::GameDialog(sf::Texture &tex, sf::Font &fnt, GameDisplay *m_scene) :
MainObject(),
m_scene(m_scene),
m_showDialog(false),
m_mouseInCollison(false),
m_dialogEnd(false),
m_newLine(true),
m_msgIndex(0),
m_msgIndexMax(0),
m_size(0),
m_blindTime(0.f),
m_dialogIndex(DIALOG_NONE)
{
m_strName = "GameDialog"; // object name
m_imageScale = 0.f;
is::createText(fnt, m_txtDialog, "", m_x, m_y, is::GameConfig::DEFAULT_RPG_DIALOG_TEXT_COLOR, is::GameConfig::DEFAULT_RPG_DIALOG_TEXT_SIZE);
is::createText(fnt, m_txtSkip, is::lang::pad_dialog_skip[m_scene->getGameSystem().m_gameLanguage],
m_x, m_y, is::GameConfig::DEFAULT_RPG_DIALOG_SELECTED_TEXT_COLOR, true, is::GameConfig::DEFAULT_RPG_DIALOG_BUTTON_TEXT_SIZE);
m_strDialog = "";
is::createSprite(tex, m_sprParent, sf::IntRect(0, 0, 480, 96), sf::Vector2f(0.f, 0.f), sf::Vector2f(240.f, 48.f));
is::createSprite(tex, m_sprNext, sf::IntRect(64, 96, 32, 32), sf::Vector2f(0.f, 0.f), sf::Vector2f(16.f, 16.f));
is::createSprite(tex, m_sprSkip, sf::IntRect(0, 96, 64, 24), sf::Vector2f(0.f, 0.f), sf::Vector2f(32.f, 12.f));
is::setSFMLObjScale(m_txtDialog, 0.f);
is::centerSFMLObj(m_txtSkip);
is::setSFMLObjScale(m_txtSkip, 0.f);
is::setSFMLObjScale(m_sprParent, 0.f);
is::setSFMLObjScale(m_sprNext, 0.f);
}
void GameDialog::step(const float &DELTA_TIME)
{
if (m_showDialog)
{
if (!m_scene->getGameSystem().keyIsPressed(is::GameConfig::KEY_A) && !m_scene->getGameSystem().isPressed(is::GameSystem::MOUSE))
m_scene->getGameSystem().m_keyIsPressed = false;
setPosition(m_scene->getViewX(), m_scene->getViewY() + 32.f);
float const _VAL(is::getMSecond(DELTA_TIME));
m_time += (0.8f * is::VALUE_CONVERSION) * DELTA_TIME;
m_blindTime += _VAL;
if (m_blindTime > 30.f) m_blindTime = 0.f;
auto getDialogChar = [this](int index = -1)
{
int n = m_strDialog.length();
wchar_t* char_array = new wchar_t[n + 1];
for (int i(0); i < n; i++) char_array[i] = m_strDialog[i];
auto my_char = char_array[((index == -1) ? m_size + 1: index)];
delete[] char_array;
return my_char;
};
linkArrayToEnum();
if (m_size < static_cast(m_strDialog.size()) - 1)
{
if (m_time > 1.f)
{
std::wstring tempoStr = m_txtDialog.
#if !defined(IS_ENGINE_SFML)
getWString();
#else
getString();
#endif
if (m_newLine)
{
m_scene->GSMplaySound("change_option"); // We play this sound
m_txtDialog.setString(getDialogChar(0));
m_newLine = false;
}
else
{
m_txtDialog.setString(tempoStr + getDialogChar());
m_size++;
}
m_time = 0.f;
}
}
bool mouseInCollisonSkip(false);
if (m_scene->mouseCollision(m_sprSkip)) mouseInCollisonSkip = true;
if (m_scene->getGameSystem().isPressed(is::GameSystem::ValidationButton::MOUSE) && mouseInCollisonSkip &&
!m_dialogEnd)
{
m_scene->GSMplaySound("cancel"); // We play this sound
m_scene->getGameSystem().useVibrate(60);
m_dialogEnd = true;
}
m_mouseInCollison = m_scene->mouseCollision(m_sprParent);
if (!m_mouseInCollison && m_scene->getGameSystem().isPressed(is::GameSystem::MOUSE))
m_scene->getGameSystem().m_keyIsPressed = true;
if ((m_scene->getGameSystem().keyIsPressed(is::GameConfig::KEY_A) ||
(m_scene->getGameSystem().isPressed(is::GameSystem::ValidationButton::MOUSE) && m_mouseInCollison)) &&
!m_scene->getGameSystem().m_keyIsPressed && !m_dialogEnd)
{
m_scene->getGameSystem().m_keyIsPressed = true;
m_scene->getGameSystem().useVibrate(60);
if (m_size < static_cast(m_strDialog.size()) - 1)
{
m_txtDialog.setString(m_strDialog);
m_size = static_cast(m_strDialog.size()) - 1;
}
else
{
m_msgIndex += 2;
if (m_msgIndex == m_msgIndexMax)
{
m_scene->GSMplaySound("cancel"); // We play this sound
m_dialogEnd = true;
}
else
{
m_newLine = true;
m_size = 0;
m_txtDialog.setString("");
}
}
}
if (!m_dialogEnd) is::increaseVar(DELTA_TIME, m_imageScale, 0.1f, 1.f, 1.f);
else
{
is::decreaseVar(DELTA_TIME, m_imageScale, 0.1f, 0.f, 0.f);
if (m_imageScale < 0.05f) m_showDialog = false;
}
is::setSFMLObjX_Y(m_sprParent, m_x, m_y - 90.f);
is::setSFMLObjX_Y(m_txtDialog, is::getSFMLObjX(m_sprParent) - 225.f,
is::getSFMLObjY(m_sprParent) - 38.f);
is::setSFMLObjX_Y(m_sprNext, is::getSFMLObjX(m_sprParent) + 220.f,
is::getSFMLObjY(m_sprParent) + 29.f);
is::setSFMLObjX_Y(m_sprSkip, m_x, m_y + 145.f);
is::setSFMLObjX_Y(m_txtSkip, m_x, is::getSFMLObjY(m_sprSkip));
}
is::setSFMLObjScale(m_txtDialog, m_imageScale);
is::setSFMLObjScale(m_txtSkip, m_imageScale);
is::setSFMLObjScale(m_sprSkip, m_imageScale);
is::setSFMLObjScale(m_sprParent, m_imageScale);
is::setSFMLObjScale(m_sprNext, m_imageScale);
}
void GameDialog::setDialog(DialogIndex dialogIndex)
{
m_dialogEnd = false;
m_msgIndex = 0;
m_size = 0;
m_dialogIndex = dialogIndex;
m_strDialog = "";
m_txtDialog.setString("");
m_showDialog = true;
m_newLine = true;
}
void GameDialog::setMouseInCollison(bool val)
{
m_mouseInCollison = val;
}
void GameDialog::draw(is::Render &surface)
{
if (m_imageScale > 0.05)
{
is::draw(surface, m_sprParent);
is::draw(surface, m_txtDialog);
is::draw(surface, m_txtSkip);
is::draw(surface, m_sprSkip);
if (m_blindTime < 18.f && m_size == (static_cast(m_strDialog.size()) - 1)) is::draw(surface, m_sprNext);
}
}
}
================================================
FILE: app/src/main/cpp/GameDisplay.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/display/GameDisplay.h"
#include "app_src/language/GameLanguage.h"
namespace is
{
sf::Vector2f getMapPixelToCoords(GameDisplay const *scene, sf::Vector2i pixelPos)
{
return scene->getRenderWindow().mapPixelToCoords(pixelPos, scene->getView());
}
GameDisplay::GameDisplay(GameSystemExtended &gameSysExt, sf::Color bgColor) :
m_isClosed(false),
m_window(gameSysExt.m_window),
m_view(sf::Vector2f(is::GameConfig::VIEW_WIDTH / 2.f,
is::GameConfig::VIEW_HEIGHT / 2.f),
sf::Vector2f(is::GameConfig::VIEW_WIDTH, is::GameConfig::VIEW_HEIGHT)),
m_surface(gameSysExt.m_window),
m_gameSysExt(gameSysExt),
m_timeVibrateDuration(40),
m_optionIndex(0),
m_waitTime(0),
m_msgWaitTime(0),
m_sceneWidth(is::GameConfig::VIEW_WIDTH),
m_sceneHeight(is::GameConfig::VIEW_HEIGHT),
DELTA_TIME(0.f),
m_viewW(is::GameConfig::VIEW_WIDTH),
m_viewH(is::GameConfig::VIEW_HEIGHT),
m_viewX(m_viewW / 2.f),
m_viewY(m_viewH / 2.f),
m_sprButtonSelectScale(1.f),
m_isRunning(true),
m_windowIsActive(true),
m_isPlaying(true),
m_sceneStart(true),
m_sceneEnd(false),
m_keyBackPressed(false),
m_showMsg(false),
m_mbYesNo(false),
m_msgBoxMouseInCollision(false),
m_mouseInCollision(false)
{
setViewSize(m_viewW, m_viewH);
setView(m_viewX, m_viewY);
m_windowBgColor = bgColor;
}
GameDisplay::~GameDisplay() {}
void GameDisplay::setOptionIndex(int optionIndexValue, bool callWhenClick, float buttonScale)
{
if (m_waitTime == 0) {
m_gameSysExt.useVibrate(m_timeVibrateDuration);
GSMplaySound("change_option");
m_sprButtonSelectScale = buttonScale;
if (!callWhenClick) {
m_optionIndex += optionIndexValue;
m_gameSysExt.m_keyIsPressed = true;
} else m_optionIndex = optionIndexValue;
}
}
void GameDisplay::setOptionIndex(int optionIndexValue)
{
m_optionIndex = optionIndexValue;
}
void GameDisplay::setTextAnimation(sf::Text &txt, sf::Sprite &spr, int val)
{
if (m_optionIndex == val)
{
is::setSFMLObjX_Y(m_sprButtonSelect, is::getSFMLObjX(spr), is::getSFMLObjY(spr));
is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_SELECTED_TEXT_COLOR);
}
else is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_TEXT_COLOR);
}
void GameDisplay::setSprButtonSelectScale(float val)
{
m_sprButtonSelectScale = val;
}
void GameDisplay::setView(sf::Vector2f v)
{
m_view.setCenter(v.x, v.y);
m_surface.setView(m_view);
}
void GameDisplay::setView(float x, float y)
{
m_view.setCenter(x, y);
m_surface.setView(m_view);
}
void GameDisplay::setView()
{
m_view.setCenter(m_viewX, m_viewY);
m_surface.setView(m_view);
}
void GameDisplay::setViewVarX(float val)
{
m_viewX = val;
}
void GameDisplay::setViewVarY(float val)
{
m_viewY = val;
}
void GameDisplay::setViewVarXY(float x, float y)
{
m_viewX = x;
m_viewY = y;
}
void GameDisplay::setViewSize(sf::Vector2f v)
{
m_view.setSize(v.x, v.y);
}
void GameDisplay::setViewSize(float x, float y)
{
m_view.setSize(x, y);
}
void GameDisplay::setWindowSize(sf::Vector2u v, bool updateViewSize)
{
#if defined(__ANDROID__)
m_window.setSize(v);
if (updateViewSize) {
m_viewW = v.x;
m_viewH = v.y;
m_viewX = m_viewW / 2.f;
m_viewY = m_viewH / 2.f;
m_view.setSize(m_viewW, m_viewH);
m_view.setCenter(m_viewX, m_viewY);
m_window.setView(m_view);
m_surface.setView(m_view);
}
#endif
}
void GameDisplay::setWindowTitle(const std::string &title)
{
m_window.setTitle(title);
}
void GameDisplay::setWindowBgColor(sf::Color color)
{
m_windowBgColor = color;
}
void GameDisplay::controlEventFocusClosing(sf::Event &event)
{
// Manage the state of window
if (event.type == sf::Event::GainedFocus) m_windowIsActive = true;
if (event.type == sf::Event::LostFocus) m_windowIsActive = false;
// Closing the application
if (event.type == sf::Event::Closed)
{
m_isRunning = false; // quit the main render loop
m_window.close();
}
}
void GameDisplay::showMessageBox(const std::string &msgBody, bool mbYesNo)
{
setMessageBoxData(mbYesNo);
m_txtMsgBox.setString(msgBody);
}
void GameDisplay::showMessageBox(std::wstring const &msgBody, bool mbYesNo)
{
setMessageBoxData(mbYesNo);
m_txtMsgBox.setString(msgBody);
}
void GameDisplay::setWidgetsPosition()
{
setSFMLObjX_Y(m_recMsgBox, sf::Vector2f(m_view.getCenter().x, m_view.getCenter().y));
setSFMLObjX_Y(m_sprMsgBox, sf::Vector2f(m_view.getCenter().x, m_view.getCenter().y));
const float dim(6.f),
boxXOrigin(is::getSFMLObjOriginX(m_sprMsgBox)),
boxYOrigin(is::getSFMLObjOriginY(m_sprMsgBox));
setSFMLObjX_Y(m_sprMsgBoxButton1,
is::getSFMLObjX(m_sprMsgBox) - boxXOrigin +
is::getSFMLObjOriginX(m_sprMsgBoxButton1) + dim,
is::getSFMLObjY(m_sprMsgBox) + boxYOrigin -
is::getSFMLObjHeight(m_sprMsgBoxButton1) + dim);
setSFMLObjX_Y(m_sprMsgBoxButton2,
is::getSFMLObjX(m_sprMsgBox) + boxXOrigin -
is::getSFMLObjOriginX(m_sprMsgBoxButton2) - dim,
is::getSFMLObjY(m_sprMsgBox) + boxYOrigin -
is::getSFMLObjHeight(m_sprMsgBoxButton2) + dim);
setSFMLObjX_Y(m_sprMsgBoxButton3,
is::getSFMLObjX(m_sprMsgBox),
is::getSFMLObjY(m_sprMsgBox) + boxYOrigin -
is::getSFMLObjHeight(m_sprMsgBoxButton1) + dim);
setSFMLObjX_Y(m_txtMsgBox,
is::getSFMLObjX(m_sprMsgBox) - boxXOrigin + 16.f,
is::getSFMLObjY(m_sprMsgBox) - boxYOrigin + 8.f);
// Adjust the text on button
setSFMLObjX_Y(m_txtMsgBoxYes, is::getSFMLObjX(m_sprMsgBoxButton1),
is::getSFMLObjY(m_sprMsgBoxButton1)
#if defined(IS_ENGINE_SFML)
- is::getSFMLObjHeight(m_txtMsgBoxYes) / 4.f
#endif
);
setSFMLObjX_Y(m_txtMsgBoxNo, is::getSFMLObjX(m_sprMsgBoxButton2),
is::getSFMLObjY(m_sprMsgBoxButton2)
#if defined(IS_ENGINE_SFML)
- is::getSFMLObjHeight(m_txtMsgBoxNo) / 4.f
#endif
);
setSFMLObjX_Y(m_txtMsgBoxOK, is::getSFMLObjX(m_sprMsgBoxButton3),
is::getSFMLObjY(m_sprMsgBoxButton3)
#if defined(IS_ENGINE_SFML)
- is::getSFMLObjHeight(m_txtMsgBoxOK) / 4.f
#endif
);
}
void GameDisplay::setMessageBoxData(bool mbYesNo)
{
m_showMsg = true;
m_mbYesNo = mbYesNo;
if (m_mbYesNo) m_msgAnswer = MsgAnswer::NO;
m_msgWaitTime = 0;
m_msgBoxMouseInCollision = false;
m_txtMsgBoxYes.setString(is::lang::pad_answer_yes[m_gameSysExt.m_gameLanguage]);
m_txtMsgBoxNo.setString(is::lang::pad_answer_no[m_gameSysExt.m_gameLanguage]);
m_txtMsgBoxOK.setString(is::lang::pad_answer_ok[m_gameSysExt.m_gameLanguage]);
centerSFMLObj(m_txtMsgBoxYes);
centerSFMLObj(m_txtMsgBoxNo);
centerSFMLObj(m_txtMsgBoxOK);
setView();
setWidgetsPosition();
is::setSFMLObjAlpha(m_sprMsgBoxButton1, m_msgWaitTime);
is::setSFMLObjAlpha(m_sprMsgBoxButton2, m_msgWaitTime);
is::setSFMLObjAlpha(m_sprMsgBoxButton3, m_msgWaitTime);
is::setSFMLObjAlpha(m_sprMsgBox, m_msgWaitTime);
is::setSFMLObjAlpha2(m_txtMsgBoxNo, m_msgWaitTime);
is::setSFMLObjAlpha2(m_txtMsgBoxYes, m_msgWaitTime);
is::setSFMLObjAlpha2(m_txtMsgBoxOK, m_msgWaitTime);
is::setSFMLObjAlpha2(m_txtMsgBox, m_msgWaitTime);
}
void GameDisplay::updateMsgBox(int sliderDirection, bool rightSideValidation,
sf::Color textDefaultColor, sf::Color selectedTextColor)
{
if (m_msgWaitTime < 240) m_msgWaitTime += static_cast((8.f * is::VALUE_CONVERSION) * DELTA_TIME);
else m_msgWaitTime = 255;
if (!m_gameSysExt.isPressed()) m_gameSysExt.m_keyIsPressed = false;
// Check collision with all objects of message box
if (mouseCollision(m_sprMsgBoxButton1, m_mousePosCurrent) ||
mouseCollision(m_sprMsgBoxButton2, m_mousePosCurrent) ||
mouseCollision(m_sprMsgBoxButton3))
m_msgBoxMouseInCollision = true;
else m_msgBoxMouseInCollision = false;
/*
* sliderDirection is the enum variable found in is::GameSlider. It was not called from the instance
* because its use is not mandatory in a Scene. This avoids the error message which implies that the
* instance has not been declared because here we have implemented are not used in even if it does not exist
* These different values (represents the enum of the class)
SLIDE_NONE = 0,
SLIDE_UP = 1,
SLIDE_DOWN = 2,
SLIDE_RIGHT = 3,
SLIDE_LEFT = 4
*/
// Avoid the long pressing button effect
if (!m_msgBoxMouseInCollision && sliderDirection == 0 &&
m_gameSysExt.isPressed(is::GameSystem::MOUSE))
m_gameSysExt.m_keyIsPressed = true;
if (m_msgWaitTime == 255 && m_windowIsActive)
{
// If it's YES / NO message box
if (m_mbYesNo)
{
if ((m_gameSysExt.keyIsPressed(is::GameConfig::KEY_LEFT) || (sliderDirection == 4) ||
(mouseCollision(m_sprMsgBoxButton1, m_mousePosCurrent) && m_mousePosPrevious != m_mousePosCurrent)) &&
m_msgAnswer != MsgAnswer::YES)
{
if (m_msgBoxMouseInCollision) m_mousePosPrevious = m_mousePosCurrent;
m_gameSysExt.useVibrate(m_timeVibrateDuration);
GSMplaySound("change_option");
m_msgAnswer = MsgAnswer::YES; // answer = yes
}
else if ((m_gameSysExt.keyIsPressed(is::GameConfig::KEY_RIGHT) || (sliderDirection == 3) ||
(mouseCollision(m_sprMsgBoxButton2, m_mousePosCurrent) && m_mousePosPrevious != m_mousePosCurrent)) &&
m_msgAnswer != MsgAnswer::NO)
{
if (m_msgBoxMouseInCollision) m_mousePosPrevious = m_mousePosCurrent;
m_gameSysExt.useVibrate(m_timeVibrateDuration);
GSMplaySound("change_option");
m_msgAnswer = MsgAnswer::NO; // answer = no
}
else if (m_gameSysExt.isPressed(is::GameSystem::KEYBOARD) || (rightSideValidation) ||
((mouseCollision(m_sprMsgBoxButton1, m_mousePosCurrent) ||
mouseCollision(m_sprMsgBoxButton2, m_mousePosCurrent)) &&
m_gameSysExt.isPressed(is::GameSystem::MOUSE) && !m_gameSysExt.m_keyIsPressed))
{
m_showMsg = false;
m_gameSysExt.m_keyIsPressed = true;
}
else if (m_keyBackPressed)
{
m_msgAnswer = MsgAnswer::NO; // answer = no (canceled)
m_showMsg = false;
m_keyBackPressed = false;
}
// Texts animations
if (m_msgAnswer == MsgAnswer::YES)
{
is::setSFMLObjFillColor(m_txtMsgBoxYes, selectedTextColor);
is::setSFMLObjFillColor(m_txtMsgBoxNo, textDefaultColor);
}
else
{
is::setSFMLObjFillColor(m_txtMsgBoxNo, selectedTextColor);
is::setSFMLObjFillColor(m_txtMsgBoxYes, textDefaultColor);
}
}
else // If it's OK message box
{
if (mouseCollision(m_sprMsgBoxButton3) && m_msgAnswer == MsgAnswer::NO)
{
m_gameSysExt.useVibrate(m_timeVibrateDuration);
GSMplaySound("change_option");
m_msgAnswer = MsgAnswer::YES; // answer = OK
is::setSFMLObjFillColor(m_txtMsgBoxOK, selectedTextColor);
}
else if (((m_gameSysExt.isPressed(is::GameSystem::KEYBOARD) || m_keyBackPressed) &&
!mouseCollision(m_sprMsgBoxButton3)) || (rightSideValidation)|| (mouseCollision(m_sprMsgBoxButton3) &&
m_gameSysExt.isPressed(is::GameSystem::MOUSE) && !m_gameSysExt.m_keyIsPressed))
{
m_showMsg = false;
m_keyBackPressed = false;
m_gameSysExt.m_keyIsPressed = true;
}
else if (!mouseCollision(m_sprMsgBoxButton3) && m_msgAnswer == MsgAnswer::YES)
{
m_msgAnswer = MsgAnswer::NO; // answer = NO
is::setSFMLObjFillColor(m_txtMsgBoxOK, textDefaultColor);
}
}
}
if (m_msgWaitTime != 255)
{
if (m_mbYesNo)
{
is::setSFMLObjColor(m_sprMsgBoxButton1, sf::Color(255, 255, 255, m_msgWaitTime));
is::setSFMLObjColor(m_sprMsgBoxButton2, sf::Color(255, 255, 255, m_msgWaitTime));
is::setSFMLObjFillColor(m_txtMsgBoxNo, sf::Color(selectedTextColor.r, selectedTextColor.g, selectedTextColor.b, m_msgWaitTime));
is::setSFMLObjFillColor(m_txtMsgBoxYes, sf::Color(textDefaultColor.r, textDefaultColor.g, textDefaultColor.b, m_msgWaitTime));
}
else
{
is::setSFMLObjColor(m_sprMsgBoxButton3, sf::Color(255, 255, 255, m_msgWaitTime));
is::setSFMLObjFillColor(m_txtMsgBoxOK, sf::Color(textDefaultColor.r, textDefaultColor.g, textDefaultColor.b, m_msgWaitTime));
}
}
is::setSFMLObjColor(m_sprMsgBox, sf::Color(255, 255, 255, m_msgWaitTime));
is::setSFMLObjFillColor(m_txtMsgBox, sf::Color(textDefaultColor.r, textDefaultColor.g, textDefaultColor.b, m_msgWaitTime));
if (!m_showMsg)
{
if (m_msgAnswer == MsgAnswer::NO)
{
// If is OK message box the answer is automatically YES
if (!m_mbYesNo)
{
m_msgAnswer = MsgAnswer::YES;
GSMplaySound("select_option");
m_gameSysExt.useVibrate(m_timeVibrateDuration);
}
else GSMplaySound("cancel");
}
else
{
GSMplaySound("select_option");
m_gameSysExt.useVibrate(m_timeVibrateDuration);
}
}
}
void GameDisplay::updateTimeWait()
{
// Waiting time before validating an option
if (m_waitTime > 0)
{
m_waitTime -= is::getMSecond(DELTA_TIME);
}
else m_waitTime = 0;
}
void GameDisplay::drawMsgBox()
{
if (m_showMsg)
{
is::draw(m_surface, m_recMsgBox);
is::draw(m_surface, m_sprMsgBox);
if (m_mbYesNo)
{
is::draw(m_surface, m_sprMsgBoxButton1);
is::draw(m_surface, m_sprMsgBoxButton2);
is::draw(m_surface, m_txtMsgBoxYes);
is::draw(m_surface, m_txtMsgBoxNo);
}
else
{
is::draw(m_surface, m_sprMsgBoxButton3);
is::draw(m_surface, m_txtMsgBoxOK);
}
is::draw(m_surface, m_txtMsgBox);
}
}
void GameDisplay::drawScreen()
{
is::clear(m_surface, m_windowBgColor);
#if defined(__ANDROID__)
// On Android when the window is no longer active, nothing is displayed just a black screen.
// Its allows to optimize the application
if (m_windowIsActive)
{
#endif
draw();
#if defined(__ANDROID__)
}
#endif
is::display(m_window);
}
void GameDisplay::showTempLoading(float time)
{
float timeToQuit(0.f);
sf::Sprite sprTmploading, sprTmploading2;
is::createSprite(GRMgetTexture("temp_loading"), sprTmploading, sf::Vector2f(m_viewX, m_viewY), sf::Vector2f(320.f, 240.f));
is::createSprite(GRMgetTexture("loading_icon"), sprTmploading2, sf::Vector2f(m_viewX, m_viewY), sf::Vector2f(16.f, 16.f));
while (timeToQuit < time)
{
float dTime = getDeltaTime();
timeToQuit += is::getMSecond(dTime);
sprTmploading2.rotate((5.f * is::VALUE_CONVERSION) * dTime);
sf::Event ev;
while (m_window.pollEvent(ev))
{
if (ev.type == sf::Event::Closed) is::closeApplication();
}
is::clear(m_window, sf::Color::Black);
is::draw(m_surface, sprTmploading);
is::draw(m_surface, sprTmploading2);
is::display(m_window);
}
}
void GameDisplay::loadParentResources()
{
if (!m_gameSysExt.m_loadParentResources)
{
// Load sound
m_gameSysExt.GSMaddSound("change_option", is::GameConfig::SFX_DIR + "change_option" + SND_FILE_EXTENSION);
m_gameSysExt.GSMaddSound("cancel", is::GameConfig::SFX_DIR + "cancel" + SND_FILE_EXTENSION);
m_gameSysExt.GSMaddSound("select_option", is::GameConfig::SFX_DIR + "select_option" + SND_FILE_EXTENSION);
// Load message box sprite
m_gameSysExt.GRMaddTexture("confirm_box", is::GameConfig::GUI_DIR + "confirm_box.png");
m_gameSysExt.GRMaddTexture("confirm_box_button", is::GameConfig::GUI_DIR + "confirm_box_button.png");
// Temporal loading texture
m_gameSysExt.GRMaddTexture("temp_loading", is::GameConfig::GUI_DIR + "temp_loading.png");
m_gameSysExt.GRMaddTexture("loading_icon", is::GameConfig::GUI_DIR + "loading_icon.png");
// Load font
m_gameSysExt.GRMaddFont("font_system", GameConfig::FONT_DIR + "font_system.ttf");
m_gameSysExt.GRMaddFont("font_msg", GameConfig::FONT_DIR + "font_msg.ttf");
m_gameSysExt.m_loadParentResources = true;
}
if (m_gameSysExt.m_loadParentResources)
{
GRMuseGameSystemFont();
GRMuseGameSystemTexture();
GSMuseGameSystemSound();
}
auto &texMsgButton = GRMgetTexture("confirm_box_button");
is::createSprite(GRMgetTexture("confirm_box"), m_sprMsgBox, sf::Vector2f(0.f, 0.f), sf::Vector2f(0.f, 0.f));
is::createSprite(texMsgButton, m_sprMsgBoxButton1, sf::Vector2f(0.f, 0.f), sf::Vector2f(0.f, 0.f));
is::createSprite(texMsgButton, m_sprMsgBoxButton2, sf::Vector2f(0.f, 0.f), sf::Vector2f(0.f, 0.f));
is::createSprite(texMsgButton, m_sprMsgBoxButton3, sf::Vector2f(0.f, 0.f), sf::Vector2f(0.f, 0.f));
is::createRectangle(m_recMsgBox, sf::Vector2f(m_viewW + 40.f, m_viewH + 40.f), sf::Color(0, 0, 0, 200), 0.f, 0.f);
is::centerSFMLObj(m_sprMsgBox);
is::centerSFMLObj(m_sprMsgBoxButton1);
is::centerSFMLObj(m_sprMsgBoxButton2);
is::centerSFMLObj(m_sprMsgBoxButton3);
// Load font
auto &fontSystem = GRMgetFont("font_system");
is::createText(fontSystem, m_txtMsgBox, "", 0.f, 0.f, is::GameConfig::DEFAULT_MSG_BOX_TEXT_SIZE);
#if defined(IS_ENGINE_SDL_2)
m_txtMsgBox.m_SDLaddTextRecWSize += 32;
#endif
is::createText(fontSystem, m_txtMsgBoxYes, is::lang::pad_answer_yes[m_gameSysExt.m_gameLanguage],
0.f, 0.f, true, is::GameConfig::DEFAULT_MSG_BOX_BUTTON_TEXT_SIZE);
is::createText(fontSystem, m_txtMsgBoxNo, is::lang::pad_answer_no[m_gameSysExt.m_gameLanguage],
0.f, 0.f, true, is::GameConfig::DEFAULT_MSG_BOX_BUTTON_TEXT_SIZE);
is::createText(fontSystem, m_txtMsgBoxOK, is::lang::pad_answer_ok[m_gameSysExt.m_gameLanguage],
0.f, 0.f, true, is::GameConfig::DEFAULT_MSG_BOX_BUTTON_TEXT_SIZE);
is::createSprite(GRMgetTexture("temp_loading"), m_sprLoading, sf::Vector2f(m_viewX, m_viewY), sf::Vector2f(320.f, 240.f));
}
void GameDisplay::setIsRunning(bool val)
{
m_isRunning = val;
}
void GameDisplay::setIsPlaying(bool val)
{
m_isPlaying = val;
}
void GameDisplay::quitScene(int nextScene)
{
if (nextScene != -1)
{
m_gameSysExt.m_launchOption = static_cast(nextScene);
m_isRunning = false;
}
else is::closeApplication();
}
void GameDisplay::setWaitTime(int val)
{
m_waitTime = val;
}
void GameDisplay::setSceneStart(bool val)
{
m_sceneStart = val;
}
void GameDisplay::setSceneEnd(bool val)
{
m_sceneEnd = val;
}
void GameDisplay::setKeyBackPressed(bool val)
{
m_keyBackPressed = val;
}
void GameDisplay::setMouseInCollision()
{
if (m_mousePosCurrent != m_mousePosPrevious)
{
is::setVector2(m_mousePosPrevious, m_mousePosCurrent.x, m_mousePosCurrent.y);
m_mouseInCollision = true;
}
}
float GameDisplay::getDeltaTime()
{
float dt = m_clock.restart().asSeconds();
if (dt > is::MAX_CLOCK_TIME) dt = is::MAX_CLOCK_TIME;
return dt;
}
sf::Vector2f GameDisplay::getCursor(unsigned int finger) const
{
return is::getCursor(m_window, finger);
}
bool GameDisplay::getMouseCurrentEqualToPrevious()
{
return (m_mousePosCurrent == m_mousePosPrevious);
}
bool GameDisplay::inViewRec(is::MainObject *obj, bool useTexRec)
{
is::Rectangle testRec;
if (useTexRec)
{
testRec.m_left = obj->getX();
testRec.m_top = obj->getY();
testRec.m_right = obj->getX() + is::getSFMLObjWidth(obj->getSprite());
testRec.m_bottom = obj->getY() + is::getSFMLObjHeight(obj->getSprite());
}
else testRec = obj->getMask();
bool isCollision = false;
is::Rectangle viewRec;
viewRec.m_left = getViewX() - (getViewW() / 2) - 16;
viewRec.m_right = getViewX() + (getViewW() / 2) + 16;
viewRec.m_top = getViewY() - (getViewH() / 2);
viewRec.m_bottom = getViewY() + (getViewH() / 2);
if (is::collisionTest(testRec, viewRec))
{
isCollision = true;
}
return isCollision;
}
bool GameDisplay::inViewRec(is::MainObject &obj, bool useTexRec)
{
return (inViewRec(&obj, useTexRec));
}
bool GameDisplay::getIsRunning() const
{
return m_isRunning;
}
#if defined(IS_ENGINE_USE_SDM)
void GameDisplay::SDMmanageScene()
{
DELTA_TIME = getDeltaTime();
updateTimeWait();
// even loop
SDMmanageSceneEvents();
// starting mechanism
if (m_sceneStart)
{
// window has focus
if (m_windowIsActive)
{
if (!m_showMsg)
{
SDMstep();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// MESSAGE BOX
//////////////////////////////////////////////////////////////////////////////////////////////////////
else
{
updateMsgBox(0, false);
// when user closes message box in update function execute this instruction
// "m_waitTime" allow to disable clicks on objects during a moment when user closes message box
if (!m_showMsg) SDMmanageSceneMsgAnswers();
}
}
}
}
void GameDisplay::SDMmanageSceneEvents()
{
sf::Event event;
while (m_window.pollEvent(event)) // even loop
{
controlEventFocusClosing(event);
if (m_gameSysExt.keyIsPressed(is::GameConfig::KEY_CANCEL))
{
if (!m_showMsg) showMessageBox(is::lang::msg_quit_game[m_gameSysExt.m_gameLanguage]);
else if (m_msgWaitTime == 255) /* Allows to close the message box with the Cancel key when it is visible*/ m_keyBackPressed = true;
}
SDMcallObjectsEvents(event);
}
}
void GameDisplay::SDMmanageSceneMsgAnswers()
{
if (m_msgAnswer == MsgAnswer::YES) // if answers is YES close application
{
m_window.close();
m_isRunning = false;
}
else // if answers is NO continue execution
{
m_waitTime = 20;
}
}
void GameDisplay::SDMcallObjectsEvents(sf::Event &event)
{
if (m_SDMObjectsEvent)
{
// call objects events
for (std::list>::iterator it = m_SDMsceneObjects.begin();
it != m_SDMsceneObjects.end(); ++it)
{
if (is::instanceExist(*it))
{
if ((*it)->m_SDMcallEvent)
{
(*it)->event(event);
}
}
}
}
}
void GameDisplay::SDMstep()
{
if (m_SDMObjectsStep)
{
// update scene objects
for (std::list>::iterator it = m_SDMsceneObjects.begin();
it != m_SDMsceneObjects.end(); ++it)
{
if (is::instanceExist(*it))
{
if ((*it)->m_SDMcallStep)
{
(*it)->step(DELTA_TIME);
}
if (*it != nullptr)
{
if ((*it)->isDestroyed())
{
it->reset();
}
}
}
}
if (m_SDMsortArray)
{
is::sortObjArrayByDepth(m_SDMsceneObjects);
m_SDMsortArray = false;
}
}
}
void GameDisplay::SDMdraw()
{
if (m_SDMObjectsDraw)
{
#if defined(IS_ENGINE_SDL_2)
std::shared_ptr obj = nullptr;
#endif
// draw scene objects
for (std::list>::iterator it = m_SDMsceneObjects.begin();
it != m_SDMsceneObjects.end(); ++it)
{
if (is::instanceExist(*it))
{
if ((*it)->m_SDMcallDraw)
{
if ((*it)->m_SDMblitSprTextureName != "")
{
#if defined(IS_ENGINE_SDL_2)
if (obj.get() != nullptr)
{
if (obj->m_strTextureName != (*it)->m_SDMblitSprTextureName)
{
for (unsigned int i(0); i < m_SDMblitSDLSprite.size(); ++i)
{
if (m_SDMblitSDLSprite[i]->m_strTextureName == (*it)->m_SDMblitSprTextureName)
{
obj = m_SDMblitSDLSprite[i];
break;
}
}
}
}
else
{
for (unsigned int i(0); i < m_SDMblitSDLSprite.size(); ++i)
{
if (m_SDMblitSDLSprite[i]->m_strTextureName == (*it)->m_SDMblitSprTextureName)
{
obj = m_SDMblitSDLSprite[i];
break;
}
}
}
obj->m_sprBlit.setTextureRect(sf::IntRect((*it)->getSprite().getTextureRect().left,
(*it)->getSprite().getTextureRect().top,
(*it)->getSprite().getTextureRect().width,
(*it)->getSprite().getTextureRect().height));
obj->m_sprBlit.setPosition(is::getSFMLObjX((*it)->getSprite()), is::getSFMLObjY((*it)->getSprite()));
obj->m_sprBlit.setOrigin(is::getSFMLObjOriginX((*it)->getSprite()), is::getSFMLObjOriginY((*it)->getSprite()));
obj->m_sprBlit.setScale(is::getSFMLObjXScale((*it)->getSprite()), is::getSFMLObjYScale((*it)->getSprite()));
obj->m_sprBlit.setColor((*it)->getSprite().getColor().r, (*it)->getSprite().getColor().g,
(*it)->getSprite().getColor().b, (*it)->getSprite().getColor().a);
#endif
if (inViewRec(it->get(), true))
{
if ((*it)->getVisible()) m_window.draw(
#if defined(IS_ENGINE_SDL_2)
obj->m_sprBlit
#else
(*it)->getSprite()
#endif
);
}
}
else (*it)->draw(m_surface);
}
}
}
}
drawMsgBox();
}
void GameDisplay::createSprite(const std::string &spriteName, is::MainObject &obj, sf::IntRect rec, sf::Vector2f position, sf::Vector2f origin, sf::Vector2f scale, unsigned int alpha)
{
auto &tex = GRMgetTexture(spriteName);
obj.m_SDMblitSprTextureName =
#if !defined(IS_ENGINE_SDL_2)
spriteName;
is::createSprite(tex, obj.getSprite(), rec, sf::Vector2f(position.x, position.y), sf::Vector2f(origin.x, origin.y), false, false);
#else
GRMgetTexture(spriteName).getFileName();
bool exists = false;
for (unsigned int i(0); i < m_SDMblitSDLSprite.size(); ++i)
{
if (m_SDMblitSDLSprite[i]->m_strTextureName == obj.m_SDMblitSprTextureName)
{
exists = true;
break;
}
}
if (!exists) m_SDMblitSDLSprite.push_back(std::make_shared(obj.m_SDMblitSprTextureName, tex));
obj.getSprite().setTextureRect(sf::IntRect(rec.left, rec.top, rec.width, rec.height));
obj.getSprite().setPosition(position.x, position.y);
obj.getSprite().setOrigin(origin.x, origin.y);
obj.getSprite().setScale(scale.x, scale.y);
obj.getSprite().setColor(255, 255, 255, alpha);
#endif
}
#endif
}
================================================
FILE: app/src/main/cpp/GameEngine.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2025 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/core/GameEngine.h"
#if defined(IS_ENGINE_HTML_5)
std::function mainLoop;
void MainLoop()
{
return mainLoop();
}
#endif
namespace is
{
GameEngine::GameEngine():
m_gameSysExt(m_window)
{}
GameEngine::~GameEngine()
{
#if defined(IS_ENGINE_SDL_2)
is::SDL2freeLib();
#endif
};
void GameEngine::initEngine()
{
m_gameSysExt.initSystemData();
m_window.create(sf::VideoMode(is::GameConfig::WINDOW_WIDTH, is::GameConfig::WINDOW_HEIGHT),
is::GameConfig::GAME_NAME,
is::getWindowStyle());
#if !defined(__ANDROID__)
#if defined(IS_ENGINE_SFML)
// load application icon
sf::Image iconTex;
if (iconTex.loadFromFile(is::GameConfig::GUI_DIR + "icon.png"))
m_window.setIcon(iconTex.getSize().x, iconTex.getSize().y, iconTex.getPixelsPtr());
#endif
// create saving directory
#if (!defined(IS_ENGINE_HTML_5) && !defined(IS_ENGINE_SWITCH))
if (!m_gameSysExt.fileExist(is::GameConfig::CONFIG_FILE))
{
#if defined(IS_ENGINE_VS)
_mkdir
#else
mkdir
#endif
(is::GameConfig::DATA_PARENT_DIR.c_str()
#if defined(SFML_SYSTEM_LINUX) || defined(IS_ENGINE_LINUX)
, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
#endif
);
m_gameSysExt.saveConfig(is::GameConfig::CONFIG_FILE);
}
#endif
#endif // defined
setFPS(m_window, is::GameConfig::FPS);
}
#if defined(IS_ENGINE_HTML_5)
void GameEngine::execMainLoop(std::function loop)
{
mainLoop = [myLoop = loop] {(void)myLoop();};
emscripten_set_main_loop(&MainLoop, -1, 1);
}
void GameEngine::execMainLoop(std::function loop)
{
mainLoop = loop;
emscripten_set_main_loop(&MainLoop, -1, 1);
}
#endif
bool GameEngine::play()
{
//////////////////////////////////////////////////////////////////////////////////////////////////////
// GAME INTILISATION
//////////////////////////////////////////////////////////////////////////////////////////////////////
initEngine();
//////////////////////////////////////////////////////////////////////////////////////////////////////
// GAME STARTUP
//////////////////////////////////////////////////////////////////////////////////////////////////////
std::unique_ptr app = nullptr;
#if !defined(IS_ENGINE_HTML_5)
while (m_window.isOpen()
#ifdef __SWITCH__
&& appletMainLoop()
#endif
)
#else
EM_ASM(console.log("Start successfully!");, 0);
execMainLoop([&]
{
if (emscripten_run_script_int("Module.syncdone") == 1)
#endif
{
if (app == nullptr) app = std::make_unique(m_gameSysExt);
else
{
app->update();
app->draw();
}
}
#if defined(IS_ENGINE_HTML_5)
});
#endif
return true;
}
}
================================================
FILE: app/src/main/cpp/GameFunction.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/function/GameFunction.h"
#if defined(IS_ENGINE_HTML_5)
#include
#include
// Allows to send C++ string vector in javascript code
inline std::vector *vectorFromIntPointer(uintptr_t vec) {
return reinterpret_cast *>(vec);
}
EMSCRIPTEN_BINDINGS(Wrappers) {
emscripten::register_vector("VectorString").constructor(&vectorFromIntPointer, emscripten::allow_raw_pointers());
};
#endif
namespace is
{
const float MAX_CLOCK_TIME = 0.018f;
const float VALUE_CONVERSION = 65.f;
const float SECOND = 59.f;
const float VALUE_TIME = 1.538f;
std::string w_chart_tToStr(wchar_t const *val)
{
std::wstring ws(val);
return (std::string(ws.begin(), ws.end()));
}
std::wstring strToWStr(const std::string &str)
{
std::wstring wsTemp(str.begin(), str.end());
return wsTemp;
}
int getMSecond(const float &DELTA_TIME)
{
return static_cast(DELTA_TIME * (VALUE_TIME * VALUE_CONVERSION));
}
std::tm makeTime(int year, int month, int day)
{
std::tm tm = {0};
tm.tm_year = year - 1900; // years count from 1900
tm.tm_mon = month - 1; // months count from January=0
tm.tm_mday = day; // days count from 1
return tm;
}
bool checkDateLimit(int year, int mont, int day)
{
time_t currentTime = time(0);
std::tm tm1 = makeTime(year, mont, day);
std::time_t expirationDate = std::mktime(&tm1);
const int seconds_per_day = 60 * 60 * 24;
return (std::difftime(expirationDate, currentTime) / seconds_per_day < 0.f);
}
void showLog(const std::string& str, bool stopApplication)
{
#if defined(IS_ENGINE_USE_SHOWLOG)
#if !defined(__ANDROID__)
std::cout << str.c_str() << "\n";
#else
__android_log_print(ANDROID_LOG_DEBUG, "LOG_INFO", "%s\n", str.c_str());
#endif
#endif
if (stopApplication) is::closeApplication();
}
bool isIn(unsigned short valNumber, const int var, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9)
{
if (var == x1) return true;
else if (var == x2) return true;
else if (var == x3) return (valNumber > 2);
else if (var == x4) return (valNumber > 3);
else if (var == x5) return (valNumber > 4);
else if (var == x6) return (valNumber > 5);
else if (var == x7) return (valNumber > 6);
else if (var == x8) return (valNumber > 7);
else if (var == x9) return (valNumber > 8);
return false;
}
bool isBetween(float a, float b, float c)
{
if (b <= c) return (b <= a && a <= c);
else return (c <= a && a <= b);
}
int sign(float x)
{
if (x > 0.f) return 1;
else if (x < 0.f) return -1;
else return 0;
}
float pointDirection(float x1, float y1, float x2, float y2)
{
return atan((y1 - y2) / (x1 - x2));
}
float radToDeg(float x)
{
return static_cast((x * 180.f) / 3.14159235f);
}
float degToRad(float x)
{
return static_cast((x * 3.14159235f) / 180.f);
}
float lengthDirX(float dir, float angle, bool useScreenScale)
{
#if defined(IS_ENGINE_SDL_2)
if (useScreenScale)
{
if (static_cast(is::IS_ENGINE_SDL_screenXScale) != 1)
{
float tempDir(dir);
dir += tempDir / is::IS_ENGINE_SDL_screenXScale;
}
return (dir * std::cos(degToRad(angle))) / is::IS_ENGINE_SDL_screenXScale;
}
#endif
return dir * std::cos(degToRad(angle));
}
float lengthDirY(float dir, float angle, bool useScreenScale)
{
#if defined(IS_ENGINE_SDL_2)
if (useScreenScale)
{
if (static_cast(is::IS_ENGINE_SDL_screenXScale) != 1)
{
float tempDir(dir);
dir += tempDir / is::IS_ENGINE_SDL_screenXScale;
return (dir * std::sin(degToRad(angle))) / is::IS_ENGINE_SDL_screenYScale;
}
}
#endif
return dir * std::sin(degToRad(angle));
}
bool collisionTest(Rectangle const &a, Rectangle const &b)
{
if (a.m_bottom <= b.m_top) return false;
if (a.m_top >= b.m_bottom) return false;
if (a.m_right <= b.m_left) return false;
if (a.m_left >= b.m_right) return false;
return true;
}
bool collisionTest(Circle const &a, Circle const &b)
{
auto distanceSquared = [](int x1, int y1, int x2, int y2)
{
int deltaX = x2 - x1;
int deltaY = y2 - y1;
return deltaX * deltaX + deltaY * deltaY;
};
// Calculate total radius squared
int totalRadiusSquared = a.m_raduis + b.m_raduis;
totalRadiusSquared = totalRadiusSquared * totalRadiusSquared;
// If the distance between the centers of the circles is less than the sum of their radii
if (distanceSquared(a.m_x, a.m_y, b.m_x, b.m_y) < totalRadiusSquared) return true; // The circles have collided
return false; // If not
}
bool collisionTest(Circle const &circle, Rectangle const &rec)
{
// temporary variables to set edges for testing
float testX = circle.m_x;
float testY = circle.m_y;
// which edge is closest?
if (circle.m_x < rec.m_left) testX = rec.m_left; // test left edge
else if (circle.m_x > rec.m_right) testX = rec.m_right; // right edge
if (circle.m_y < rec.m_top) testY = rec.m_top; // top edge
else if (circle.m_y > rec.m_bottom) testY = rec.m_bottom; // bottom edge
// get distance from closest edges
float distX = circle.m_x - testX;
float distY = circle.m_y - testY;
float distance = sqrt((distX * distX) + (distY * distY));
// if the distance is less than the radius, collision!
if (distance <= circle.m_raduis) return true;
return false;
}
bool collisionTest(Rectangle const &rec, Circle const &circle)
{
return collisionTest(circle, rec);
}
void setTextAnimation(sf::Text &txt, sf::Sprite &spr, sf::Sprite &sprSelected, int &var, int val)
{
if (var == val)
{
is::setSFMLObjX_Y(sprSelected, is::getSFMLObjX(spr), is::getSFMLObjY(spr));
is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_SELECTED_TEXT_COLOR);
}
else is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_TEXT_COLOR);
}
void setTextAnimation(sf::Text &txt, int &var, int val)
{
if (var == val) is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_SELECTED_TEXT_COLOR);
else is::setSFMLObjFillColor(txt, is::GameConfig::DEFAULT_SFML_TEXT_COLOR);
}
void setFrame(sf::Sprite &sprite, float frame, int subFrame, int frameWidth, int frameHeight, int recWidth, int recHeight)
{
/* Description of the image decoupage algorithm
* be << frame >> number of the image to get (to have it start counting images from 0 to X)
* either << subFrame >> number of images on one line
* be << frameLineIndex >> number of the line corresponding to the image
* (frame / subFrame) returns the number of times there is << frame >> in << subFrame >> to determine the number of the line of the image
* 32 * (frame - (subFrame * frameLineIndex)) returns the position (number) of the image on the X axis can return the value 0 (1st image on the line)
* when the value of << frame >> exceeds the number of image on the X axis (the value of << subFrame >>) then we are on a new line
* (32 * frameLineIndex) gives the position of the image on the Y axis its value varies according to the << frame >>
* example: 32 * frameLineIndex = 1 when frame > subFrame; 32 * frameLineIndex = 2 when frame > subFrame * 2; ...
*/
int frameLineIndex = (frame / subFrame);
setSFMLObjTexRec(sprite, frameWidth * (static_cast(frame) - (subFrame * frameLineIndex)), frameHeight * frameLineIndex, recWidth, recHeight);
}
void setFrame(sf::Sprite &sprite, float frame, int subFrame, int frameSize)
{
setFrame(sprite, frame, subFrame, frameSize, frameSize, frameSize, frameSize);
}
/*
void createRenderTexture(sf::RenderTexture &renderTexture, unsigned int width, unsigned int height)
{
renderTexture.create(width, height);
}*/
void createRectangle(sf::RectangleShape &rec, sf::Vector2f recSize, sf::Color color, float x, float y, bool center)
{
rec.setSize(recSize);
if (center) is::centerSFMLObj(rec);
setSFMLObjFillColor(rec, color);
is::setSFMLObjX_Y(rec, x, y);
}
void textStyleConfig(sf::Text &txt, bool underLined, bool boldText, bool italicText)
{
if (underLined && boldText && italicText) txt.setStyle(sf::Text::Underlined | sf::Text::Bold | sf::Text::Italic);
else if (underLined && boldText) txt.setStyle(sf::Text::Underlined | sf::Text::Bold);
else if (underLined && italicText) txt.setStyle(sf::Text::Underlined | sf::Text::Italic);
else if (boldText && italicText) txt.setStyle(sf::Text::Bold | sf::Text::Italic);
else if (underLined) txt.setStyle(sf::Text::Underlined);
else if (boldText) txt.setStyle(sf::Text::Bold);
else if (italicText) txt.setStyle(sf::Text::Italic);
}
void setSFMLTextOutlineColor(sf::Text &txt, float thickness, sf::Color color)
{
txt.setOutlineColor(color);
txt.setOutlineThickness(thickness);
}
void createSprite(sf::Texture &tex, sf::Sprite &spr, sf::Vector2f position, sf::Vector2f origin, bool smooth)
{
#if defined(IS_ENGINE_SFML)
tex.setSmooth(smooth);
#endif
spr.setTexture(tex);
spr.setOrigin(origin.x, origin.y);
is::setSFMLObjX_Y(spr, position.x, position.y);
}
void createSprite(sf::Texture &tex, sf::Sprite &spr, sf::IntRect rec, sf::Vector2f position, sf::Vector2f origin, bool repeatTexture, bool smooth)
{
createSprite(tex, spr, position, origin, smooth);
is::setSFMLObjTexRec(spr, rec.left, rec.top, rec.width, rec.height);
#if defined(IS_ENGINE_SFML)
if (repeatTexture) tex.setRepeated(true);
#endif
}
void createSprite(sf::Texture &tex, sf::Sprite &spr, sf::IntRect rec, sf::Vector2f position, sf::Vector2f origin, sf::Vector2f scale, unsigned int alpha, bool repeatTexture, bool smooth)
{
createSprite(tex, spr, rec, position, origin, repeatTexture, smooth);
is::setSFMLObjScaleX_Y(spr, scale.x, scale.y);
is::setSFMLObjAlpha(spr, alpha);
}
sf::Vector2f getCursor(sf::RenderWindow &window, unsigned int finger)
{
sf::Vector2i pixelPos =
((IS_ENGINE_MOBILE_OS) ?
sf::Touch::getPosition(finger, window)
:
sf::Mouse::getPosition(window)
);
sf::Vector2f worldPos = window.mapPixelToCoords(pixelPos, window.getView());
float dx = pointDistance(window.getView().getCenter().x, window.getView().getCenter().y,
worldPos.x, window.getView().getCenter().y);
float dy = pointDistance(window.getView().getCenter().x, window.getView().getCenter().y,
window.getView().getCenter().x, worldPos.y);
if (worldPos.x < window.getView().getCenter().x) dx *= -1;
if (worldPos.y < window.getView().getCenter().y) dy *= -1;
return sf::Vector2f(window.getView().getCenter().x + dx, window.getView().getCenter().y + dy);
}
short vibrate(short duration)
{
#if defined(__ANDROID__)
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
jobject activity = (jobject)SDL_AndroidGetActivity();
jclass clazz(env->GetObjectClass(activity));
JavaVM* vm;
env->GetJavaVM(&vm);
// 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, 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;
// 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);
env->DeleteLocalRef(clazz);
// Detach thread again
// this line is comment because it cause a bug
// vm->DetachCurrentThread();
#elif defined(IS_ENGINE_HTML_5)
EM_ASM_ARGS({
navigator.vibrate($0);
}, duration);
#else
is::showLog("Vibrate Called ! Time : " + is::numToStr(duration) + " ms");
#endif
return 1; // EXIT_SUCCESS;
}
void openURL(const std::string& url, OpenURLAction action)
{
std::string urlStr;
switch(action)
{
case OpenURLAction::Http: urlStr = "http://" + url; break;
case OpenURLAction::Tel: urlStr = "tel:" + url; break;
default: urlStr = "mailto:" + url; break;
}
#if defined(__ANDROID__)
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
jobject activity = (jobject)SDL_AndroidGetActivity();
JavaVM* vm;
env->GetJavaVM(&vm);
vm->AttachCurrentThread(&env, NULL);
// Retrieve class information
jclass activityClass = env->FindClass("android/app/Activity");
jclass intentClass = env->FindClass("android/content/Intent");
jclass uriClass = env->FindClass("android/net/Uri");
// convert URL std::string to jstring
jstring uriString = env->NewStringUTF(urlStr.c_str());
// call parse method
jmethodID uriParse = env->GetStaticMethodID(uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
// set URL in method
jobject uri = env->CallStaticObjectMethod(uriClass, uriParse, uriString);
// intent action
jstring actionString =
env->NewStringUTF((action != OpenURLAction::Tel) ? "android.intent.action.VIEW" : "android.intent.action.DIAL");
// call the intent object constructor
jmethodID newIntent = env->GetMethodID(intentClass, "", "(Ljava/lang/String;Landroid/net/Uri;)V");
// create the intent instance
jobject intent = env->AllocObject(intentClass);
// set intent constructor
env->CallVoidMethod(intent, newIntent, actionString, uri);
jmethodID startActivity = env->GetMethodID(activityClass, "startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod(activity, startActivity, intent);
env->DeleteLocalRef(activityClass);
env->DeleteLocalRef(intentClass);
env->DeleteLocalRef(uriClass);
env->DeleteLocalRef(intent);
env->DeleteLocalRef(activity);
//vm->DetachCurrentThread();
#elif defined(IS_ENGINE_HTML_5)
std::vector vectorArray;
vectorArray.push_back(urlStr);
EM_ASM_ARGS
({
var vectorArray = new Module.VectorString($0);
window.open(vectorArray.get(0));
}, &vectorArray);
#else
std::string op =
#if !defined(SFML_SYSTEM_LINUX)
std::string("start ")
#else
std::string("xdg-open ")
#endif
.append(urlStr);
system(op.c_str());
#endif
}
#if defined(__ANDROID__)
std::string jstring2string(JNIEnv *env, jstring jStr)
{
if (!jStr) return "";
const jclass stringClass = env->GetObjectClass(jStr);
const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));
size_t length = (size_t) env->GetArrayLength(stringJbytes);
jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
std::string ret = std::string((char *)pBytes, length);
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
env->DeleteLocalRef(stringJbytes);
env->DeleteLocalRef(stringClass);
return ret;
}
std::string getDeviceId(JNIEnv *env, ANativeActivity *activity)
{
jclass classActivity = env->FindClass("android/app/NativeActivity");
jclass context = env->FindClass("android/content/Context");
jclass telephony = env->FindClass("android/telephony/TelephonyManager");
jfieldID field = env->GetStaticFieldID(context, "TELEPHONY_SERVICE", "Ljava/lang/String;");
jobject staticField = env->GetStaticObjectField(context, field);
jmethodID getSS = env->GetMethodID(classActivity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject objTel = env->CallObjectMethod(activity->clazz, getSS, staticField);
jmethodID getId = env->GetMethodID(telephony, "getDeviceId", "()Ljava/lang/String;");
jstring strId = (jstring)env->CallObjectMethod(objTel, getId);
env->DeleteLocalRef(classActivity);
env->DeleteLocalRef(context);
env->DeleteLocalRef(telephony);
return jstring2string(env, strId);
}
#endif
}
================================================
FILE: app/src/main/cpp/GameKeyData.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/function/GameKeyData.h"
namespace is
{
GameKeyData::GameKeyData(is::GameDisplay *scene) :
MainObject(),
m_keyPausePressed(false),
m_keyLeftPressed(false),
m_keyRightPressed(false),
m_keyUpPressed(false),
m_keyDownPressed(false),
m_keyAPressed(false),
m_keyBPressed(false),
m_keyAUsed(false),
m_keyBUsed(false),
m_keyLeftUsed(false),
m_keyRightUsed(false),
m_keyUpUsed(false),
m_keyDownUsed(false),
m_disableAllKey(false),
m_hideGamePad(false),
#if defined(__ANDROID__)
m_moveObj(0.f),
#endif
m_scene(scene)
{
m_strName = "GameKeyData";
m_moveKeyPressed = V_KEY_NONE;
m_actionKeyPressed = V_KEY_NONE;
m_keyboardA = &is::GameConfig::KEY_A;
m_keyboardB = &is::GameConfig::KEY_B;
m_keyboardLeft = &is::GameConfig::KEY_LEFT;
m_keyboardRight = &is::GameConfig::KEY_RIGHT;
m_keyboardUp = &is::GameConfig::KEY_UP;
m_keyboardDown = &is::GameConfig::KEY_DOWN;
loadResources();
}
void GameKeyData::loadResources(bool usePadColorBlack)
{
auto &tex = m_scene->GRMaddTexture("game_pad", is::GameConfig::GUI_DIR + "game_pad.png");
is::createSprite(tex, m_sprJoystick[0], sf::IntRect(0, (!usePadColorBlack) ? 0 : 134, 134, 134), sf::Vector2f(0.f, 0.f), sf::Vector2f(67.f, 67.f));
is::createSprite(tex, m_sprJoystick[1], sf::IntRect(134, ((!m_scene->getGameSystem().m_permutePadAB) ? 0 : 67) + ((!usePadColorBlack) ? 0 : 134), 144, 67),
sf::Vector2f(0.f, 0.f), sf::Vector2f(72.f, 37.f));
is::setSFMLObjSize(m_recJoystickMask[0], 134.f, 134.f);
is::setSFMLObjSize(m_recJoystickMask[1], 144.f, 74.f);
for (int i(0); i < 2; i++)
{
is::setSFMLObjFillColor(m_recJoystickMask[i], sf::Color::Blue);
is::centerSFMLObj(m_recJoystickMask[i]);
}
const float OBJ_SIZE(40.f), _ADD_SIZE(24.f), _ADD_ACT_SIZE(24.f), _ADD_W(16.f);
is::setSFMLObjSize(m_recKeyLeftMask, OBJ_SIZE + _ADD_W, OBJ_SIZE + _ADD_SIZE);
is::setSFMLObjSize(m_recKeyRightMask, OBJ_SIZE + _ADD_W, OBJ_SIZE + _ADD_SIZE);
is::setSFMLObjSize(m_recKeyUpMask, OBJ_SIZE + _ADD_SIZE, OBJ_SIZE + _ADD_W);
is::setSFMLObjSize(m_recKeyDownMask, OBJ_SIZE + _ADD_SIZE, OBJ_SIZE + _ADD_W);
is::setSFMLObjSize(m_recKeyAMask, OBJ_SIZE + _ADD_ACT_SIZE, OBJ_SIZE + _ADD_ACT_SIZE);
is::setSFMLObjSize(m_recKeyBMask, OBJ_SIZE + _ADD_ACT_SIZE, OBJ_SIZE + _ADD_ACT_SIZE);
is::centerSFMLObj(m_recKeyLeftMask);
is::centerSFMLObj(m_recKeyRightMask);
is::centerSFMLObj(m_recKeyUpMask);
is::centerSFMLObj(m_recKeyDownMask);
is::centerSFMLObj(m_recKeyAMask);
is::centerSFMLObj(m_recKeyBMask);
}
void GameKeyData::step(const float &DELTA_TIME)
{
if (!keyAPressed()) m_keyAUsed = false;
if (!keyBPressed()) m_keyBUsed = false;
if (!keyLeftPressed()) m_keyLeftUsed = false;
if (!keyRightPressed()) m_keyRightUsed = false;
if (!keyUpPressed()) m_keyUpUsed = false;
if (!keyDownPressed()) m_keyDownUsed = false;
m_keyLeftPressed = keyLeftPressed();
m_keyRightPressed = keyRightPressed();
m_keyUpPressed = keyUpPressed();
m_keyDownPressed = keyDownPressed();
m_keyAPressed = keyAPressed();
m_keyBPressed = keyBPressed();
if (m_keyLeftPressed)
{
m_keyRightPressed = false;
m_keyUpPressed = false;
m_keyDownPressed = false;
if (!IS_ENGINE_MOBILE_OS) m_moveKeyPressed = V_KEY_LEFT;
}
else if (m_keyRightPressed)
{
m_keyLeftPressed = false;
m_keyUpPressed = false;
m_keyDownPressed = false;
if (!IS_ENGINE_MOBILE_OS) m_moveKeyPressed = V_KEY_RIGHT;
}
else if (m_keyUpPressed)
{
m_keyLeftPressed = false;
m_keyRightPressed = false;
m_keyDownPressed = false;
if (!IS_ENGINE_MOBILE_OS) m_moveKeyPressed = V_KEY_UP;
}
else if (m_keyDownPressed)
{
m_keyLeftPressed = false;
m_keyRightPressed = false;
m_keyUpPressed = false;
if (!IS_ENGINE_MOBILE_OS) m_moveKeyPressed = V_KEY_DOWN;
}
if (is::IS_ENGINE_MOBILE_OS)
{
if (m_hideGamePad)
{
if (m_moveObj < 320.f) m_moveObj += (10.f * is::VALUE_CONVERSION) * DELTA_TIME;
}
else
{
is::decreaseVar(DELTA_TIME, m_moveObj, 8.f, 0.f, 10.f);
}
float moveMaskOnX(0.f), _LIMIT(-19.f), _POS(37.f);
const float _W_SIZE(48.f);
if (m_moveKeyPressed == V_KEY_LEFT) moveMaskOnX = -6.f;
if (m_moveKeyPressed == V_KEY_RIGHT) moveMaskOnX = 6.f;
is::setSFMLObjX_Y(m_sprJoystick[0],
m_scene->getViewX() + m_scene->getGameSystem().m_padDirXPos,
m_scene->getViewY() + m_scene->getGameSystem().m_padDirYPos + m_moveObj);
is::setSFMLObjX_Y(m_sprJoystick[1],
m_scene->getViewX() + m_scene->getGameSystem().m_padActionXPos,
m_scene->getViewY() + m_scene->getGameSystem().m_padActionYPos + m_moveObj);
is::setSFMLObjX_Y(m_recKeyLeftMask, (is::getSFMLObjX(m_sprJoystick[0]) - _W_SIZE / 2.f) + _LIMIT,
is::getSFMLObjY(m_sprJoystick[0]));
is::setSFMLObjX_Y(m_recKeyRightMask, (is::getSFMLObjX(m_sprJoystick[0]) + _W_SIZE / 2.f) - _LIMIT,
is::getSFMLObjY(m_sprJoystick[0]));
is::setSFMLObjX_Y(m_recKeyUpMask, is::getSFMLObjX(m_sprJoystick[0]),
(is::getSFMLObjY(m_sprJoystick[0]) - _W_SIZE / 2.f) + _LIMIT);
is::setSFMLObjX_Y(m_recKeyDownMask, is::getSFMLObjX(m_sprJoystick[0]),
(is::getSFMLObjY(m_sprJoystick[0]) + _W_SIZE / 2.f) - _LIMIT);
is::setSFMLObjX_Y(m_recKeyAMask, is::getSFMLObjX(m_sprJoystick[1]) + (_POS * ((!m_scene->getGameSystem().m_permutePadAB) ? -1.f : 1.f)),
is::getSFMLObjY(m_sprJoystick[1]));
is::setSFMLObjX_Y(m_recKeyBMask, is::getSFMLObjX(m_sprJoystick[1]) + (_POS * ((!m_scene->getGameSystem().m_permutePadAB) ? 1.f : -1.f)),
is::getSFMLObjY(m_sprJoystick[1]));
for (int i(0); i < 2; i++)
{
is::setSFMLObjX_Y(m_recJoystickMask[i], is::getSFMLObjX(m_sprJoystick[i]) + ((i == 0) ? moveMaskOnX : 0.f), is::getSFMLObjY(m_sprJoystick[i]));
is::setSFMLObjAlpha(m_sprJoystick[i], m_scene->getGameSystem().m_padAlpha);
}
}
else
{
if (m_keyAPressed) m_actionKeyPressed = V_KEY_A;
else if (m_keyBPressed) m_actionKeyPressed = V_KEY_B;
else m_actionKeyPressed = V_KEY_NONE;
if (!m_keyLeftPressed && !m_keyRightPressed && !m_keyUpPressed && !m_keyDownPressed) m_moveKeyPressed = V_KEY_NONE;
}
}
void GameKeyData::draw(is::Render &surface)
{
if (is::IS_ENGINE_MOBILE_OS)
{
if (m_moveObj < 320.f)
{
/*
* This displays the virtual key mask on the screen
*
for (int i(0); i < 2; i++) surface.draw(m_recJoystickMask[i]);
surface.draw(m_recKeyLeftMask);
surface.draw(m_recKeyRightMask);
surface.draw(m_recKeyUpMask);
surface.draw(m_recKeyDownMask);
surface.draw(m_recKeyAMask);
surface.draw(m_recKeyBMask);
*/
for (int i(0); i < 2; i++)
{
if (m_scene->getIsPlaying()) surface.draw(m_sprJoystick[i]);
}
}
}
}
bool GameKeyData::checkKeyPressed(VirtualKeyIndex virtualKeyIndex, sf::Keyboard::Key *keyboardIndex)
{
if (m_disableAllKey) return false;
//////////////////////////////////////////////////////////
// Mobile version code
//if (is::IS_ENGINE_MOBILE_OS)
//{
if (virtualKeyPressed(virtualKeyIndex)) return true;
//}
else
//{
if (m_scene->getGameSystem().keyIsPressed(*keyboardIndex)) return true;
//}
//////////////////////////////////////////////////////////
return false;
}
bool GameKeyData::keyLeftPressed()
{
return checkKeyPressed(V_KEY_LEFT, m_keyboardLeft);
}
bool GameKeyData::keyRightPressed()
{
return checkKeyPressed(V_KEY_RIGHT, m_keyboardRight);
}
bool GameKeyData::keyUpPressed()
{
return checkKeyPressed(V_KEY_UP, m_keyboardUp);
}
bool GameKeyData::keyDownPressed()
{
return checkKeyPressed(V_KEY_DOWN, m_keyboardDown);
}
bool GameKeyData::keyAPressed()
{
return checkKeyPressed(V_KEY_A, m_keyboardA);
}
bool GameKeyData::keyBPressed()
{
return checkKeyPressed(V_KEY_B, m_keyboardB);
}
bool GameKeyData::virtualKeyPressed(VirtualKeyIndex virtualKeyIndex)
{
// Joystick controller
bool mouseOnLJoystick(false);
bool mouseOnRJoystick(false);
if (virtualKeyIndex == V_KEY_LEFT || virtualKeyIndex == V_KEY_RIGHT || virtualKeyIndex == V_KEY_UP || virtualKeyIndex == V_KEY_DOWN)
{
// Check collision with left joystick
if (m_scene->mouseCollision(m_recJoystickMask[0]) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recJoystickMask[0], 1))) mouseOnLJoystick = true;
if (mouseOnLJoystick)
{
if (m_moveKeyPressed != V_KEY_NONE && m_moveKeyPressed != virtualKeyIndex)
{
if (m_scene->mouseCollision(m_recKeyLeftMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyLeftMask, 1))) m_moveKeyPressed = V_KEY_LEFT;
else if (m_scene->mouseCollision(m_recKeyRightMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyRightMask, 1))) m_moveKeyPressed = V_KEY_RIGHT;
else if (m_scene->mouseCollision(m_recKeyUpMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyUpMask, 1))) m_moveKeyPressed = V_KEY_UP;
else if (m_scene->mouseCollision(m_recKeyDownMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyDownMask, 1))) m_moveKeyPressed = V_KEY_DOWN;
}
switch (m_moveKeyPressed)
{
case V_KEY_LEFT:
return (m_moveKeyPressed == virtualKeyIndex);
break;
case V_KEY_RIGHT:
return (m_moveKeyPressed == virtualKeyIndex);
break;
case V_KEY_UP:
return (m_moveKeyPressed == virtualKeyIndex);
break;
case V_KEY_DOWN:
return (m_moveKeyPressed == virtualKeyIndex);
break;
default: break;
}
}
// If left joystick pressed
if ((m_scene->getGameSystem().isPressed() ||
(IS_ENGINE_MOBILE_OS && m_scene->getGameSystem().isPressed(1))) && mouseOnLJoystick)
{
switch (virtualKeyIndex)
{
case V_KEY_LEFT:
if (m_scene->mouseCollision(m_recKeyLeftMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyLeftMask, 1)))
{
m_moveKeyPressed = V_KEY_LEFT;
// is::showLog("L Pressed !");
return true;
}
break;
case V_KEY_RIGHT:
if (m_scene->mouseCollision(m_recKeyRightMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyRightMask, 1)))
{
m_moveKeyPressed = V_KEY_RIGHT;
// is::showLog("R Pressed !");
return true;
}
break;
case V_KEY_UP:
if (m_scene->mouseCollision(m_recKeyUpMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyUpMask, 1)))
{
m_moveKeyPressed = V_KEY_UP;
// is::showLog("U Pressed !");
return true;
}
break;
case V_KEY_DOWN:
if (m_scene->mouseCollision(m_recKeyDownMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyDownMask, 1)))
{
m_moveKeyPressed = V_KEY_DOWN;
// is::showLog("D Pressed !");
return true;
}
break;
default: break;
}
}
m_moveKeyPressed = V_KEY_NONE;
}
if (virtualKeyIndex == V_KEY_A || virtualKeyIndex == V_KEY_B)
{
// Check collision with right joystick
if (m_scene->mouseCollision(m_recJoystickMask[1]) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recJoystickMask[1], 1))) mouseOnRJoystick = true;
// If left joystick pressed
if ((m_scene->getGameSystem().isPressed() ||
(IS_ENGINE_MOBILE_OS && m_scene->getGameSystem().isPressed(1))) && mouseOnRJoystick)
{
switch (virtualKeyIndex)
{
case V_KEY_A:
if (m_scene->mouseCollision(m_recKeyAMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyAMask, 1)))
{
m_actionKeyPressed = V_KEY_A;
// is::showLog("A Pressed !");
return true;
}
break;
case V_KEY_B:
if (m_scene->mouseCollision(m_recKeyBMask) ||
(IS_ENGINE_MOBILE_OS && m_scene->mouseCollision(m_recKeyBMask, 1)))
{
m_actionKeyPressed = V_KEY_B;
// is::showLog("B Pressed !");
return true;
}
break;
default: break;
}
}
m_actionKeyPressed = V_KEY_NONE;
}
return false;
}
};
================================================
FILE: app/src/main/cpp/GameSlider.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/function/GameSlider.h"
namespace is
{
GameSlider::GameSlider(is::GameDisplay *scene):
MainObject(),
Type(SLIDE_NONE),
m_scene(scene),
m_slideDistance(64.f)
{
m_strName = "GameSlider";
#if defined(IS_ENGINE_USE_SDM)
m_depth = 999999999; // will update this object before all others
#endif
}
void GameSlider::step(const float &DELTA_TIME)
{
if (m_scene->getGameSystem().isPressed(is::GameSystem::MOUSE))
{
sf::Vector2f cursor(m_scene->getCursor());
if (static_cast(m_time) == 0)
{
m_xStart = cursor.x;
m_yStart = cursor.y;
}
m_time = 5.f;
m_x = cursor.x;
m_y = cursor.y;
if (m_type == SLIDE_NONE)
{
if (m_x > m_xStart + m_slideDistance) m_type = SLIDE_RIGHT;
else if (m_x < m_xStart - m_slideDistance) m_type = SLIDE_LEFT;
else if (m_y < m_yStart - m_slideDistance) m_type = SLIDE_UP;
else if (m_y > m_yStart + m_slideDistance) m_type = SLIDE_DOWN;
}
}
if (m_time > 0.f) m_time -= is::getMSecond(DELTA_TIME);
else
{
m_type = SLIDE_NONE;
m_time = 0.f;
}
}
GameSlider::SlideDirection GameSlider::getSlideDirection() const
{
switch (m_type)
{
default: break;
case 1: return SLIDE_UP; break;
case 2: return SLIDE_DOWN; break;
case 3: return SLIDE_RIGHT; break;
case 4: return SLIDE_LEFT; break;
}
return SLIDE_NONE;
}
}
================================================
FILE: app/src/main/cpp/GameSystem.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/function/GameSystem.h"
namespace is
{
const short MOUSE = 0;
const short KEYBOARD = -1;
const short ALL_BUTTONS = -2;
GameSystem::GameSystem(sf::RenderWindow &window):
m_window(window)
{
srand((unsigned int)time(0));
m_gameLanguage = 0; // 0 = default language
m_validationMouseKey = &GameConfig::KEY_VALIDATION_MOUSE;
m_validationKeyboardKey = &GameConfig::KEY_VALIDATION_KEYBOARD;
m_disableKey = false;
m_enableSound = true;
m_enableMusic = true;
m_enableVibrate = true;
m_loadParentResources = false;
m_keyIsPressed = false;
}
bool GameSystem::isPressed(int finger) const
{
if (m_disableKey) return false;
//////////////////////////////////////////////////////////
// Android version code
if (is::IS_ENGINE_MOBILE_OS)
{
// Exclude the keyboard test when we are on Android
if (finger == -1) return false;
// When testing the mouse validation buttons on PC then consider it as a touch
if (finger == -2) finger = 0;
if (sf::Touch::isDown(finger)) return true;
}
else
{
//////////////////////////////////////////////////////////
switch (finger)
{
case MOUSE:
if (sf::Mouse::isButtonPressed(*m_validationMouseKey)) return true;
break;
case KEYBOARD:
if (sf::Keyboard::isKeyPressed(*m_validationKeyboardKey)) return true;
break;
case ALL_BUTTONS:
if (sf::Mouse::isButtonPressed(*m_validationMouseKey)) return true;
else if (sf::Keyboard::isKeyPressed(*m_validationKeyboardKey)) return true;
break;
}
}
return false;
}
bool GameSystem::isPressed(ValidationButton validationButton) const
{
int value = validationButton;
return isPressed(value);
}
bool GameSystem::keyIsPressed(sf::Keyboard::Key key) const
{
if (m_disableKey) return false;
#ifdef __SWITCH__
const Uint8 *state = getControllerButtonState(NULL);
if (key == is::GameConfig::KEY_VALIDATION_KEYBOARD)
{if (state[SDL_CONTROLLER_BUTTON_START]) return true;}
if (key == is::GameConfig::KEY_CANCEL)
{if (state[SDL_CONTROLLER_BUTTON_BACK]) return true;}
if (key == is::GameConfig::KEY_A)
{if (state[SDL_CONTROLLER_BUTTON_A]) return true;}
if (key == is::GameConfig::KEY_B)
{if (state[SDL_CONTROLLER_BUTTON_B]) return true;}
if (key == is::GameConfig::KEY_X)
{if (state[SDL_CONTROLLER_BUTTON_X]) return true;}
if (key == is::GameConfig::KEY_Y)
{if (state[SDL_CONTROLLER_BUTTON_Y]) return true;}
if (key == is::GameConfig::KEY_LEFT)
{if (state[SDL_CONTROLLER_BUTTON_DPAD_LEFT]) return true;}
if (key == is::GameConfig::KEY_RIGHT)
{if (state[SDL_CONTROLLER_BUTTON_DPAD_RIGHT]) return true;}
if (key == is::GameConfig::KEY_UP)
{if (state[SDL_CONTROLLER_BUTTON_DPAD_UP]) return true;}
if (key == is::GameConfig::KEY_DOWN)
{if (state[SDL_CONTROLLER_BUTTON_DPAD_DOWN]) return true;}
return false;
#endif
if (sf::Keyboard::isKeyPressed(key)) return true;
return false;
}
bool GameSystem::keyIsPressed(sf::Mouse::Button button) const
{
if (m_disableKey) return false;
if (sf::Mouse::isButtonPressed(button)) return true;
return false;
}
bool GameSystem::fileExist(const std::string &fileName)
{
return is::fileExist(fileName);
}
void GameSystem::removeFile(const std::string &fileName)
{
remove(fileName.c_str());
#if defined(IS_ENGINE_HTML_5)
EM_ASM(FS.syncfs(false, function(err){console.log(err)});, 0);
#endif
}
void GameSystem::playSound(sf::Sound &obj)
{
if (m_enableSound) is::playSFMLSnd(obj);
}
void GameSystem::playSound(sf::Sound *obj)
{
if (m_enableSound) is::playSFMLSnd(obj);
}
void GameSystem::playMusic(sf::Music &obj)
{
if (m_enableMusic) is::playSFMLSnd(obj);
}
void GameSystem::playMusic(sf::Music *obj)
{
if (m_enableMusic) is::playSFMLSnd(obj);
}
void GameSystem::stopSound(sf::Sound &obj)
{
if (m_enableSound)
{
if (is::checkSFMLSndState(obj, SFMLSndStatus::Playing)) is::stopSFMLSnd(obj);
}
}
void GameSystem::stopMusic(sf::Music &obj)
{
if (m_enableMusic)
{
if (is::checkSFMLSndState(obj, SFMLSndStatus::Playing)) is::stopSFMLSnd(obj);
}
}
void GameSystem::useVibrate(short ms)
{
if (m_enableVibrate) is::vibrate(ms);
}
void GameSystem::saveConfig(const std::string &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "wb");
if (file != NULL)
{
fwrite(&m_enableSound, sizeof(bool), 1, file);
fwrite(&m_enableMusic, sizeof(bool), 1, file);
fwrite(&m_enableVibrate, sizeof(bool), 1, file);
fwrite(&m_gameLanguage, sizeof(int), 1, file);
fwrite(&m_firstLaunch, sizeof(bool), 1, file);
fclose(file);
#if defined(IS_ENGINE_HTML_5)
EM_ASM(FS.syncfs(false, function(err){console.log(err)});, 0);
#endif
}
}
void GameSystem::loadConfig(const std::string &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "rb");
if (file != NULL)
{
fread(&m_enableSound, sizeof(bool), 1, file);
fread(&m_enableMusic, sizeof(bool), 1, file);
fread(&m_enableVibrate, sizeof(bool), 1, file);
fread(&m_gameLanguage, sizeof(int), 1, file);
fread(&m_firstLaunch, sizeof(bool), 1, file);
fclose(file);
}
}
void GameSystem::savePadConfig(const std::string &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "wb");
if (file != NULL)
{
fwrite(&m_padDirXPos, sizeof(float), 1, file);
fwrite(&m_padDirYPos, sizeof(float), 1, file);
fwrite(&m_padActionXPos, sizeof(float), 1, file);
fwrite(&m_padActionYPos, sizeof(float), 1, file);
fwrite(&m_padAlpha, sizeof(int), 1, file);
fwrite(&m_permutePadAB, sizeof(bool), 1, file);
fclose(file);
#if defined(IS_ENGINE_HTML_5)
EM_ASM(FS.syncfs(false, function(err){console.log(err)});, 0);
#endif
}
}
void GameSystem::loadPadConfig(const std::string &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "rb");
if (file != NULL)
{
fread(&m_padDirXPos, sizeof(float), 1, file);
fread(&m_padDirYPos, sizeof(float), 1, file);
fread(&m_padActionXPos, sizeof(float), 1, file);
fread(&m_padActionYPos, sizeof(float), 1, file);
fread(&m_padAlpha, sizeof(int), 1, file);
fread(&m_permutePadAB, sizeof(bool), 1, file);
fclose(file);
}
}
void GSMplaySound(const std::string& name, std::vector> &GSMsound, GameSystem &gameSystem)
{
bool soundExist(false);
WITH(GSMsound.size())
{
if (GSMsound[_I].get() != nullptr)
{
if (GSMsound[_I]->getName() == name)
{
soundExist = true;
if (GSMsound[_I]->getFileIsLoaded()) gameSystem.playSound(GSMsound[_I]->getSound());
else is::showLog("ERROR: Can't play <" + name + "> sound!");
break;
}
}
}
if (!soundExist) is::showLog("ERROR: Can't play <" + name + "> sound because sound does not exist!");
}
void GSMplayMusic(const std::string& name, std::vector> &GSMmusic, GameSystem &gameSystem)
{
//#if defined(__ANDROID__)
// GSMplaySound(name, GSMmusic, gameSystem);
//#else
bool musicExist(false);
WITH(GSMmusic.size())
{
if (GSMmusic[_I].get() != nullptr)
{
if (GSMmusic[_I]->getName() == name)
{
musicExist = true;
if (GSMmusic[_I]->getFileIsLoaded()) gameSystem.playMusic(GSMmusic[_I]->getMusic());
else is::showLog("ERROR: Can't play <" + name + "> music!");
break;
}
}
}
if (!musicExist) is::showLog("ERROR: Can't play <" + name + "> music because music does not exist!");
//#endif
}
}
================================================
FILE: app/src/main/cpp/GameSystemExtended.cpp
================================================
#include "app_src/gamesystem_ext/GameSystemExtended.h"
namespace is
{
GameSystemExtended::GameSystemExtended(sf::RenderWindow &window) :
GameSystem(window)
{
initProgress();
// Default position of the Virtual Pad Game on the screen
m_defaultPadDirXPos = -250.f;
m_defaultPadDirYPos = 170.f;
m_defaultPadActionXPos = 245.f;
m_defaultPadActionYPos = 200.f;
// Configurable position of the Virtual Pad Game on the screen
m_padDirXPos = m_defaultPadDirXPos;
m_padDirYPos = m_defaultPadDirYPos;
m_padActionXPos = m_defaultPadActionXPos;
m_padActionYPos = m_defaultPadActionYPos;
m_permutePadAB = false;
m_padAlpha = 255;
}
void GameSystemExtended::initProgress()
{
m_gameProgression = 0; // LEVEL 1
m_currentLives = 3;
m_currentBonus = 0;
m_currentLevel = 0;
m_currentScore = 0;
m_currentHiScore = 0;
}
void GameSystemExtended::initSystemData()
{
// global variable
m_gameLanguage = 0;
m_firstLaunch = true;
// Determine the number of levels
// LEVEL_MAX - 1 because we count the number of levels from zero (0) as for the array)
m_levelNumber = is::level::LevelId::LEVEL_MAX - 1;
initProgress();
}
void GameSystemExtended::initData(bool clearCurrentLevel)
{
if (clearCurrentLevel) m_currentLevel = 0; // LEVEL 1
m_currentLives = 3;
m_currentBonus = 0;
m_currentScore = 0;
}
void GameSystemExtended::saveData(std::string const &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "wb");
if (file != NULL)
{
fwrite(&m_gameProgression, sizeof(int), 1, file);
fwrite(&m_currentLives, sizeof(int), 1, file);
fwrite(&m_currentBonus, sizeof(int), 1, file);
fwrite(&m_currentHiScore, sizeof(int), 1, file);
fclose(file);
#if defined(IS_ENGINE_HTML_5)
EM_ASM(FS.syncfs(false, function(err){console.log(err)});, 0);
#endif
}
}
void GameSystemExtended::loadData(std::string const &fileName)
{
FILE *file = NULL;
//file = fopen(fileName.c_str(), "rb");
if (file != NULL)
{
fread(&m_gameProgression, sizeof(int), 1, file);
fread(&m_currentLives, sizeof(int), 1, file);
fread(&m_currentBonus, sizeof(int), 1, file);
fread(&m_currentHiScore, sizeof(int), 1, file);
fclose(file);
}
}
}
================================================
FILE: app/src/main/cpp/GameTime.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/function/GameFunction.h"
#include "isEngine/system/function/GameTime.h"
namespace is
{
GameTime::GameTime():
m_minute(0),
m_second(0),
m_mSecond(0)
{
}
GameTime::GameTime(unsigned int ms):
m_minute(0),
m_second(0),
m_mSecond(0)
{
m_mSecond = ms;
m_second += m_mSecond / 60;
m_minute += m_second / 60;
m_mSecond %= 60;
m_second %= 60;
}
GameTime::GameTime(unsigned int m, unsigned int s, unsigned int ms):
m_minute(m),
m_second(s),
m_mSecond(ms)
{
}
GameTime::~GameTime()
{
}
void GameTime::step(const float &DELTA_TIME)
{
if (m_mSecond > 0) m_mSecond -= static_cast((is::VALUE_CONVERSION * is::VALUE_TIME) * DELTA_TIME);
else
{
if (m_second == 0)
{
if (m_minute > 0)
{
m_second = 59;
m_mSecond = 59;
m_minute--;
}
}
else
{
m_second--;
m_mSecond = 59;
}
}
}
void GameTime::addTimeValue(int m, int s, int ms)
{
m_minute += m;
m_second += s;
if (m_second > 59)
{
m_minute++;
m_second = m_second - 59;
}
m_mSecond += ms;
}
void GameTime::setTimeValue(int m, int s, int ms)
{
m_minute = m;
m_second = s;
m_mSecond = ms;
}
void GameTime::setMSecond(int ms)
{
m_second = 0;
m_minute = 0;
m_mSecond = ms;
m_second += m_mSecond / 60;
m_minute += m_second / 60;
m_mSecond %= 60;
m_second %= 60;
}
GameTime& GameTime::operator=(GameTime const &t)
{
m_minute = t.m_minute;
m_second = t.m_second;
m_mSecond = t.m_mSecond;
return *this;
}
unsigned int GameTime::getTimeValue() const
{
return ((m_minute * 3600) + (m_second * 60) + m_mSecond);
}
unsigned int GameTime::getMinute() const
{
return m_minute;
}
unsigned int GameTime::getSecond() const
{
return m_second;
}
unsigned int GameTime::getMSecond() const
{
return m_mSecond;
}
bool GameTime::compareTime(unsigned int m, unsigned int s, unsigned int ms) const
{
return (((m * 3600) + (s * 60) + ms) >= getTimeValue());
}
const std::string GameTime::getTimeString() const noexcept
{
std::string str;
str = writeZero(m_minute) + ":" + writeZero(m_second) + "." + writeZero(m_mSecond);
return str;
}
bool operator==(GameTime const &t1, GameTime const &t2)
{
return (t1.getTimeValue() == t2.getTimeValue());
}
bool operator>(GameTime const &t1, GameTime const &t2)
{
return (t1.getTimeValue() > t2.getTimeValue());
}
bool operator<(GameTime const &t1, GameTime const &t2)
{
return (t1.getTimeValue() < t2.getTimeValue());
}
std::ostream& operator<<(std::ostream &flux, GameTime const &t)
{
flux <<
t.m_minute << "m " <<
t.m_second << "s " <<
t.m_mSecond << "ms" <<
std::endl;
return flux;
}
}
================================================
FILE: app/src/main/cpp/Main.hpp
================================================
#ifndef MAIN_HPP
#define MAIN_HPP
#ifdef __APPLE__
#include "vscode/MacOS/MacHelper.hpp"
MacHelper macHelper;
#endif // __APPLE__
#ifdef __linux__
#include "vscode/Linux/LinuxHelper.hpp"
LinuxHelper linuxHelper;
#endif // __linux__
#ifdef _WIN32
#include "vscode/Win32/WindowsHelper.hpp"
WindowsHelper windowsHelper;
#endif // _WIN32
//
#endif // MAIN_HPP
================================================
FILE: app/src/main/cpp/MainObject.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/entity/MainObject.h"
namespace is
{
int MainObject::instanceNumber = 0;
MainObject::MainObject():
Name(),
#if defined(IS_ENGINE_USE_SDM)
Destructible(),
DepthObject(DepthObject::NORMAL_DEPTH),
Visibility(),
#endif
m_x(0.f),
m_y(0.f),
m_xStart(0.f),
m_yStart(0.f),
m_xPrevious(m_x),
m_yPrevious(m_y),
m_speed(0.f),
m_hsp(0.f),
m_vsp(0.f),
m_frameStart(0.f),
m_frameEnd(0.f),
m_frame(0.f),
m_imageXscale(1.f),
m_imageYscale(1.f),
m_imageScale(1.f),
m_imageAngle(0.f),
m_xOffset(0.f),
m_yOffset(0.f),
m_time(0.f),
m_w(32),
m_h(32),
m_imageAlpha(255),
m_imageIndex(0),
m_isActive(false),
m_isSDMSprite(false),
m_drawMask(false)
{
updateCollisionMask();
instanceNumber++;
m_instanceId = instanceNumber;
}
MainObject::MainObject(float x, float y):
Name(),
#if defined(IS_ENGINE_USE_SDM)
Destructible(),
DepthObject(DepthObject::NORMAL_DEPTH),
Visibility(),
#endif
m_x(x),
m_y(y),
m_xStart(x),
m_yStart(y),
m_xPrevious(m_x),
m_yPrevious(m_y),
m_speed(0.f),
m_hsp(0.f),
m_vsp(0.f),
m_frameStart(0.f),
m_frameEnd(0.f),
m_frame(0.f),
m_imageXscale(1.f),
m_imageYscale(1.f),
m_imageScale(1.f),
m_imageAngle(0.f),
m_xOffset(0.f),
m_yOffset(0.f),
m_time(0.f),
m_w(32),
m_h(32),
m_imageAlpha(255),
m_imageIndex(0),
m_isActive(false),
m_isSDMSprite(false),
m_drawMask(false)
{
updateCollisionMask();
instanceNumber++;
m_instanceId = instanceNumber;
}
MainObject::MainObject(sf::Sprite &spr, float x, float y):
Name(),
#if defined(IS_ENGINE_USE_SDM)
Destructible(),
DepthObject(DepthObject::NORMAL_DEPTH),
Visibility(),
#endif
m_x((static_cast(x) == 0) ? x : spr.getPosition().x),
m_y((static_cast(y) == 0) ? y : spr.getPosition().y),
m_xStart(m_x),
m_yStart(m_y),
m_xPrevious(m_x),
m_yPrevious(m_y),
m_speed(0.f),
m_hsp(0.f),
m_vsp(0.f),
m_frameStart(0.f),
m_frameEnd(0.f),
m_frame(0.f),
m_imageXscale(1.f),
m_imageYscale(1.f),
m_imageScale(1.f),
m_imageAngle(0.f),
m_xOffset(0.f),
m_yOffset(0.f),
m_time(0.f),
m_w(32),
m_h(32),
m_imageAlpha(255),
m_imageIndex(0),
m_isActive(false),
m_isSDMSprite(true),
m_drawMask(false),
m_sprParent(spr)
{
#if defined(IS_ENGINE_USE_SDM)
m_SDMcallStep = false;
m_SDMcallEvent = false;
#endif
setRectangleMask(spr.getTexture()->getSize().x, spr.getTexture()->getSize().y);
updateCollisionMask();
updateSprite();
instanceNumber++;
m_instanceId = instanceNumber;
}
MainObject::MainObject(sf::Texture &tex, float x, float y, bool center):
Name(),
#if defined(IS_ENGINE_USE_SDM)
Destructible(),
DepthObject(DepthObject::NORMAL_DEPTH),
#endif
m_x(x),
m_y(y),
m_xStart(m_x),
m_yStart(m_y),
m_xPrevious(m_x),
m_yPrevious(m_y),
m_speed(0.f),
m_hsp(0.f),
m_vsp(0.f),
m_frameStart(0.f),
m_frameEnd(0.f),
m_frame(0.f),
m_imageXscale(1.f),
m_imageYscale(1.f),
m_imageScale(1.f),
m_imageAngle(0.f),
m_xOffset(0.f),
m_yOffset(0.f),
m_time(0.f),
m_w(32),
m_h(32),
m_imageAlpha(255),
m_imageIndex(0),
m_isActive(false),
m_isSDMSprite(true),
m_drawMask(false)
{
m_centerSpr = center;
#if defined(IS_ENGINE_USE_SDM)
m_SDMcallStep = false;
m_SDMcallEvent = false;
#endif
setRectangleMask(tex.getSize().x, tex.getSize().y);
is::createSprite(tex, m_sprParent, sf::Vector2f(m_x, m_y), sf::Vector2f(0.f, 0.f));
if (!m_centerSpr) updateCollisionMask();
else
{
is::centerSFMLObj(m_sprParent);
centerCollisionMask(m_x, m_y);
}
updateSprite();
instanceNumber++;
m_instanceId = instanceNumber;
}
MainObject::~MainObject()
{
instanceNumber--;
}
void MainObject::setPosition(float x, float y)
{
m_xPrevious = m_x;
m_yPrevious = m_y;
m_x = x;
m_y = y;
updateSDMsprite();
}
void MainObject::setSpriteScale(float x, float y)
{
is::setSFMLObjScaleX_Y(m_sprParent, x, y);
}
void MainObject::setXStart(float x)
{
m_xStart = x;
}
void MainObject::setYStart(float y)
{
m_yStart = y;
}
void MainObject::setXPrevious(float x)
{
m_xPrevious = x;
}
void MainObject::setYPrevious(float y)
{
m_yPrevious = y;
}
void MainObject::setStartPosition(float x, float y)
{
m_xStart = x;
m_yStart = y;
}
void MainObject::setX(float x)
{
setPosition(x, m_y);
}
void MainObject::setY(float y)
{
setPosition(m_x, y);
}
void MainObject::moveX(float x)
{
setPosition(m_x + x, m_y);
}
void MainObject::moveY(float y)
{
setPosition(m_x, m_y + y);
}
void MainObject::setSpeed(float val)
{
m_speed = val;
}
void MainObject::setHsp(float val)
{
m_hsp = val;
}
void MainObject::setVsp(float val)
{
m_vsp = val;
}
void MainObject::setAngularMove(const float &DELTA_TIME, float speed, float angle)
{
m_x += (is::lengthDirX(speed, angle) * is::VALUE_CONVERSION) * DELTA_TIME;
m_y -= (is::lengthDirY(speed, angle) * is::VALUE_CONVERSION) * DELTA_TIME;
updateSDMsprite();
}
void MainObject::setFrame(float val)
{
m_frame = val;
}
void MainObject::setFrameStart(float val)
{
m_frameStart = val;
}
void MainObject::setFrameEnd(float val)
{
m_frameEnd = val;
}
void MainObject::setImageXscale(float val)
{
setImageScaleX_Y(val, m_imageYscale);
}
void MainObject::setImageYscale(float val)
{
setImageScaleX_Y(m_imageXscale, val);
}
void MainObject::setImageScale(float val, bool updateXYscale)
{
m_imageScale = val;
if (updateXYscale) setImageScaleX_Y(m_imageScale, m_imageScale);
}
void MainObject::setImageAngle(float val)
{
m_imageAngle = val;
updateSDMsprite();
}
void MainObject::setXOffset(float val)
{
setXYOffset(val, m_xOffset);
}
void MainObject::setYOffset(float val)
{
setXYOffset(m_xOffset, val);
}
void MainObject::setXYOffset(float x, float y)
{
m_xOffset = x;
m_yOffset = y;
updateSDMsprite();
}
void MainObject::setXYOffset()
{
setXYOffset(is::getSFMLObjOriginX(m_sprParent), is::getSFMLObjOriginY(m_sprParent));
}
void MainObject::setImageScaleX_Y(float x, float y)
{
m_imageXscale = x;
m_imageYscale = y;
updateSDMsprite();
}
void MainObject::setTime(float x)
{
m_time = x;
}
void MainObject::setImageAlpha(int val)
{
m_imageAlpha = val;
updateSDMsprite();
}
void MainObject::setImageIndex(int val)
{
m_imageIndex = val;
}
void MainObject::setMaskW(int val)
{
m_w = val;
}
void MainObject::setMaskH(int val)
{
m_h = val;
}
void MainObject::setRectangleMask(int width, int height)
{
m_w = width;
m_h = height;
m_circle.m_raduis = 0.f;
updateCollisionMask();
}
void MainObject::setCircleMask(float raduis)
{
m_circle.m_raduis = raduis;
m_w = 0;
m_h = 0;
updateCollisionMask();
}
void MainObject::setIsActive(bool val)
{
m_isActive = val;
}
void MainObject::updateCollisionMask()
{
if (m_w > 0 && m_h > 0)
{
m_aabb.m_left = static_cast(m_x);
m_aabb.m_top = static_cast(m_y);
m_aabb.m_right = static_cast(m_x) + m_w;
m_aabb.m_bottom = static_cast(m_y) + m_h;
}
else {m_circle.m_x = m_x; m_circle.m_y = m_y;}
}
void MainObject::updateCollisionMask(int x, int y)
{
if (m_w > 0 && m_h > 0)
{
m_aabb.m_left = static_cast(x);
m_aabb.m_top = static_cast(y);
m_aabb.m_right = static_cast(x) + m_w;
m_aabb.m_bottom = static_cast(y) + m_h;
}
else {m_circle.m_x = x; m_circle.m_y = y;}
}
void MainObject::centerCollisionMask(int x, int y)
{
if (m_w > 0 && m_h > 0)
{
m_aabb.m_left = static_cast(x - m_w / 2.f);
m_aabb.m_top = static_cast(y - m_h / 2.f);
m_aabb.m_right = static_cast(x + m_w / 2.f);
m_aabb.m_bottom = static_cast(y + m_h / 2.f);
}
else {m_circle.m_x = x; m_circle.m_y = y;}
}
void MainObject::updateSprite()
{
is::setSFMLObjAlpha(m_sprParent, m_imageAlpha);
is::setSFMLObjAngle(m_sprParent, m_imageAngle);
is::setSFMLObjScaleX_Y(m_sprParent, m_imageXscale, m_imageYscale);
is::setSFMLObjX_Y(m_sprParent, m_x + m_xOffset, m_y + m_yOffset);
}
void MainObject::updateSprite(float x, float y, float angle, int alpha, float xScale, float yScale, float xOffset, float yOffset)
{
is::setSFMLObjAlpha(m_sprParent, alpha);
is::setSFMLObjAngle(m_sprParent, angle);
is::setSFMLObjScaleX_Y(m_sprParent, xScale, yScale);
is::setSFMLObjX_Y(m_sprParent, x + xOffset, y + yOffset);
}
void MainObject::draw(is::Render &surface)
{
is::draw(surface, m_sprParent);
if (m_drawMask) drawMask(surface);
}
void MainObject::drawMask(is::Render &surface, sf::Color color)
{
// We draw the AABB (rectangle, square) mask only if it has dimensions
if (m_w > 0 && m_h > 0)
{
sf::RectangleShape rec(sf::Vector2f(static_cast(m_w), static_cast(m_h)));
rec.setOutlineThickness(1.f);
rec.setFillColor(sf::Color::Transparent);
rec.setOutlineColor(color);
is::setSFMLObjX_Y(rec, static_cast(m_aabb.m_left), static_cast(m_aabb.m_top));
is::draw(surface, rec);
}
else if (m_circle.m_raduis > 0.f) // We draw the circle mask only if it has dimensions
{
sf::CircleShape circle(m_circle.m_raduis);
circle.setOutlineThickness(1.f);
circle.setFillColor(sf::Color::Transparent);
circle.setOutlineColor(color);
is::centerSFMLObj(circle);
is::setSFMLObjX_Y(circle, m_circle.m_x, m_circle.m_y);
is::draw(surface, circle);
}
}
void MainObject::setFrameLimit(float frameStart, float frameEnd)
{
if (frameEnd > -1.f)
{
if (m_frame > frameEnd) m_frame = frameStart;
if (m_frame < frameStart) m_frame = frameStart;
}
else m_frame = frameStart;
}
float MainObject::distantToPoint(float x, float y) const
{
float X = (getX() + getMaskW() / 2) - x;
float Y = (getY() + getMaskH() / 2) - y;
return sqrt(X * X + Y * Y);
}
float MainObject::distantToObject(MainObject const *other, bool useSpritePosition) const
{
float X = ((useSpritePosition) ? getSpriteX() - other->getSpriteX() : (getX() + (getMaskW() / 2)) - (other->getX() + (other->getMaskW() / 2)));
float Y = ((useSpritePosition) ? getSpriteY() - other->getSpriteY() : (getY() + (getMaskH() / 2)) - (other->getY() + (other->getMaskH() / 2)));
return sqrt(X * X + Y * Y);
}
float MainObject::distantToObject(std::shared_ptr const &other, bool useSpritePosition) const
{
float X = ((useSpritePosition) ? getSpriteX() - other->getSpriteX() : (getX() + (getMaskW() / 2)) - (other->getX() + (other->getMaskW() / 2)));
float Y = ((useSpritePosition) ? getSpriteY() - other->getSpriteY() : (getY() + (getMaskH() / 2)) - (other->getY() + (other->getMaskH() / 2)));
return sqrt(X * X + Y * Y);
}
float MainObject::pointDirection(float x, float y) const
{
return (is::pointDirection(m_x, m_y, x, y));
}
float MainObject::pointDirection(std::shared_ptr const &other) const
{
return (is::pointDirection(m_x, m_y, other->getX(), other->getY()));
}
float MainObject::pointDirectionSprite(float x, float y) const
{
return (is::pointDirection(getSpriteX(), getSpriteY(), x, y));
}
float MainObject::pointDirectionSprite(std::shared_ptr const &other) const
{
return (is::pointDirection(getSpriteX(), getSpriteY(), other->getSpriteX(), other->getSpriteY()));
}
float MainObject::getSpeed() const
{
return m_speed;
}
float MainObject::getHsp() const
{
return m_hsp;
}
float MainObject::getVsp() const
{
return m_vsp;
}
float MainObject::getFrame() const
{
return m_frame;
}
float MainObject::getFrameStart() const
{
return m_frameStart;
}
float MainObject::getFrameEnd() const
{
return m_frameEnd;
}
float MainObject::getImageXscale() const
{
return m_imageXscale;
}
float MainObject::getImageYscale() const
{
return m_imageYscale;
}
float MainObject::getImageScale() const
{
return m_imageScale;
}
float MainObject::getImageAngle() const
{
return m_imageAngle;
}
float MainObject::getXOffset() const
{
return m_xOffset;
}
float MainObject::getYOffset() const
{
return m_yOffset;
}
float MainObject::getX() const
{
return m_x;
}
float MainObject::getY() const
{
return m_y;
}
float MainObject::getXStart() const
{
return m_xStart;
}
float MainObject::getYStart() const
{
return m_yStart;
}
float MainObject::getXPrevious() const
{
return m_xPrevious;
}
float MainObject::getYPrevious() const
{
return m_yPrevious;
}
float MainObject::getTime() const
{
return m_time;
}
int MainObject::getInstanceId() const
{
return m_instanceId;
}
unsigned int MainObject::getMaskW() const
{
return m_w;
}
unsigned int MainObject::getMaskH() const
{
return m_h;
}
bool MainObject::getIsActive() const
{
return m_isActive;
}
int MainObject::getImageAlpha() const
{
return m_imageAlpha;
}
int MainObject::getImageIndex() const
{
return m_imageIndex;
}
int MainObject::getSpriteWidth() const
{
return m_sprParent.getTextureRect().width;
}
int MainObject::getSpriteHeight() const
{
return m_sprParent.getTextureRect().height;
}
float MainObject::getSpriteX() const
{
return m_sprParent.getPosition().x;
}
float MainObject::getSpriteY() const
{
return m_sprParent.getPosition().y;
}
int MainObject::getTextureWidth() const
{
return is::getSFMLTextureWidth(m_sprParent.getTexture());
}
int MainObject::getTextureHeight() const
{
return is::getSFMLTextureHeight(m_sprParent.getTexture());
}
int MainObject::getSpriteCenterX() const
{
return (m_sprParent.getTextureRect().width / 2);
}
int MainObject::getSpriteCenterY() const
{
return (m_sprParent.getTextureRect().height / 2);
}
int MainObject::getSpriteNumberSubImage(int subImageWidth) const
{
return (m_sprParent.getTexture()->getSize().x / subImageWidth);
}
bool MainObject::placeMettingSubFunction(float x, float y, MainObject const *other) const
{
is::Rectangle testRec = this->getMask();
testRec.m_left += x;
testRec.m_right += x;
testRec.m_top += y;
testRec.m_bottom += y;
is::Circle testCircle = this->getCircleMask();
testCircle.m_x += x;
testCircle.m_y += y;
is::Rectangle otherRectangle = other->getMask();
is::Circle otherCircle = other->getCircleMask();
if (m_w > 0 && m_h > 0 && other->getMaskW() > 0 && other->getMaskH() > 0)
{
return (is::collisionTest(testRec, otherRectangle));
}
else if ((m_w == 0 || m_h == 0) && other->getMaskW() > 0 && other->getMaskH() > 0)
{
return (is::collisionTest(testCircle, otherRectangle));
}
else if ((m_w > 0 && m_h > 0) && (other->getMaskW() == 0 || other->getMaskH() == 0))
{
return (is::collisionTest(testRec, otherCircle));
}
else if ((m_w == 0 || m_h == 0) && testCircle.m_raduis > 0.f &&
(other->getMaskW() == 0 || other->getMaskH() == 0) && otherCircle.m_raduis > 0.f)
{
return (is::collisionTest(testCircle, otherCircle));
}
else
{
is::showLog("ERROR: Badly defined collision masks between these objects: <" + m_strName +
"> & <" + other->getName() + ">", true);
}
return false;
}
void MainObject::updateSDMsprite()
{
if (m_isSDMSprite)
{
if (m_centerSpr) centerCollisionMask(m_x, m_y); else updateCollisionMask();
updateSprite();
}
}
bool MainObject::placeMetting(int x, int y, MainObject const *other)
{
return placeMettingSubFunction(x, y, other);
}
bool MainObject::placeMetting(int x, int y, std::shared_ptr const &other)
{
return placeMettingSubFunction(x, y, other.get());
}
bool MainObject::inViewRec(sf::View const &view, bool useTexRec)
{
is::Rectangle testRec;
if (useTexRec)
{
testRec.m_left = m_x;
testRec.m_top = m_y;
testRec.m_right = m_x + ((m_sprParent.getGlobalBounds().width < 1) ? 32 : m_sprParent.getGlobalBounds().width);
testRec.m_bottom = m_y + ((m_sprParent.getGlobalBounds().height < 1) ? 32 : m_sprParent.getGlobalBounds().height);
}
else testRec = this->getMask();
is::Rectangle viewRec;
viewRec.m_left = view.getCenter().x - (view.getSize().x / 2.f);
viewRec.m_right = view.getCenter().x + (view.getSize().x / 2.f);
viewRec.m_top = view.getCenter().y - (view.getSize().y / 2.f);
viewRec.m_bottom = view.getCenter().y + (view.getSize().y / 2.f);
if (is::collisionTest(testRec, viewRec)) return true;
return false;
}
sf::Sprite& MainObject::getSprite()
{
return m_sprParent;
}
float COMPARE_DISTANCE(460.f);
bool operator<(const MainObject *a, const MainObject &b)
{
if (is::instanceExist(a)) return a->getX() < (b.getX() - COMPARE_DISTANCE);
else return false;
}
bool operator<(const MainObject &b, const MainObject *a)
{
if (is::instanceExist(a)) return (b.getX() + COMPARE_DISTANCE) < a->getX();
else return false;
}
bool operator<(std::shared_ptr const &a, const MainObject &b)
{
if (is::instanceExist(a)) return a->getX() < (b.getX() - COMPARE_DISTANCE);
else return false;
}
bool operator<(const MainObject &b, std::shared_ptr const &a)
{
if (is::instanceExist(a)) return (b.getX() + COMPARE_DISTANCE) < a->getX();
else return false;
}
}
================================================
FILE: app/src/main/cpp/PCH.hpp
================================================
#ifndef PRECOMPILED_HEADER_HPP
#define PRECOMPILED_HEADER_HPP
// Allow to use icon for Windows OS applications
#define IS_ENGINE_VS_CODE
#ifndef _DEBUG
#ifndef NDEBUG
#define NDEBUG
#endif
#endif // _DEBUG
// Raspberry Pi
#ifdef SFML_SYSTEM_LINUX
#ifdef __arm__
#define SFML_SYSTEM_PI
#endif
#endif // SFML SYSTEM_LINUX
// Typical stdafx.h
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Additional C/C++ libs
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Windows
#ifdef _WIN32
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include
#endif // _WIN32
// Utils
#include "vscode/Utility/Types.hpp"
// Macros
#define _UNUSED(x) (void)(x)
#endif // PRECOMPILED_HEADER_HPP
================================================
FILE: app/src/main/cpp/SDL_android_main.c
================================================
#if !defined(IS_ENGINE_VS_CODE) && !defined(IS_ENGINE_SWITCH)
#ifdef __ANDROID__
/*
SDL_android_main.c, placed in the public domain by Sam Lantinga 3/13/14
*/
#include "SDL_internal.h"
/* Include the SDL main definition header */
#include "SDL_main.h"
/*******************************************************************************
Functions called by JNI
*******************************************************************************/
#include
/* Called before SDL_main() to initialize JNI bindings in SDL library */
extern void SDL_Android_Init(JNIEnv* env, jclass cls);
/* This prototype is needed to prevent a warning about the missing prototype for global function below */
JNIEXPORT int JNICALL Java_com_author_isengine_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array);
/* Start up the SDL app */
JNIEXPORT int JNICALL Java_com_author_isengine_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array)
{
int i;
int argc;
int status;
int len;
char** argv;
/* This interface could expand with ABI negotiation, callbacks, etc. */
SDL_Android_Init(env, cls);
SDL_SetMainReady();
/* Prepare the arguments. */
len = (*env)->GetArrayLength(env, array);
argv = SDL_stack_alloc(char*, 1 + len + 1);
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
*/
argv[argc++] = SDL_strdup("app_process");
for (i = 0; i < len; ++i) {
const char* utf;
char* arg = NULL;
jstring string = (*env)->GetObjectArrayElement(env, array, i);
if (string) {
utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
arg = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
}
(*env)->DeleteLocalRef(env, string);
}
if (!arg) {
arg = SDL_strdup("");
}
argv[argc++] = arg;
}
argv[argc] = NULL;
/* Run the application. */
status = SDL_main(argc, argv);
/* Release the arguments. */
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
SDL_stack_free(argv);
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */
return status;
}
#endif /* __ANDROID__ */
/* vi: set ts=4 sw=4 expandtab: */
#endif /* IS_ENGINE_VS_CODE */
================================================
FILE: app/src/main/cpp/TransitionEffect.cpp
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2024 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as 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 "isEngine/system/graphic/TransitionEffect.h"
namespace is
{
TransitionEffect::TransitionEffect(is::GameDisplay *scene):
MainObject(),
Type(FADE_OUT),
m_scene(scene),
m_transitionEnd(false)
{
m_strName = "TransitionEffect";
m_imageAlpha = 255;
#if defined(IS_ENGINE_USE_SDM)
m_depth = -999999999;
#endif
// transition rectangle
is::createRectangle(m_recTransition, sf::Vector2f(scene->getViewW() + 10.f, scene->getViewH() + 10.f),
sf::Color(0, 0, 0, m_imageAlpha), scene->getViewW() / 2.f, scene->getViewH() / 2.f);
}
void TransitionEffect::step(const float &DELTA_TIME)
{
m_x = m_scene->getViewX();
m_y = m_scene->getViewY();
// transition fade out
if (m_type == FADE_OUT)
{
if (m_imageAlpha > 5)
{
m_imageAlpha -= static_cast((5.f * is::VALUE_CONVERSION) * DELTA_TIME);
m_transitionEnd = false;
}
else
{
m_imageAlpha = 0;
m_transitionEnd = true;
}
}
// transition fade in
if (m_type == FADE_IN)
{
if (m_imageAlpha < 250)
{
m_imageAlpha += static_cast((5.f * is::VALUE_CONVERSION) * DELTA_TIME);
m_transitionEnd = false;
}
else
{
m_imageAlpha = 255;
m_transitionEnd = true;
}
}
is::setSFMLObjFillColor(m_recTransition, sf::Color(0, 0, 0, m_imageAlpha));
is::setSFMLObjX_Y(m_recTransition, m_x, m_y);
}
void TransitionEffect::draw(is::Render &render)
{
is::draw(render, m_recTransition);
}
}
================================================
FILE: app/src/main/cpp/app_src/activity/GameActivity.h
================================================
#ifndef GAMEACTIVITY_H_INCLUDED
#define GAMEACTIVITY_H_INCLUDED
#include "../scenes/HelloScene/HelloScene.h"
// example
// #include "../scenes/YourScene/YourScene.h"
////////////////////////////////////////////////////////////
/// Allows to manage the different scenes of the game
////////////////////////////////////////////////////////////
class GameActivity
{
private:
std::shared_ptr m_gameScene;
public:
bool m_changeActivity = false;
GameActivity(is::GameSystemExtended &gameSysExt)
{
m_gameScene = nullptr;
////////////////////////////////////////////////////////////
// Allows to choose the scene that will be launched
switch (gameSysExt.m_launchOption)
{
case is::DisplayOption::HELLO_SCENE:
m_gameScene = std::make_shared(gameSysExt);
break;
/*
* /!\ WARNING! /!\
* This constructor is no longer supported in this version of the engine. Use the one in the example.
*
* m_gameScene = std::make_shared(activityCtrl.getWindow(), getView(), m_surface, gameSysExt);
*/
// example
// case is::DisplayOption::YOUR_SCENE:
// m_gameScene = std::make_shared(gameSysExt);
// break;
default:
is::showLog("ERROR: Scene not found !", true);
break;
}
m_gameScene->loadResources();
}
virtual void onUpdate()
{
if (m_gameScene->getIsRunning()) m_gameScene->step();
else
{
if (!m_changeActivity) m_changeActivity = true;
}
}
virtual void onDraw() {m_gameScene->drawScreen();}
virtual ~GameActivity() {}
};
#endif // GAMEACTIVITY_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/config/ExtraConfig.h
================================================
#ifndef EXTRACONFIG_H_INCLUDED
#define EXTRACONFIG_H_INCLUDED
// Uncomment to enable this function
// #define IS_ENGINE_USE_RENDER_TEXTURE ///< This feature coming soon !
/*
* 1) Uncomment this line (definition of the Preporcessor which is below) to use the engine's main render loop.
* 2) But if you want to use a basic SFML render loop comment out this line.
* It activates the "basicSFMLmain()" function which launches an SFML window.
* Very useful if you already have an existing project and want to integrate it into the engine.
* The "basicSFMLmain()" function is implemented in the "basicSFMLmain.cpp" file (found in the "cpp" directory).
* It is in this file that you can associate your code with that of the engine.
*/
#define IS_ENGINE_USE_MAIN_LOOP ///< Allows to use the engine's main render loop
// Uncomment to enable SDM function
#define IS_ENGINE_USE_SDM ///< Allows to use Step and Draw Manager
#define SND_FILE_EXTENSION ".wav"
// Uncomment to enable this function
#define IS_ENGINE_OPTIMIZE_PERF ///< Allows to activate the optimization in certain parts of the engine
// Uncomment to enable SHOW LOG function
#define IS_ENGINE_USE_SHOWLOG ///< Allows to show log in console
#include
#include
#include
#include
#include "../../isEngine/system/islibconnect/isLibConnect.h"
namespace is
{
inline bool fileExist(std::string const &fileName)
{
std::ifstream file(fileName.c_str());
return !file.fail();
}
}
#endif // EXTRACONFIG_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/config/GameConfig.h
================================================
#ifndef GAMECONFIG_H_INCLUDED
#define GAMECONFIG_H_INCLUDED
#include "ExtraConfig.h"
namespace is
{
////////////////////////////////////////////////////////////
/// \brief Allows to manipulate the different scenes and options
///
////////////////////////////////////////////////////////////
enum DisplayOption
{
HELLO_SCENE, ///< Access the hello scene
// example
// YOUR_SCENE, ///< Access to your scene
};
////////////////////////////////////////////////////////////
/// \brief Allows to manipulate the window style
///
////////////////////////////////////////////////////////////
enum WindowStyle
{
NONE, ///< No decoration at all
TITLEBAR, ///< The window has a titlebar
RESIZE, ///< The window can be resized and has a maximize button
CLOSE, ///< The window has a close button
FULLSCREEN, ///< The window is shown in fullscreen mode
DEFAULT ///< The default style, which is a shortcut for Titlebar | Resize | Close
};
////////////////////////////////////////////////////////////
/// Allows to define the general parameters of the game and
/// that the ad manager (Admob)
////////////////////////////////////////////////////////////
namespace GameConfig
{
static const unsigned int WINDOW_WIDTH = 640; ///< Window width work only for PC Platform
static const unsigned int WINDOW_HEIGHT = 480; ///< Window height work only for PC Platform
static const float VIEW_WIDTH = 640.f;
static const float VIEW_HEIGHT = 480.f;
static const float FPS = 60.f; ///< Game FPS
static const is::WindowStyle WINDOW_SETTINGS = WindowStyle::DEFAULT; ///< Window style
static const DisplayOption LAUNCH_OPTION = DisplayOption::HELLO_SCENE; ///< Represents the first scene to be launched
/// Represent the key which validates the options with the Mouse
static sf::Mouse::Button KEY_VALIDATION_MOUSE = sf::Mouse::Left;
/// Represent the key which validates the options with the Keyboard
static sf::Keyboard::Key KEY_VALIDATION_KEYBOARD = sf::Keyboard::Return;
/// Represent the key which cancel the options with the Keyboard
static sf::Keyboard::Key KEY_CANCEL = sf::Keyboard::Escape;
/// Represents the button A key
static sf::Keyboard::Key KEY_A = sf::Keyboard::W;
/// Represents the button B key
static sf::Keyboard::Key KEY_B = sf::Keyboard::X;
/// Represents the button X key
static sf::Keyboard::Key KEY_X = sf::Keyboard::Q;
/// Represents the button Y key
static sf::Keyboard::Key KEY_Y = sf::Keyboard::S;
/// Represents the Left directional key
static sf::Keyboard::Key KEY_LEFT = sf::Keyboard::Left;
/// Represents the Right directional key
static sf::Keyboard::Key KEY_RIGHT = sf::Keyboard::Right;
/// Represents the Up directional key
static sf::Keyboard::Key KEY_UP = sf::Keyboard::Up;
/// Represents the Down directional key
static sf::Keyboard::Key KEY_DOWN = sf::Keyboard::Down;
////////////////////////////////////////////////////////////
/// Default values that SFML texts will take when they are created
////////////////////////////////////////////////////////////
static const int DEFAULT_SFML_TEXT_SIZE = 20;
static const sf::Color &DEFAULT_SFML_TEXT_COLOR = sf::Color::Blue;
static const sf::Color &DEFAULT_SFML_SELECTED_TEXT_COLOR = sf::Color::White;
static const int DEFAULT_MSG_BOX_TEXT_SIZE = 20;
static const int DEFAULT_MSG_BOX_BUTTON_TEXT_SIZE = 18;
static const sf::Color &DEFAULT_MSG_BOX_TEXT_COLOR = sf::Color::White;
static const sf::Color &DEFAULT_MSG_BOX_SELECTED_TEXT_COLOR = sf::Color::Red;
static const int DEFAULT_RPG_DIALOG_TEXT_SIZE = 16;
static const int DEFAULT_RPG_DIALOG_BUTTON_TEXT_SIZE = 13;
static const sf::Color &DEFAULT_RPG_DIALOG_TEXT_COLOR = sf::Color::White;
static const sf::Color &DEFAULT_RPG_DIALOG_SELECTED_TEXT_COLOR = sf::Color::Blue;
static const sf::Color &DEFAULT_BUTTON_TEXT_COLOR = sf::Color::White;
static const std::string MAJOR = "1"; ///< Game major version
static const std::string MINOR = "0"; ///< Game minor version
inline std::string getGameVersion() {return MAJOR + "." + MINOR;} ///< return version of the game
static std::string const GAME_NAME = "Hello"; ///< Windows title name
static std::string const GAME_AUTHOR = "Author";
// parent directory
static std::string const ASSETS_DIR =
#if !defined(__ANDROID__)
#if defined(IS_ENGINE_QT)
(fileExist("assets/assets.dat") ? "" : "../../") +
#endif
std::string("assets/");
#elif defined(IS_ENGINE_HTML_5)
"/assets/"
#elif defined(IS_ENGINE_SWITCH)
"assets/"
#else
"";
#endif // defined
static std::string const GUI_DIR = ASSETS_DIR + "image/gui/"; ///< Path to resource files that serve as GUI
static std::string const FONT_DIR = ASSETS_DIR + "font/"; ///< Path to resource files that serve as Font
static std::string const SPRITES_DIR = ASSETS_DIR + "image/sprites/"; ///< Path to resource files that serve as Sprite
static std::string const TILES_DIR = ASSETS_DIR + "image/tiles/"; ///< Path to resource files that serve as tile and background
static std::string const SFX_DIR = ASSETS_DIR + "sound/sfx/"; ///< Path to resource files that serve as SFX
static std::string const MUSIC_DIR = ASSETS_DIR + "sound/music/"; ///< Path to resource files that serve as Music
static std::string const TMX_RSC_DIR = ASSETS_DIR + "maps/"; ///< Path to TMX resource files
#if defined(__ANDROID__)
////////////////////////////////////////////////////////////
/// \brief game package name
/// Represents the place where your data will be saved on Android
/// Replace this with your real package name (e.g. com.StudioName.GameName)
/// You must apply this name for the applicationId in the build.gradle file
////////////////////////////////////////////////////////////
static std::string const PACKAGE_NAME = "com.author.isengine";
#endif // defined
// parent directory
static std::string DATA_PARENT_DIR =
#if defined(__ANDROID__)
"/data/data/" + PACKAGE_NAME + "/"
#elif defined(IS_ENGINE_HTML_5)
"/save/"
#else
"save/"
#endif
;
///< Path to save game progress file
static std::string const GAME_DATA_FILE = DATA_PARENT_DIR + "game_data.bin";
///< Path to save game menu configuration file
static std::string const CONFIG_FILE = DATA_PARENT_DIR + "game_config.dat";
///< Path to save game pad configuration file
static std::string const GAME_PAD_FILE = DATA_PARENT_DIR + "game_pad_config.dat";
}
}
#endif // GAMECONFIG_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/gamesystem_ext/GameSystemExtended.h
================================================
#ifndef GAMESYSTEMEXTENDED_H_INCLUDED
#define GAMESYSTEMEXTENDED_H_INCLUDED
#include "../../isEngine/system/function/GameSystem.h"
#include "../levels/Level.h"
////////////////////////////////////////////////////////////
/// \brief Class derived from GameSystem to manage the
/// different engine components
///
/// Allows to manage the saving / loading of game and
/// configuration data, manipulate the data of the virtual
/// Game Pad and act on the different scenes of the game
////////////////////////////////////////////////////////////
namespace is
{
class GameSystemExtended : public GameSystem
{
public:
GameSystemExtended(sf::RenderWindow &window);
/// Initialize the data link to the game engine
void initSystemData();
/// Initialize game progress data
void initProgress();
/// Initialize game play data (bonus, score, ...)
void initData(bool clearCurrentLevel = true);
/// Save game play data
void saveData(std::string const &fileName);
/// Load game play data
void loadData(std::string const &fileName);
/// Allows to choose the scene that will be launched
is::DisplayOption m_launchOption = is::GameConfig::LAUNCH_OPTION; // Represents the first scene to be launched
int m_gameProgression;
int m_levelNumber;
int m_currentLevel;
int m_currentLives;
int m_currentBonus;
int m_currentScore;
int m_currentHiScore;
int m_levelTime;
};
}
#endif // GAMESYSTEMEXTENDED_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/language/GameLanguage.h
================================================
#ifndef GAMELANGUAGE_H_INCLUDED
#define GAMELANGUAGE_H_INCLUDED
#include "../../isEngine/system/function/GameKeyName.h"
/*
* This file allows you to define the languages you want to use in the game.
* To use a language you must define a array. the first index represents the first language
* (e.g lang_array[0] => eng) and the index following its translation (e.g lang_array[1] => fr).
*
* example to display several sentences in the dialog manager.
* lang_array[] = {"eng 1", "translation fr 1", "eng 2", "translation fr 2", ...};
* (Go to the GameDialog Class to see how we implement languages to make sentences in dialogs)
*/
namespace is
{
//////////////////////////////////////////////////////
/// \brief Access to content that allows internationalization of the game
///
//////////////////////////////////////////////////////
namespace lang
{
////////////////////////////////////////////////////////////
/// \brief Represent the index of each language
///
////////////////////////////////////////////////////////////
enum GameLanguage
{
ENGLISH, ///< English language index
FRANCAIS, ///< French language index
// example
// YOUR_LANGUAGE ///< Your language index
};
// ------------------------ message box answer ------------------------
static std::string pad_answer_ok[] = {"OK" , "OK"};
static std::string pad_answer_yes[] = {"YES", "OUI"};
static std::string pad_answer_no[] = {"NO" , "NON"};
// ------------------------ message box sentences ------------------------
static std::string msg_quit_game[] = {"Quit Game", "Quitter le Jeu"};
// example
// static std::string msg_your_message[] = {"Message in English", "Message in French"};
// ------------------------ RPG dialog ------------------------
static std::string pad_dialog_skip[] = {"Skip", "Passer"};
static std::string dialog_hello[] = {"Hello !",
"Salut !",
"Ready to make the future best game in the world!",
"En route pour invinter le futur meilleur jeu du monde !"};
// example
// static std::wstring dialog_your_dialog[] = {L"Represents the first message of the dialog in English",
// L"Represents the first message of the dialog in French",
// L"Represents the second message of the dialog in English",
// L"Represents the second message of the dialog in French"};
}
}
#endif // GAMELANGUAGE_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/levels/Level.h
================================================
#ifndef LEVEL_H_INCLUDED
#define LEVEL_H_INCLUDED
/*
* This file allows to include the level header generated by the is::Engine
* level editor to be able to use them with the engine components
*/
// #include "../levels/level_1.h"
// ...
namespace is
{
//////////////////////////////////////////////////////
/// \brief Access the content which allows to manage
/// the integration of game levels
///
//////////////////////////////////////////////////////
namespace level
{
////////////////////////////////////////////////////////////
/// \brief Enum represents a array containing the level data
///
/// Allows to identify and load the corresponding level
/// array in GameLevel
////////////////////////////////////////////////////////////
enum LevelId
{
LEVEL_1
// ...
////////////////////////////////////////////////////////////
// don't touch this. Add all level item before this one
, LEVEL_MAX ///< Allows you to know the number of levels
////////////////////////////////////////////////////////////
};
////////////////////////////////////////////////////////////
/// \brief Returns the level array according to its index
///
/// It is used in @a GameLevelLoadResource() to determine the
/// level array that will be loaded to create the game level
////////////////////////////////////////////////////////////
inline short const* getLevelMap(int CURRENT_LEVEL)
{
switch (CURRENT_LEVEL)
{
// case LEVEL_1 : return LEVEL_1_MAP; break;
// ...
default: return 0; break;
}
}
}
}
#endif // LEVEL_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/objects/HelloWorld.h
================================================
#pragma once
#include "../../isEngine/system/display/GameDisplay.h"
//////////////////////////////////////////////////////
/// \brief This class allows to scroll a "Hello world!"
/// on the screen and perform touch / click detection tests
//////////////////////////////////////////////////////
class HelloWorld : public is::MainObject
{
public:
HelloWorld(float x, float y, is::GameDisplay *scene):
is::MainObject(x ,y),
m_scene(scene)
{
// Create the sprite of object and center it
m_xOffset = 80.f; // set offset x to center the image
m_yOffset = 82.f; // set offset y to center the image
is::createSprite(scene->GRMgetTexture("hello_world"), m_sprParent, sf::Vector2f(m_x, m_y), sf::Vector2f(m_xOffset, m_yOffset));
// Display depth of the object in the scene
m_depth = -1;
}
void step(float const &DELTA_TIME)
{
// When you touch (on Android) or click on the sprite of the object it moves down (in pixel)
if (m_scene->mouseCollision(m_sprParent) && m_scene->getGameSystem().isPressed())
{
// VALUE_CONVERSION : allows to avoid using large values to do operations
// (basically it converts small values to large) and it also acts on the timing
// of the program
m_imageScale += (is::VALUE_CONVERSION * 0.05f) * DELTA_TIME; // scale the image
if (m_imageScale > 2.f) m_imageScale = 1.f;
m_imageXscale = m_imageScale;
m_imageYscale = m_imageScale;
m_y += (is::VALUE_CONVERSION * 1.f) * DELTA_TIME; // move (down) object on y axis
}
// moved the object to the right (in pixel)
m_x += (is::VALUE_CONVERSION * 2.f) * DELTA_TIME;
// If the object comes out to the right or at the top of the scene, bring it back
// to its starting position
// By default the size of the scene is equal to that of the window
if (m_x > m_scene->getSceneWidth()) m_x = m_xStart - (m_xOffset * 2.f);
if (m_y > m_scene->getSceneHeight() - 32.f) m_y = m_yStart - m_yOffset;
updateSprite(); // update the sprite with all object variables (x, y, angle, scale, ...)
}
private:
is::GameDisplay *m_scene;
};
================================================
FILE: app/src/main/cpp/app_src/objects/widgets/GameDialog.h
================================================
#ifndef GAMEDIALOG_H_INCLUDED
#define GAMEDIALOG_H_INCLUDED
#include
#include "../../../isEngine/system/display/GameDisplay.h"
#include "../../language/GameLanguage.h"
////////////////////////////////////////////////////////////
/// \brief Displays and manages game dialogs
///
////////////////////////////////////////////////////////////
namespace is
{
class GameDialog : public is::MainObject
{
public:
GameDialog(sf::Texture &tex, sf::Font &fnt, is::GameDisplay *scene);
////////////////////////////////////////////////////////////
/// \brief Represents the different dialogs
///
/// Each enum is linked to an array of string representing
/// a dialogs found in GameLanguage.h
////////////////////////////////////////////////////////////
enum DialogIndex
{
DIALOG_NONE = -1,
DIALOG_HELLO,
// example
// DIALOG_YOUR_DIALOG
};
////////////////////////////////////////////////////////////
/// \brief Link enum to an array of string representing the
/// dialog in GameLanguage.h
///
/// Each time an array of string representing a dialog is added
/// it must be linked to its enum to be able to launch it later
/// with the setDialog() method.
////////////////////////////////////////////////////////////
void linkArrayToEnum()
{
auto setMsg = [this](std::string txt)
{
m_strDialog = txt;
};
auto checkMsg =[this, &setMsg](std::string txt[])
{
if (m_msgIndex < m_msgIndexMax) setMsg(txt[m_msgIndex + m_scene->getGameSystem().m_gameLanguage]);
};
// each enum with its array of string
switch (m_dialogIndex)
{
case DIALOG_HELLO:
m_msgIndexMax = is::arraySize(is::lang::dialog_hello);
checkMsg(is::lang::dialog_hello);
break;
// example
// case DIALOG_YOUR_DIALOG:
// m_msgIndexMax = is::arraySize(is::lang::dialog_your_dialog);
// checkMsg(is::lang::dialog_your_dialog);
// break;
default:
break;
}
}
void step(const float &DELTA_TIME);
/// launch a dialog based on the enumeration index
void setDialog(DialogIndex dialogIndex);
void setMouseInCollison(bool val);
void draw(is::Render &surface);
DialogIndex getDialogIndex() const
{
return m_dialogIndex;
}
bool getMouseInCollison() const
{
return m_mouseInCollison;
}
bool showDialog() const
{
return m_showDialog;
}
private:
is::GameDisplay *m_scene;
sf::Text m_txtDialog, m_txtSkip;
std::string m_strDialog;
sf::Sprite m_sprNext, m_sprSkip;
bool m_showDialog, m_mouseInCollison, m_dialogEnd, m_newLine;
int m_msgIndex, m_msgIndexMax, m_size;
float m_blindTime;
DialogIndex m_dialogIndex;
};
}
#endif // GAMEDIALOG_H_INCLUDED
================================================
FILE: app/src/main/cpp/app_src/scenes/HelloScene/HelloScene.h
================================================
#pragma once
#include "../../../isEngine/system/entity/Background.h"
#include "../../objects/widgets/GameDialog.h"
#include "../../objects/HelloWorld.h"
class HelloScene : public is::GameDisplay
{
public:
/* /!\ WARNING! /!\
* This constructor is no longer supported in this version of the engine. Use the one below.
*
* HelloScene(sf::RenderWindow &window, sf::View &view, is::Render &surface, is::GameSystemExtended &gameSysExt):
* GameDisplay(window, view, surface, gameSysExt, sf::Color::White) {}
*/
HelloScene(is::GameSystemExtended &gameSysExt):
GameDisplay(gameSysExt, sf::Color::White /* => scene color*/) {}
void loadResources() {
m_gameSysExt.m_gameLanguage = is::lang::ENGLISH; // set default game language
// uncomment to change English language in French
// m_gameSysExt.m_gameLanguage = is::lang::FRANCAIS;
// load font and texture
GameDisplay::loadParentResources(); // allows to load system resource (very important never forgot to call him)
GRMaddTexture("is_engine_logo", is::GameConfig::SPRITES_DIR + "is_engine_logo.png");
GRMaddTexture("hello_world", is::GameConfig::SPRITES_DIR + "hello_world.png");
auto &texBg = GRMaddTexture("background", is::GameConfig::TILES_DIR + "background.png");
auto &texDialog = GRMaddTexture("dialog_box", is::GameConfig::GUI_DIR + "dialog_box.png");
// add a background to the position x = 0, y = 0 which will fill the scene and which will be scrolled (scrolling speed = 0.5)
SDMaddSceneObject(std::make_shared(texBg, 0.f, 0.f, this, 0.5f, -0.5f, false, false));
// add an SFML sprite which will be above the background and which will have the name "Logo" (by default x = 0 and y = 0)
SDMaddSprite(GRMgetTexture("is_engine_logo"), "Logo", 0.f, 62.f, false, -1);
// add an object at position x = 0, y = 0 which will be updated and displayed in the scene
SDMaddSceneObject(std::make_shared(0.f, 0.f, this));
// add RPG style game dialog
auto gameDialog = std::make_shared(texDialog, GRMgetFont("font_msg"), this);
gameDialog->setDepth(-2); // the display depth (make it appear on all objects. The object with the smallest value appears on the others)
gameDialog->setDialog(is::GameDialog::DialogIndex::DIALOG_HELLO); // set the corresponding dialog (See GameDialog.h and GameLanguage.h for more details on creating a message for dialogue)
SDMaddSceneObject(gameDialog);
// add and play music
GSMaddSound("game_music", is::GameConfig::MUSIC_DIR + "game_music.wav");
GSMplaySound("game_music");
GSMsetSoundLoop("game_music", true);
}
};
================================================
FILE: app/src/main/cpp/b2BlockAllocator.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include
#include
#include
#include
int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
{
16, // 0
32, // 1
64, // 2
96, // 3
128, // 4
160, // 5
192, // 6
224, // 7
256, // 8
320, // 9
384, // 10
448, // 11
512, // 12
640, // 13
};
uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
bool b2BlockAllocator::s_blockSizeLookupInitialized;
struct b2Chunk
{
int32 blockSize;
b2Block* blocks;
};
struct b2Block
{
b2Block* next;
};
b2BlockAllocator::b2BlockAllocator()
{
b2Assert(b2_blockSizes < UCHAR_MAX);
m_chunkSpace = b2_chunkArrayIncrement;
m_chunkCount = 0;
m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
memset(m_freeLists, 0, sizeof(m_freeLists));
if (s_blockSizeLookupInitialized == false)
{
int32 j = 0;
for (int32 i = 1; i <= b2_maxBlockSize; ++i)
{
b2Assert(j < b2_blockSizes);
if (i <= s_blockSizes[j])
{
s_blockSizeLookup[i] = (uint8)j;
}
else
{
++j;
s_blockSizeLookup[i] = (uint8)j;
}
}
s_blockSizeLookupInitialized = true;
}
}
b2BlockAllocator::~b2BlockAllocator()
{
for (int32 i = 0; i < m_chunkCount; ++i)
{
b2Free(m_chunks[i].blocks);
}
b2Free(m_chunks);
}
void* b2BlockAllocator::Allocate(int32 size)
{
if (size == 0)
return NULL;
b2Assert(0 < size);
if (size > b2_maxBlockSize)
{
return b2Alloc(size);
}
int32 index = s_blockSizeLookup[size];
b2Assert(0 <= index && index < b2_blockSizes);
if (m_freeLists[index])
{
b2Block* block = m_freeLists[index];
m_freeLists[index] = block->next;
return block;
}
else
{
if (m_chunkCount == m_chunkSpace)
{
b2Chunk* oldChunks = m_chunks;
m_chunkSpace += b2_chunkArrayIncrement;
m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
b2Free(oldChunks);
}
b2Chunk* chunk = m_chunks + m_chunkCount;
chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
#if defined(_DEBUG)
memset(chunk->blocks, 0xcd, b2_chunkSize);
#endif
int32 blockSize = s_blockSizes[index];
chunk->blockSize = blockSize;
int32 blockCount = b2_chunkSize / blockSize;
b2Assert(blockCount * blockSize <= b2_chunkSize);
for (int32 i = 0; i < blockCount - 1; ++i)
{
b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
block->next = next;
}
b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
last->next = NULL;
m_freeLists[index] = chunk->blocks->next;
++m_chunkCount;
return chunk->blocks;
}
}
void b2BlockAllocator::Free(void* p, int32 size)
{
if (size == 0)
{
return;
}
b2Assert(0 < size);
if (size > b2_maxBlockSize)
{
b2Free(p);
return;
}
int32 index = s_blockSizeLookup[size];
b2Assert(0 <= index && index < b2_blockSizes);
#ifdef _DEBUG
// Verify the memory address and size is valid.
int32 blockSize = s_blockSizes[index];
bool found = false;
for (int32 i = 0; i < m_chunkCount; ++i)
{
b2Chunk* chunk = m_chunks + i;
if (chunk->blockSize != blockSize)
{
b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
(int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
}
else
{
if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
{
found = true;
}
}
}
b2Assert(found);
memset(p, 0xfd, blockSize);
#endif
b2Block* block = (b2Block*)p;
block->next = m_freeLists[index];
m_freeLists[index] = block;
}
void b2BlockAllocator::Clear()
{
for (int32 i = 0; i < m_chunkCount; ++i)
{
b2Free(m_chunks[i].blocks);
}
m_chunkCount = 0;
memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
memset(m_freeLists, 0, sizeof(m_freeLists));
}
================================================
FILE: app/src/main/cpp/b2Body.cpp
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2Joint.h"
b2Body::b2Body(const b2BodyDef* bd, b2World* world)
{
b2Assert(bd->position.IsValid());
b2Assert(bd->linearVelocity.IsValid());
b2Assert(b2IsValid(bd->angle));
b2Assert(b2IsValid(bd->angularVelocity));
b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
m_flags = 0;
if (bd->bullet)
{
m_flags |= e_bulletFlag;
}
if (bd->fixedRotation)
{
m_flags |= e_fixedRotationFlag;
}
if (bd->allowSleep)
{
m_flags |= e_autoSleepFlag;
}
if (bd->awake)
{
m_flags |= e_awakeFlag;
}
if (bd->active)
{
m_flags |= e_activeFlag;
}
m_world = world;
m_xf.p = bd->position;
m_xf.q.Set(bd->angle);
m_sweep.localCenter.SetZero();
m_sweep.c0 = m_xf.p;
m_sweep.c = m_xf.p;
m_sweep.a0 = bd->angle;
m_sweep.a = bd->angle;
m_sweep.alpha0 = 0.0f;
m_jointList = NULL;
m_contactList = NULL;
m_prev = NULL;
m_next = NULL;
m_linearVelocity = bd->linearVelocity;
m_angularVelocity = bd->angularVelocity;
m_linearDamping = bd->linearDamping;
m_angularDamping = bd->angularDamping;
m_gravityScale = bd->gravityScale;
m_force.SetZero();
m_torque = 0.0f;
m_sleepTime = 0.0f;
m_type = bd->type;
if (m_type == b2_dynamicBody)
{
m_mass = 1.0f;
m_invMass = 1.0f;
}
else
{
m_mass = 0.0f;
m_invMass = 0.0f;
}
m_I = 0.0f;
m_invI = 0.0f;
m_userData = bd->userData;
m_fixtureList = NULL;
m_fixtureCount = 0;
}
b2Body::~b2Body()
{
// shapes and joints are destroyed in b2World::Destroy
}
void b2Body::SetType(b2BodyType type)
{
b2Assert(m_world->IsLocked() == false);
if (m_world->IsLocked() == true)
{
return;
}
if (m_type == type)
{
return;
}
m_type = type;
ResetMassData();
if (m_type == b2_staticBody)
{
m_linearVelocity.SetZero();
m_angularVelocity = 0.0f;
m_sweep.a0 = m_sweep.a;
m_sweep.c0 = m_sweep.c;
SynchronizeFixtures();
}
SetAwake(true);
m_force.SetZero();
m_torque = 0.0f;
// Delete the attached contacts.
b2ContactEdge* ce = m_contactList;
while (ce)
{
b2ContactEdge* ce0 = ce;
ce = ce->next;
m_world->m_contactManager.Destroy(ce0->contact);
}
m_contactList = NULL;
// Touch the proxies so that new contacts will be created (when appropriate)
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
int32 proxyCount = f->m_proxyCount;
for (int32 i = 0; i < proxyCount; ++i)
{
broadPhase->TouchProxy(f->m_proxies[i].proxyId);
}
}
}
b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
{
b2Assert(m_world->IsLocked() == false);
if (m_world->IsLocked() == true)
{
return NULL;
}
b2BlockAllocator* allocator = &m_world->m_blockAllocator;
void* memory = allocator->Allocate(sizeof(b2Fixture));
b2Fixture* fixture = new (memory) b2Fixture;
fixture->Create(allocator, this, def);
if (m_flags & e_activeFlag)
{
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
fixture->CreateProxies(broadPhase, m_xf);
}
fixture->m_next = m_fixtureList;
m_fixtureList = fixture;
++m_fixtureCount;
fixture->m_body = this;
// Adjust mass properties if needed.
if (fixture->m_density > 0.0f)
{
ResetMassData();
}
// Let the world know we have a new fixture. This will cause new contacts
// to be created at the beginning of the next time step.
m_world->m_flags |= b2World::e_newFixture;
return fixture;
}
b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)
{
b2FixtureDef def;
def.shape = shape;
def.density = density;
return CreateFixture(&def);
}
void b2Body::DestroyFixture(b2Fixture* fixture)
{
b2Assert(m_world->IsLocked() == false);
if (m_world->IsLocked() == true)
{
return;
}
b2Assert(fixture->m_body == this);
// Remove the fixture from this body's singly linked list.
b2Assert(m_fixtureCount > 0);
b2Fixture** node = &m_fixtureList;
bool found = false;
while (*node != NULL)
{
if (*node == fixture)
{
*node = fixture->m_next;
found = true;
break;
}
node = &(*node)->m_next;
}
// You tried to remove a shape that is not attached to this body.
b2Assert(found);
// Destroy any contacts associated with the fixture.
b2ContactEdge* edge = m_contactList;
while (edge)
{
b2Contact* c = edge->contact;
edge = edge->next;
b2Fixture* fixtureA = c->GetFixtureA();
b2Fixture* fixtureB = c->GetFixtureB();
if (fixture == fixtureA || fixture == fixtureB)
{
// This destroys the contact and removes it from
// this body's contact list.
m_world->m_contactManager.Destroy(c);
}
}
b2BlockAllocator* allocator = &m_world->m_blockAllocator;
if (m_flags & e_activeFlag)
{
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
fixture->DestroyProxies(broadPhase);
}
fixture->Destroy(allocator);
fixture->m_body = NULL;
fixture->m_next = NULL;
fixture->~b2Fixture();
allocator->Free(fixture, sizeof(b2Fixture));
--m_fixtureCount;
// Reset the mass data.
ResetMassData();
}
void b2Body::ResetMassData()
{
// Compute mass data from shapes. Each shape has its own density.
m_mass = 0.0f;
m_invMass = 0.0f;
m_I = 0.0f;
m_invI = 0.0f;
m_sweep.localCenter.SetZero();
// Static and kinematic bodies have zero mass.
if (m_type == b2_staticBody || m_type == b2_kinematicBody)
{
m_sweep.c0 = m_xf.p;
m_sweep.c = m_xf.p;
m_sweep.a0 = m_sweep.a;
return;
}
b2Assert(m_type == b2_dynamicBody);
// Accumulate mass over all fixtures.
b2Vec2 localCenter = b2Vec2_zero;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
if (f->m_density == 0.0f)
{
continue;
}
b2MassData massData;
f->GetMassData(&massData);
m_mass += massData.mass;
localCenter += massData.mass * massData.center;
m_I += massData.I;
}
// Compute center of mass.
if (m_mass > 0.0f)
{
m_invMass = 1.0f / m_mass;
localCenter *= m_invMass;
}
else
{
// Force all dynamic bodies to have a positive mass.
m_mass = 1.0f;
m_invMass = 1.0f;
}
if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
{
// Center the inertia about the center of mass.
m_I -= m_mass * b2Dot(localCenter, localCenter);
b2Assert(m_I > 0.0f);
m_invI = 1.0f / m_I;
}
else
{
m_I = 0.0f;
m_invI = 0.0f;
}
// Move center of mass.
b2Vec2 oldCenter = m_sweep.c;
m_sweep.localCenter = localCenter;
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
// Update center of mass velocity.
m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
}
void b2Body::SetMassData(const b2MassData* massData)
{
b2Assert(m_world->IsLocked() == false);
if (m_world->IsLocked() == true)
{
return;
}
if (m_type != b2_dynamicBody)
{
return;
}
m_invMass = 0.0f;
m_I = 0.0f;
m_invI = 0.0f;
m_mass = massData->mass;
if (m_mass <= 0.0f)
{
m_mass = 1.0f;
}
m_invMass = 1.0f / m_mass;
if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
{
m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
b2Assert(m_I > 0.0f);
m_invI = 1.0f / m_I;
}
// Move center of mass.
b2Vec2 oldCenter = m_sweep.c;
m_sweep.localCenter = massData->center;
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
// Update center of mass velocity.
m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
}
bool b2Body::ShouldCollide(const b2Body* other) const
{
// At least one body should be dynamic.
if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
{
return false;
}
// Does a joint prevent collision?
for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
{
if (jn->other == other)
{
if (jn->joint->m_collideConnected == false)
{
return false;
}
}
}
return true;
}
void b2Body::SetTransform(const b2Vec2& position, float32 angle)
{
b2Assert(m_world->IsLocked() == false);
if (m_world->IsLocked() == true)
{
return;
}
m_xf.q.Set(angle);
m_xf.p = position;
m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
m_sweep.a = angle;
m_sweep.c0 = m_sweep.c;
m_sweep.a0 = angle;
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
f->Synchronize(broadPhase, m_xf, m_xf);
}
}
void b2Body::SynchronizeFixtures()
{
b2Transform xf1;
xf1.q.Set(m_sweep.a0);
xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter);
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
f->Synchronize(broadPhase, xf1, m_xf);
}
}
void b2Body::SetActive(bool flag)
{
b2Assert(m_world->IsLocked() == false);
if (flag == IsActive())
{
return;
}
if (flag)
{
m_flags |= e_activeFlag;
// Create all proxies.
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
f->CreateProxies(broadPhase, m_xf);
}
// Contacts are created the next time step.
}
else
{
m_flags &= ~e_activeFlag;
// Destroy all proxies.
b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
f->DestroyProxies(broadPhase);
}
// Destroy the attached contacts.
b2ContactEdge* ce = m_contactList;
while (ce)
{
b2ContactEdge* ce0 = ce;
ce = ce->next;
m_world->m_contactManager.Destroy(ce0->contact);
}
m_contactList = NULL;
}
}
void b2Body::SetFixedRotation(bool flag)
{
bool status = (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
if (status == flag)
{
return;
}
if (flag)
{
m_flags |= e_fixedRotationFlag;
}
else
{
m_flags &= ~e_fixedRotationFlag;
}
m_angularVelocity = 0.0f;
ResetMassData();
}
void b2Body::Dump()
{
int32 bodyIndex = m_islandIndex;
b2Log("{\n");
b2Log(" b2BodyDef bd;\n");
b2Log(" bd.type = b2BodyType(%d);\n", m_type);
b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y);
b2Log(" bd.angle = %.15lef;\n", m_sweep.a);
b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y);
b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity);
b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping);
b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping);
b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag);
b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag);
b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag);
b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag);
b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag);
b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale);
b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex);
b2Log("\n");
for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
{
b2Log(" {\n");
f->Dump(bodyIndex);
b2Log(" }\n");
}
b2Log("}\n");
}
================================================
FILE: app/src/main/cpp/b2BroadPhase.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2BroadPhase.h"
b2BroadPhase::b2BroadPhase()
{
m_proxyCount = 0;
m_pairCapacity = 16;
m_pairCount = 0;
m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
m_moveCapacity = 16;
m_moveCount = 0;
m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
}
b2BroadPhase::~b2BroadPhase()
{
b2Free(m_moveBuffer);
b2Free(m_pairBuffer);
}
int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)
{
int32 proxyId = m_tree.CreateProxy(aabb, userData);
++m_proxyCount;
BufferMove(proxyId);
return proxyId;
}
void b2BroadPhase::DestroyProxy(int32 proxyId)
{
UnBufferMove(proxyId);
--m_proxyCount;
m_tree.DestroyProxy(proxyId);
}
void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
{
bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement);
if (buffer)
{
BufferMove(proxyId);
}
}
void b2BroadPhase::TouchProxy(int32 proxyId)
{
BufferMove(proxyId);
}
void b2BroadPhase::BufferMove(int32 proxyId)
{
if (m_moveCount == m_moveCapacity)
{
int32* oldBuffer = m_moveBuffer;
m_moveCapacity *= 2;
m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32));
b2Free(oldBuffer);
}
m_moveBuffer[m_moveCount] = proxyId;
++m_moveCount;
}
void b2BroadPhase::UnBufferMove(int32 proxyId)
{
for (int32 i = 0; i < m_moveCount; ++i)
{
if (m_moveBuffer[i] == proxyId)
{
m_moveBuffer[i] = e_nullProxy;
}
}
}
// This is called from b2DynamicTree::Query when we are gathering pairs.
bool b2BroadPhase::QueryCallback(int32 proxyId)
{
// A proxy cannot form a pair with itself.
if (proxyId == m_queryProxyId)
{
return true;
}
// Grow the pair buffer as needed.
if (m_pairCount == m_pairCapacity)
{
b2Pair* oldBuffer = m_pairBuffer;
m_pairCapacity *= 2;
m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
b2Free(oldBuffer);
}
m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);
m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);
++m_pairCount;
return true;
}
================================================
FILE: app/src/main/cpp/b2ChainAndCircleContact.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include
b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact));
return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB);
}
void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact();
allocator->Free(contact, sizeof(b2ChainAndCircleContact));
}
b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB)
: b2Contact(fixtureA, indexA, fixtureB, indexB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_chain);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape();
b2EdgeShape edge;
chain->GetChildEdge(&edge, m_indexA);
b2CollideEdgeAndCircle( manifold, &edge, xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2ChainAndPolygonContact.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include
b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact));
return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB);
}
void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact();
allocator->Free(contact, sizeof(b2ChainAndPolygonContact));
}
b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB)
: b2Contact(fixtureA, indexA, fixtureB, indexB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_chain);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape();
b2EdgeShape edge;
chain->GetChildEdge(&edge, m_indexA);
b2CollideEdgeAndPolygon( manifold, &edge, xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2ChainShape.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include
#include
#include
b2ChainShape::~b2ChainShape()
{
b2Free(m_vertices);
m_vertices = NULL;
m_count = 0;
}
void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
{
b2Assert(m_vertices == NULL && m_count == 0);
b2Assert(count >= 3);
for (int32 i = 1; i < count; ++i)
{
b2Vec2 v1 = vertices[i-1];
b2Vec2 v2 = vertices[i];
// If the code crashes here, it means your vertices are too close together.
b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
}
m_count = count + 1;
m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
memcpy(m_vertices, vertices, count * sizeof(b2Vec2));
m_vertices[count] = m_vertices[0];
m_prevVertex = m_vertices[m_count - 2];
m_nextVertex = m_vertices[1];
m_hasPrevVertex = true;
m_hasNextVertex = true;
}
void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
{
b2Assert(m_vertices == NULL && m_count == 0);
b2Assert(count >= 2);
for (int32 i = 1; i < count; ++i)
{
b2Vec2 v1 = vertices[i-1];
b2Vec2 v2 = vertices[i];
// If the code crashes here, it means your vertices are too close together.
b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
}
m_count = count;
m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
m_hasPrevVertex = false;
m_hasNextVertex = false;
m_prevVertex.SetZero();
m_nextVertex.SetZero();
}
void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
{
m_prevVertex = prevVertex;
m_hasPrevVertex = true;
}
void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
{
m_nextVertex = nextVertex;
m_hasNextVertex = true;
}
b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2ChainShape));
b2ChainShape* clone = new (mem) b2ChainShape;
clone->CreateChain(m_vertices, m_count);
clone->m_prevVertex = m_prevVertex;
clone->m_nextVertex = m_nextVertex;
clone->m_hasPrevVertex = m_hasPrevVertex;
clone->m_hasNextVertex = m_hasNextVertex;
return clone;
}
int32 b2ChainShape::GetChildCount() const
{
// edge count = vertex count - 1
return m_count - 1;
}
void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const
{
b2Assert(0 <= index && index < m_count - 1);
edge->m_type = b2Shape::e_edge;
edge->m_radius = m_radius;
edge->m_vertex1 = m_vertices[index + 0];
edge->m_vertex2 = m_vertices[index + 1];
if (index > 0)
{
edge->m_vertex0 = m_vertices[index - 1];
edge->m_hasVertex0 = true;
}
else
{
edge->m_vertex0 = m_prevVertex;
edge->m_hasVertex0 = m_hasPrevVertex;
}
if (index < m_count - 2)
{
edge->m_vertex3 = m_vertices[index + 2];
edge->m_hasVertex3 = true;
}
else
{
edge->m_vertex3 = m_nextVertex;
edge->m_hasVertex3 = m_hasNextVertex;
}
}
bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
{
B2_NOT_USED(xf);
B2_NOT_USED(p);
return false;
}
bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& xf, int32 childIndex) const
{
b2Assert(childIndex < m_count);
b2EdgeShape edgeShape;
int32 i1 = childIndex;
int32 i2 = childIndex + 1;
if (i2 == m_count)
{
i2 = 0;
}
edgeShape.m_vertex1 = m_vertices[i1];
edgeShape.m_vertex2 = m_vertices[i2];
return edgeShape.RayCast(output, input, xf, 0);
}
void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
{
b2Assert(childIndex < m_count);
int32 i1 = childIndex;
int32 i2 = childIndex + 1;
if (i2 == m_count)
{
i2 = 0;
}
b2Vec2 v1 = b2Mul(xf, m_vertices[i1]);
b2Vec2 v2 = b2Mul(xf, m_vertices[i2]);
aabb->lowerBound = b2Min(v1, v2);
aabb->upperBound = b2Max(v1, v2);
}
void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const
{
B2_NOT_USED(density);
massData->mass = 0.0f;
massData->center.SetZero();
massData->I = 0.0f;
}
================================================
FILE: app/src/main/cpp/b2CircleContact.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2CircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2WorldCallbacks.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h"
#include
b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2CircleContact));
return new (mem) b2CircleContact(fixtureA, fixtureB);
}
void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2CircleContact*)contact)->~b2CircleContact();
allocator->Free(contact, sizeof(b2CircleContact));
}
b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_circle);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideCircles(manifold,
(b2CircleShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2CircleShape.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include
b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2CircleShape));
b2CircleShape* clone = new (mem) b2CircleShape;
*clone = *this;
return clone;
}
int32 b2CircleShape::GetChildCount() const
{
return 1;
}
bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const
{
b2Vec2 center = transform.p + b2Mul(transform.q, m_p);
b2Vec2 d = p - center;
return b2Dot(d, d) <= m_radius * m_radius;
}
// Collision Detection in Interactive 3D Environments by Gino van den Bergen
// From Section 3.1.2
// x = s + a * r
// norm(x) = radius
bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const
{
B2_NOT_USED(childIndex);
b2Vec2 position = transform.p + b2Mul(transform.q, m_p);
b2Vec2 s = input.p1 - position;
float32 b = b2Dot(s, s) - m_radius * m_radius;
// Solve quadratic equation.
b2Vec2 r = input.p2 - input.p1;
float32 c = b2Dot(s, r);
float32 rr = b2Dot(r, r);
float32 sigma = c * c - rr * b;
// Check for negative discriminant and short segment.
if (sigma < 0.0f || rr < b2_epsilon)
{
return false;
}
// Find the point of intersection of the line with the circle.
float32 a = -(c + b2Sqrt(sigma));
// Is the intersection point on the segment?
if (0.0f <= a && a <= input.maxFraction * rr)
{
a /= rr;
output->fraction = a;
output->normal = s + a * r;
output->normal.Normalize();
return true;
}
return false;
}
void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const
{
B2_NOT_USED(childIndex);
b2Vec2 p = transform.p + b2Mul(transform.q, m_p);
aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
}
void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const
{
massData->mass = density * b2_pi * m_radius * m_radius;
massData->center = m_p;
// inertia about the local origin
massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));
}
================================================
FILE: app/src/main/cpp/b2CollideCircle.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
void b2CollideCircles(
b2Manifold* manifold,
const b2CircleShape* circleA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB)
{
manifold->pointCount = 0;
b2Vec2 pA = b2Mul(xfA, circleA->m_p);
b2Vec2 pB = b2Mul(xfB, circleB->m_p);
b2Vec2 d = pB - pA;
float32 distSqr = b2Dot(d, d);
float32 rA = circleA->m_radius, rB = circleB->m_radius;
float32 radius = rA + rB;
if (distSqr > radius * radius)
{
return;
}
manifold->type = b2Manifold::e_circles;
manifold->localPoint = circleA->m_p;
manifold->localNormal.SetZero();
manifold->pointCount = 1;
manifold->points[0].localPoint = circleB->m_p;
manifold->points[0].id.key = 0;
}
void b2CollidePolygonAndCircle(
b2Manifold* manifold,
const b2PolygonShape* polygonA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB)
{
manifold->pointCount = 0;
// Compute circle position in the frame of the polygon.
b2Vec2 c = b2Mul(xfB, circleB->m_p);
b2Vec2 cLocal = b2MulT(xfA, c);
// Find the min separating edge.
int32 normalIndex = 0;
float32 separation = -b2_maxFloat;
float32 radius = polygonA->m_radius + circleB->m_radius;
int32 vertexCount = polygonA->m_count;
const b2Vec2* vertices = polygonA->m_vertices;
const b2Vec2* normals = polygonA->m_normals;
for (int32 i = 0; i < vertexCount; ++i)
{
float32 s = b2Dot(normals[i], cLocal - vertices[i]);
if (s > radius)
{
// Early out.
return;
}
if (s > separation)
{
separation = s;
normalIndex = i;
}
}
// Vertices that subtend the incident face.
int32 vertIndex1 = normalIndex;
int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
b2Vec2 v1 = vertices[vertIndex1];
b2Vec2 v2 = vertices[vertIndex2];
// If the center is inside the polygon ...
if (separation < b2_epsilon)
{
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = normals[normalIndex];
manifold->localPoint = 0.5f * (v1 + v2);
manifold->points[0].localPoint = circleB->m_p;
manifold->points[0].id.key = 0;
return;
}
// Compute barycentric coordinates
float32 u1 = b2Dot(cLocal - v1, v2 - v1);
float32 u2 = b2Dot(cLocal - v2, v1 - v2);
if (u1 <= 0.0f)
{
if (b2DistanceSquared(cLocal, v1) > radius * radius)
{
return;
}
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = cLocal - v1;
manifold->localNormal.Normalize();
manifold->localPoint = v1;
manifold->points[0].localPoint = circleB->m_p;
manifold->points[0].id.key = 0;
}
else if (u2 <= 0.0f)
{
if (b2DistanceSquared(cLocal, v2) > radius * radius)
{
return;
}
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = cLocal - v2;
manifold->localNormal.Normalize();
manifold->localPoint = v2;
manifold->points[0].localPoint = circleB->m_p;
manifold->points[0].id.key = 0;
}
else
{
b2Vec2 faceCenter = 0.5f * (v1 + v2);
float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
if (separation > radius)
{
return;
}
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = normals[vertIndex1];
manifold->localPoint = faceCenter;
manifold->points[0].localPoint = circleB->m_p;
manifold->points[0].id.key = 0;
}
}
================================================
FILE: app/src/main/cpp/b2CollideEdge.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
// Compute contact points for edge versus circle.
// This accounts for edge connectivity.
void b2CollideEdgeAndCircle(b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB)
{
manifold->pointCount = 0;
// Compute circle in frame of edge
b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
b2Vec2 e = B - A;
// Barycentric coordinates
float32 u = b2Dot(e, B - Q);
float32 v = b2Dot(e, Q - A);
float32 radius = edgeA->m_radius + circleB->m_radius;
b2ContactFeature cf;
cf.indexB = 0;
cf.typeB = b2ContactFeature::e_vertex;
// Region A
if (v <= 0.0f)
{
b2Vec2 P = A;
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
// Is there an edge connected to A?
if (edgeA->m_hasVertex0)
{
b2Vec2 A1 = edgeA->m_vertex0;
b2Vec2 B1 = A;
b2Vec2 e1 = B1 - A1;
float32 u1 = b2Dot(e1, B1 - Q);
// Is the circle in Region AB of the previous edge?
if (u1 > 0.0f)
{
return;
}
}
cf.indexA = 0;
cf.typeA = b2ContactFeature::e_vertex;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_circles;
manifold->localNormal.SetZero();
manifold->localPoint = P;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
return;
}
// Region B
if (u <= 0.0f)
{
b2Vec2 P = B;
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
// Is there an edge connected to B?
if (edgeA->m_hasVertex3)
{
b2Vec2 B2 = edgeA->m_vertex3;
b2Vec2 A2 = B;
b2Vec2 e2 = B2 - A2;
float32 v2 = b2Dot(e2, Q - A2);
// Is the circle in Region AB of the next edge?
if (v2 > 0.0f)
{
return;
}
}
cf.indexA = 1;
cf.typeA = b2ContactFeature::e_vertex;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_circles;
manifold->localNormal.SetZero();
manifold->localPoint = P;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
return;
}
// Region AB
float32 den = b2Dot(e, e);
b2Assert(den > 0.0f);
b2Vec2 P = (1.0f / den) * (u * A + v * B);
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
b2Vec2 n(-e.y, e.x);
if (b2Dot(n, Q - A) < 0.0f)
{
n.Set(-n.x, -n.y);
}
n.Normalize();
cf.indexA = 0;
cf.typeA = b2ContactFeature::e_face;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = n;
manifold->localPoint = A;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
}
// This structure is used to keep track of the best separating axis.
struct b2EPAxis
{
enum Type
{
e_unknown,
e_edgeA,
e_edgeB
};
Type type;
int32 index;
float32 separation;
};
// This holds polygon B expressed in frame A.
struct b2TempPolygon
{
b2Vec2 vertices[b2_maxPolygonVertices];
b2Vec2 normals[b2_maxPolygonVertices];
int32 count;
};
// Reference face used for clipping
struct b2ReferenceFace
{
int32 i1, i2;
b2Vec2 v1, v2;
b2Vec2 normal;
b2Vec2 sideNormal1;
float32 sideOffset1;
b2Vec2 sideNormal2;
float32 sideOffset2;
};
// This class collides and edge and a polygon, taking into account edge adjacency.
struct b2EPCollider
{
void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB);
b2EPAxis ComputeEdgeSeparation();
b2EPAxis ComputePolygonSeparation();
enum VertexType
{
e_isolated,
e_concave,
e_convex
};
b2TempPolygon m_polygonB;
b2Transform m_xf;
b2Vec2 m_centroidB;
b2Vec2 m_v0, m_v1, m_v2, m_v3;
b2Vec2 m_normal0, m_normal1, m_normal2;
b2Vec2 m_normal;
VertexType m_type1, m_type2;
b2Vec2 m_lowerLimit, m_upperLimit;
float32 m_radius;
bool m_front;
};
// Algorithm:
// 1. Classify v1 and v2
// 2. Classify polygon centroid as front or back
// 3. Flip normal if necessary
// 4. Initialize normal range to [-pi, pi] about face normal
// 5. Adjust normal range according to adjacent edges
// 6. Visit each separating axes, only accept axes within the range
// 7. Return if _any_ axis indicates separation
// 8. Clip
void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB)
{
m_xf = b2MulT(xfA, xfB);
m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
m_v0 = edgeA->m_vertex0;
m_v1 = edgeA->m_vertex1;
m_v2 = edgeA->m_vertex2;
m_v3 = edgeA->m_vertex3;
bool hasVertex0 = edgeA->m_hasVertex0;
bool hasVertex3 = edgeA->m_hasVertex3;
b2Vec2 edge1 = m_v2 - m_v1;
edge1.Normalize();
m_normal1.Set(edge1.y, -edge1.x);
float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
float32 offset0 = 0.0f, offset2 = 0.0f;
bool convex1 = false, convex2 = false;
// Is there a preceding edge?
if (hasVertex0)
{
b2Vec2 edge0 = m_v1 - m_v0;
edge0.Normalize();
m_normal0.Set(edge0.y, -edge0.x);
convex1 = b2Cross(edge0, edge1) >= 0.0f;
offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
}
// Is there a following edge?
if (hasVertex3)
{
b2Vec2 edge2 = m_v3 - m_v2;
edge2.Normalize();
m_normal2.Set(edge2.y, -edge2.x);
convex2 = b2Cross(edge1, edge2) > 0.0f;
offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
}
// Determine front or back collision. Determine collision normal limits.
if (hasVertex0 && hasVertex3)
{
if (convex1 && convex2)
{
m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal1;
}
}
else if (convex1)
{
m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = -m_normal1;
}
}
else if (convex2)
{
m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal0;
}
}
else
{
m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = -m_normal0;
}
}
}
else if (hasVertex0)
{
if (convex1)
{
m_front = offset0 >= 0.0f || offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal1;
}
}
else
{
m_front = offset0 >= 0.0f && offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal0;
}
}
}
else if (hasVertex3)
{
if (convex2)
{
m_front = offset1 >= 0.0f || offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal1;
}
}
else
{
m_front = offset1 >= 0.0f && offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = m_normal1;
}
}
}
else
{
m_front = offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal1;
}
}
// Get polygonB in frameA
m_polygonB.count = polygonB->m_count;
for (int32 i = 0; i < polygonB->m_count; ++i)
{
m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
}
m_radius = 2.0f * b2_polygonRadius;
manifold->pointCount = 0;
b2EPAxis edgeAxis = ComputeEdgeSeparation();
// If no valid normal can be found than this edge should not collide.
if (edgeAxis.type == b2EPAxis::e_unknown)
{
return;
}
if (edgeAxis.separation > m_radius)
{
return;
}
b2EPAxis polygonAxis = ComputePolygonSeparation();
if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
{
return;
}
// Use hysteresis for jitter reduction.
const float32 k_relativeTol = 0.98f;
const float32 k_absoluteTol = 0.001f;
b2EPAxis primaryAxis;
if (polygonAxis.type == b2EPAxis::e_unknown)
{
primaryAxis = edgeAxis;
}
else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
{
primaryAxis = polygonAxis;
}
else
{
primaryAxis = edgeAxis;
}
b2ClipVertex ie[2];
b2ReferenceFace rf;
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
manifold->type = b2Manifold::e_faceA;
// Search for the polygon normal that is most anti-parallel to the edge normal.
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
for (int32 i = 1; i < m_polygonB.count; ++i)
{
float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
if (value < bestValue)
{
bestValue = value;
bestIndex = i;
}
}
int32 i1 = bestIndex;
int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
ie[0].v = m_polygonB.vertices[i1];
ie[0].id.cf.indexA = 0;
ie[0].id.cf.indexB = static_cast(i1);
ie[0].id.cf.typeA = b2ContactFeature::e_face;
ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
ie[1].v = m_polygonB.vertices[i2];
ie[1].id.cf.indexA = 0;
ie[1].id.cf.indexB = static_cast(i2);
ie[1].id.cf.typeA = b2ContactFeature::e_face;
ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
if (m_front)
{
rf.i1 = 0;
rf.i2 = 1;
rf.v1 = m_v1;
rf.v2 = m_v2;
rf.normal = m_normal1;
}
else
{
rf.i1 = 1;
rf.i2 = 0;
rf.v1 = m_v2;
rf.v2 = m_v1;
rf.normal = -m_normal1;
}
}
else
{
manifold->type = b2Manifold::e_faceB;
ie[0].v = m_v1;
ie[0].id.cf.indexA = 0;
ie[0].id.cf.indexB = static_cast(primaryAxis.index);
ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
ie[0].id.cf.typeB = b2ContactFeature::e_face;
ie[1].v = m_v2;
ie[1].id.cf.indexA = 0;
ie[1].id.cf.indexB = static_cast(primaryAxis.index);
ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
ie[1].id.cf.typeB = b2ContactFeature::e_face;
rf.i1 = primaryAxis.index;
rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
rf.v1 = m_polygonB.vertices[rf.i1];
rf.v2 = m_polygonB.vertices[rf.i2];
rf.normal = m_polygonB.normals[rf.i1];
}
rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
rf.sideNormal2 = -rf.sideNormal1;
rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
// Clip incident edge against extruded edge1 side edges.
b2ClipVertex clipPoints1[2];
b2ClipVertex clipPoints2[2];
int32 np;
// Clip to box side 1
np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
if (np < b2_maxManifoldPoints)
{
return;
}
// Clip to negative box side 1
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
if (np < b2_maxManifoldPoints)
{
return;
}
// Now clipPoints2 contains the clipped points.
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
manifold->localNormal = rf.normal;
manifold->localPoint = rf.v1;
}
else
{
manifold->localNormal = polygonB->m_normals[rf.i1];
manifold->localPoint = polygonB->m_vertices[rf.i1];
}
int32 pointCount = 0;
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
{
float32 separation;
separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
if (separation <= m_radius)
{
b2ManifoldPoint* cp = manifold->points + pointCount;
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
cp->id = clipPoints2[i].id;
}
else
{
cp->localPoint = clipPoints2[i].v;
cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
}
++pointCount;
}
}
manifold->pointCount = pointCount;
}
b2EPAxis b2EPCollider::ComputeEdgeSeparation()
{
b2EPAxis axis;
axis.type = b2EPAxis::e_edgeA;
axis.index = m_front ? 0 : 1;
axis.separation = FLT_MAX;
for (int32 i = 0; i < m_polygonB.count; ++i)
{
float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
if (s < axis.separation)
{
axis.separation = s;
}
}
return axis;
}
b2EPAxis b2EPCollider::ComputePolygonSeparation()
{
b2EPAxis axis;
axis.type = b2EPAxis::e_unknown;
axis.index = -1;
axis.separation = -FLT_MAX;
b2Vec2 perp(-m_normal.y, m_normal.x);
for (int32 i = 0; i < m_polygonB.count; ++i)
{
b2Vec2 n = -m_polygonB.normals[i];
float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
float32 s = b2Min(s1, s2);
if (s > m_radius)
{
// No collision
axis.type = b2EPAxis::e_edgeB;
axis.index = i;
axis.separation = s;
return axis;
}
// Adjacency
if (b2Dot(n, perp) >= 0.0f)
{
if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
{
continue;
}
}
else
{
if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
{
continue;
}
}
if (s > axis.separation)
{
axis.type = b2EPAxis::e_edgeB;
axis.index = i;
axis.separation = s;
}
}
return axis;
}
void b2CollideEdgeAndPolygon( b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB)
{
b2EPCollider collider;
collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
}
================================================
FILE: app/src/main/cpp/b2CollidePolygon.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
// Find the max separation between poly1 and poly2 using edge normals from poly1.
static float32 b2FindMaxSeparation(int32* edgeIndex,
const b2PolygonShape* poly1, const b2Transform& xf1,
const b2PolygonShape* poly2, const b2Transform& xf2)
{
int32 count1 = poly1->m_count;
int32 count2 = poly2->m_count;
const b2Vec2* n1s = poly1->m_normals;
const b2Vec2* v1s = poly1->m_vertices;
const b2Vec2* v2s = poly2->m_vertices;
b2Transform xf = b2MulT(xf2, xf1);
int32 bestIndex = 0;
float32 maxSeparation = -b2_maxFloat;
for (int32 i = 0; i < count1; ++i)
{
// Get poly1 normal in frame2.
b2Vec2 n = b2Mul(xf.q, n1s[i]);
b2Vec2 v1 = b2Mul(xf, v1s[i]);
// Find deepest point for normal i.
float32 si = b2_maxFloat;
for (int32 j = 0; j < count2; ++j)
{
float32 sij = b2Dot(n, v2s[j] - v1);
if (sij < si)
{
si = sij;
}
}
if (si > maxSeparation)
{
maxSeparation = si;
bestIndex = i;
}
}
*edgeIndex = bestIndex;
return maxSeparation;
}
static void b2FindIncidentEdge(b2ClipVertex c[2],
const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
const b2PolygonShape* poly2, const b2Transform& xf2)
{
const b2Vec2* normals1 = poly1->m_normals;
int32 count2 = poly2->m_count;
const b2Vec2* vertices2 = poly2->m_vertices;
const b2Vec2* normals2 = poly2->m_normals;
b2Assert(0 <= edge1 && edge1 < poly1->m_count);
// Get the normal of the reference edge in poly2's frame.
b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
// Find the incident edge on poly2.
int32 index = 0;
float32 minDot = b2_maxFloat;
for (int32 i = 0; i < count2; ++i)
{
float32 dot = b2Dot(normal1, normals2[i]);
if (dot < minDot)
{
minDot = dot;
index = i;
}
}
// Build the clip vertices for the incident edge.
int32 i1 = index;
int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
c[0].v = b2Mul(xf2, vertices2[i1]);
c[0].id.cf.indexA = (uint8)edge1;
c[0].id.cf.indexB = (uint8)i1;
c[0].id.cf.typeA = b2ContactFeature::e_face;
c[0].id.cf.typeB = b2ContactFeature::e_vertex;
c[1].v = b2Mul(xf2, vertices2[i2]);
c[1].id.cf.indexA = (uint8)edge1;
c[1].id.cf.indexB = (uint8)i2;
c[1].id.cf.typeA = b2ContactFeature::e_face;
c[1].id.cf.typeB = b2ContactFeature::e_vertex;
}
// Find edge normal of max separation on A - return if separating axis is found
// Find edge normal of max separation on B - return if separation axis is found
// Choose reference edge as min(minA, minB)
// Find incident edge
// Clip
// The normal points from 1 to 2
void b2CollidePolygons(b2Manifold* manifold,
const b2PolygonShape* polyA, const b2Transform& xfA,
const b2PolygonShape* polyB, const b2Transform& xfB)
{
manifold->pointCount = 0;
float32 totalRadius = polyA->m_radius + polyB->m_radius;
int32 edgeA = 0;
float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
if (separationA > totalRadius)
return;
int32 edgeB = 0;
float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
if (separationB > totalRadius)
return;
const b2PolygonShape* poly1; // reference polygon
const b2PolygonShape* poly2; // incident polygon
b2Transform xf1, xf2;
int32 edge1; // reference edge
uint8 flip;
const float32 k_tol = 0.1f * b2_linearSlop;
if (separationB > separationA + k_tol)
{
poly1 = polyB;
poly2 = polyA;
xf1 = xfB;
xf2 = xfA;
edge1 = edgeB;
manifold->type = b2Manifold::e_faceB;
flip = 1;
}
else
{
poly1 = polyA;
poly2 = polyB;
xf1 = xfA;
xf2 = xfB;
edge1 = edgeA;
manifold->type = b2Manifold::e_faceA;
flip = 0;
}
b2ClipVertex incidentEdge[2];
b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
int32 count1 = poly1->m_count;
const b2Vec2* vertices1 = poly1->m_vertices;
int32 iv1 = edge1;
int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
b2Vec2 v11 = vertices1[iv1];
b2Vec2 v12 = vertices1[iv2];
b2Vec2 localTangent = v12 - v11;
localTangent.Normalize();
b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
b2Vec2 planePoint = 0.5f * (v11 + v12);
b2Vec2 tangent = b2Mul(xf1.q, localTangent);
b2Vec2 normal = b2Cross(tangent, 1.0f);
v11 = b2Mul(xf1, v11);
v12 = b2Mul(xf1, v12);
// Face offset.
float32 frontOffset = b2Dot(normal, v11);
// Side offsets, extended by polytope skin thickness.
float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
// Clip incident edge against extruded edge1 side edges.
b2ClipVertex clipPoints1[2];
b2ClipVertex clipPoints2[2];
int np;
// Clip to box side 1
np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
if (np < 2)
return;
// Clip to negative box side 1
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2);
if (np < 2)
{
return;
}
// Now clipPoints2 contains the clipped points.
manifold->localNormal = localNormal;
manifold->localPoint = planePoint;
int32 pointCount = 0;
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
{
float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
if (separation <= totalRadius)
{
b2ManifoldPoint* cp = manifold->points + pointCount;
cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
cp->id = clipPoints2[i].id;
if (flip)
{
// Swap features
b2ContactFeature cf = cp->id.cf;
cp->id.cf.indexA = cf.indexB;
cp->id.cf.indexB = cf.indexA;
cp->id.cf.typeA = cf.typeB;
cp->id.cf.typeB = cf.typeA;
}
++pointCount;
}
}
manifold->pointCount = pointCount;
}
================================================
FILE: app/src/main/cpp/b2Collision.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/b2Distance.h"
void b2WorldManifold::Initialize(const b2Manifold* manifold,
const b2Transform& xfA, float32 radiusA,
const b2Transform& xfB, float32 radiusB)
{
if (manifold->pointCount == 0)
{
return;
}
switch (manifold->type)
{
case b2Manifold::e_circles:
{
normal.Set(1.0f, 0.0f);
b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
{
normal = pointB - pointA;
normal.Normalize();
}
b2Vec2 cA = pointA + radiusA * normal;
b2Vec2 cB = pointB - radiusB * normal;
points[0] = 0.5f * (cA + cB);
separations[0] = b2Dot(cB - cA, normal);
}
break;
case b2Manifold::e_faceA:
{
normal = b2Mul(xfA.q, manifold->localNormal);
b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
for (int32 i = 0; i < manifold->pointCount; ++i)
{
b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
b2Vec2 cB = clipPoint - radiusB * normal;
points[i] = 0.5f * (cA + cB);
separations[i] = b2Dot(cB - cA, normal);
}
}
break;
case b2Manifold::e_faceB:
{
normal = b2Mul(xfB.q, manifold->localNormal);
b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
for (int32 i = 0; i < manifold->pointCount; ++i)
{
b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
b2Vec2 cA = clipPoint - radiusA * normal;
points[i] = 0.5f * (cA + cB);
separations[i] = b2Dot(cA - cB, normal);
}
// Ensure normal points from A to B.
normal = -normal;
}
break;
}
}
void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
const b2Manifold* manifold1, const b2Manifold* manifold2)
{
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
{
state1[i] = b2_nullState;
state2[i] = b2_nullState;
}
// Detect persists and removes.
for (int32 i = 0; i < manifold1->pointCount; ++i)
{
b2ContactID id = manifold1->points[i].id;
state1[i] = b2_removeState;
for (int32 j = 0; j < manifold2->pointCount; ++j)
{
if (manifold2->points[j].id.key == id.key)
{
state1[i] = b2_persistState;
break;
}
}
}
// Detect persists and adds.
for (int32 i = 0; i < manifold2->pointCount; ++i)
{
b2ContactID id = manifold2->points[i].id;
state2[i] = b2_addState;
for (int32 j = 0; j < manifold1->pointCount; ++j)
{
if (manifold1->points[j].id.key == id.key)
{
state2[i] = b2_persistState;
break;
}
}
}
}
// From Real-time Collision Detection, p179.
bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
{
float32 tmin = -b2_maxFloat;
float32 tmax = b2_maxFloat;
b2Vec2 p = input.p1;
b2Vec2 d = input.p2 - input.p1;
b2Vec2 absD = b2Abs(d);
b2Vec2 normal;
for (int32 i = 0; i < 2; ++i)
{
if (absD(i) < b2_epsilon)
{
// Parallel.
if (p(i) < lowerBound(i) || upperBound(i) < p(i))
{
return false;
}
}
else
{
float32 inv_d = 1.0f / d(i);
float32 t1 = (lowerBound(i) - p(i)) * inv_d;
float32 t2 = (upperBound(i) - p(i)) * inv_d;
// Sign of the normal vector.
float32 s = -1.0f;
if (t1 > t2)
{
b2Swap(t1, t2);
s = 1.0f;
}
// Push the min up
if (t1 > tmin)
{
normal.SetZero();
normal(i) = s;
tmin = t1;
}
// Pull the max down
tmax = b2Min(tmax, t2);
if (tmin > tmax)
{
return false;
}
}
}
// Does the ray start inside the box?
// Does the ray intersect beyond the max fraction?
if (tmin < 0.0f || input.maxFraction < tmin)
{
return false;
}
// Intersection.
output->fraction = tmin;
output->normal = normal;
return true;
}
// Sutherland-Hodgman clipping.
int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
const b2Vec2& normal, float32 offset, int32 vertexIndexA)
{
// Start with no output points
int32 numOut = 0;
// Calculate the distance of end points to the line
float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
// If the points are behind the plane
if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
// If the points are on different sides of the plane
if (distance0 * distance1 < 0.0f)
{
// Find intersection point of edge and plane
float32 interp = distance0 / (distance0 - distance1);
vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
// VertexA is hitting edgeB.
vOut[numOut].id.cf.indexA = static_cast(vertexIndexA);
vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
++numOut;
}
return numOut;
}
bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
const b2Shape* shapeB, int32 indexB,
const b2Transform& xfA, const b2Transform& xfB)
{
b2DistanceInput input;
input.proxyA.Set(shapeA, indexA);
input.proxyB.Set(shapeB, indexB);
input.transformA = xfA;
input.transformB = xfB;
input.useRadii = true;
b2SimplexCache cache;
cache.count = 0;
b2DistanceOutput output;
b2Distance(&output, &cache, &input);
return output.distance < 10.0f * b2_epsilon;
}
================================================
FILE: app/src/main/cpp/b2Contact.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2CircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2CircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ContactSolver.h"
#include "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2Shape.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
bool b2Contact::s_initialized = false;
void b2Contact::InitializeRegisters()
{
AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle);
AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle);
AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon);
AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle);
AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon);
AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle);
AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon);
}
void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
b2Shape::Type type1, b2Shape::Type type2)
{
b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount);
b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount);
s_registers[type1][type2].createFcn = createFcn;
s_registers[type1][type2].destroyFcn = destoryFcn;
s_registers[type1][type2].primary = true;
if (type1 != type2)
{
s_registers[type2][type1].createFcn = createFcn;
s_registers[type2][type1].destroyFcn = destoryFcn;
s_registers[type2][type1].primary = false;
}
}
b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
{
if (s_initialized == false)
{
InitializeRegisters();
s_initialized = true;
}
b2Shape::Type type1 = fixtureA->GetType();
b2Shape::Type type2 = fixtureB->GetType();
b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount);
b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount);
b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
if (createFcn)
{
if (s_registers[type1][type2].primary)
{
return createFcn(fixtureA, indexA, fixtureB, indexB, allocator);
}
else
{
return createFcn(fixtureB, indexB, fixtureA, indexA, allocator);
}
}
else
{
return NULL;
}
}
void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
b2Assert(s_initialized == true);
b2Fixture* fixtureA = contact->m_fixtureA;
b2Fixture* fixtureB = contact->m_fixtureB;
if (contact->m_manifold.pointCount > 0 &&
fixtureA->IsSensor() == false &&
fixtureB->IsSensor() == false)
{
fixtureA->GetBody()->SetAwake(true);
fixtureB->GetBody()->SetAwake(true);
}
b2Shape::Type typeA = fixtureA->GetType();
b2Shape::Type typeB = fixtureB->GetType();
b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount);
b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount);
b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn;
destroyFcn(contact, allocator);
}
b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB)
{
m_flags = e_enabledFlag;
m_fixtureA = fA;
m_fixtureB = fB;
m_indexA = indexA;
m_indexB = indexB;
m_manifold.pointCount = 0;
m_prev = NULL;
m_next = NULL;
m_nodeA.contact = NULL;
m_nodeA.prev = NULL;
m_nodeA.next = NULL;
m_nodeA.other = NULL;
m_nodeB.contact = NULL;
m_nodeB.prev = NULL;
m_nodeB.next = NULL;
m_nodeB.other = NULL;
m_toiCount = 0;
m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
m_tangentSpeed = 0.0f;
}
// Update the contact manifold and touching status.
// Note: do not assume the fixture AABBs are overlapping or are valid.
void b2Contact::Update(b2ContactListener* listener)
{
b2Manifold oldManifold = m_manifold;
// Re-enable this contact.
m_flags |= e_enabledFlag;
bool touching = false;
bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;
bool sensorA = m_fixtureA->IsSensor();
bool sensorB = m_fixtureB->IsSensor();
bool sensor = sensorA || sensorB;
b2Body* bodyA = m_fixtureA->GetBody();
b2Body* bodyB = m_fixtureB->GetBody();
const b2Transform& xfA = bodyA->GetTransform();
const b2Transform& xfB = bodyB->GetTransform();
// Is this contact a sensor?
if (sensor)
{
const b2Shape* shapeA = m_fixtureA->GetShape();
const b2Shape* shapeB = m_fixtureB->GetShape();
touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB);
// Sensors don't generate manifolds.
m_manifold.pointCount = 0;
}
else
{
Evaluate(&m_manifold, xfA, xfB);
touching = m_manifold.pointCount > 0;
// Match old contact ids to new contact ids and copy the
// stored impulses to warm start the solver.
for (int32 i = 0; i < m_manifold.pointCount; ++i)
{
b2ManifoldPoint* mp2 = m_manifold.points + i;
mp2->normalImpulse = 0.0f;
mp2->tangentImpulse = 0.0f;
b2ContactID id2 = mp2->id;
for (int32 j = 0; j < oldManifold.pointCount; ++j)
{
b2ManifoldPoint* mp1 = oldManifold.points + j;
if (mp1->id.key == id2.key)
{
mp2->normalImpulse = mp1->normalImpulse;
mp2->tangentImpulse = mp1->tangentImpulse;
break;
}
}
}
if (touching != wasTouching)
{
bodyA->SetAwake(true);
bodyB->SetAwake(true);
}
}
if (touching)
{
m_flags |= e_touchingFlag;
}
else
{
m_flags &= ~e_touchingFlag;
}
if (wasTouching == false && touching == true && listener)
{
listener->BeginContact(this);
}
if (wasTouching == true && touching == false && listener)
{
listener->EndContact(this);
}
if (sensor == false && touching && listener)
{
listener->PreSolve(this, &oldManifold);
}
}
================================================
FILE: app/src/main/cpp/b2ContactManager.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/b2ContactManager.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2WorldCallbacks.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
b2ContactFilter b2_defaultFilter;
b2ContactListener b2_defaultListener;
b2ContactManager::b2ContactManager()
{
m_contactList = NULL;
m_contactCount = 0;
m_contactFilter = &b2_defaultFilter;
m_contactListener = &b2_defaultListener;
m_allocator = NULL;
}
void b2ContactManager::Destroy(b2Contact* c)
{
b2Fixture* fixtureA = c->GetFixtureA();
b2Fixture* fixtureB = c->GetFixtureB();
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
if (m_contactListener && c->IsTouching())
{
m_contactListener->EndContact(c);
}
// Remove from the world.
if (c->m_prev)
{
c->m_prev->m_next = c->m_next;
}
if (c->m_next)
{
c->m_next->m_prev = c->m_prev;
}
if (c == m_contactList)
{
m_contactList = c->m_next;
}
// Remove from body 1
if (c->m_nodeA.prev)
{
c->m_nodeA.prev->next = c->m_nodeA.next;
}
if (c->m_nodeA.next)
{
c->m_nodeA.next->prev = c->m_nodeA.prev;
}
if (&c->m_nodeA == bodyA->m_contactList)
{
bodyA->m_contactList = c->m_nodeA.next;
}
// Remove from body 2
if (c->m_nodeB.prev)
{
c->m_nodeB.prev->next = c->m_nodeB.next;
}
if (c->m_nodeB.next)
{
c->m_nodeB.next->prev = c->m_nodeB.prev;
}
if (&c->m_nodeB == bodyB->m_contactList)
{
bodyB->m_contactList = c->m_nodeB.next;
}
// Call the factory.
b2Contact::Destroy(c, m_allocator);
--m_contactCount;
}
// This is the top level collision call for the time step. Here
// all the narrow phase collision is processed for the world
// contact list.
void b2ContactManager::Collide()
{
// Update awake contacts.
b2Contact* c = m_contactList;
while (c)
{
b2Fixture* fixtureA = c->GetFixtureA();
b2Fixture* fixtureB = c->GetFixtureB();
int32 indexA = c->GetChildIndexA();
int32 indexB = c->GetChildIndexB();
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
// Is this contact flagged for filtering?
if (c->m_flags & b2Contact::e_filterFlag)
{
// Should these bodies collide?
if (bodyB->ShouldCollide(bodyA) == false)
{
b2Contact* cNuke = c;
c = cNuke->GetNext();
Destroy(cNuke);
continue;
}
// Check user filtering.
if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
{
b2Contact* cNuke = c;
c = cNuke->GetNext();
Destroy(cNuke);
continue;
}
// Clear the filtering flag.
c->m_flags &= ~b2Contact::e_filterFlag;
}
bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody;
bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody;
// At least one body must be awake and it must be dynamic or kinematic.
if (activeA == false && activeB == false)
{
c = c->GetNext();
continue;
}
int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId;
int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId;
bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB);
// Here we destroy contacts that cease to overlap in the broad-phase.
if (overlap == false)
{
b2Contact* cNuke = c;
c = cNuke->GetNext();
Destroy(cNuke);
continue;
}
// The contact persists.
c->Update(m_contactListener);
c = c->GetNext();
}
}
void b2ContactManager::FindNewContacts()
{
m_broadPhase.UpdatePairs(this);
}
void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB)
{
b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA;
b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB;
b2Fixture* fixtureA = proxyA->fixture;
b2Fixture* fixtureB = proxyB->fixture;
int32 indexA = proxyA->childIndex;
int32 indexB = proxyB->childIndex;
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
// Are the fixtures on the same body?
if (bodyA == bodyB)
{
return;
}
// TODO_ERIN use a hash table to remove a potential bottleneck when both
// bodies have a lot of contacts.
// Does a contact already exist?
b2ContactEdge* edge = bodyB->GetContactList();
while (edge)
{
if (edge->other == bodyA)
{
b2Fixture* fA = edge->contact->GetFixtureA();
b2Fixture* fB = edge->contact->GetFixtureB();
int32 iA = edge->contact->GetChildIndexA();
int32 iB = edge->contact->GetChildIndexB();
if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
{
// A contact already exists.
return;
}
if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
{
// A contact already exists.
return;
}
}
edge = edge->next;
}
// Does a joint override collision? Is at least one body dynamic?
if (bodyB->ShouldCollide(bodyA) == false)
{
return;
}
// Check user filtering.
if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
{
return;
}
// Call the factory.
b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator);
if (c == NULL)
{
return;
}
// Contact creation may swap fixtures.
fixtureA = c->GetFixtureA();
fixtureB = c->GetFixtureB();
indexA = c->GetChildIndexA();
indexB = c->GetChildIndexB();
bodyA = fixtureA->GetBody();
bodyB = fixtureB->GetBody();
// Insert into the world.
c->m_prev = NULL;
c->m_next = m_contactList;
if (m_contactList != NULL)
{
m_contactList->m_prev = c;
}
m_contactList = c;
// Connect to island graph.
// Connect to body A
c->m_nodeA.contact = c;
c->m_nodeA.other = bodyB;
c->m_nodeA.prev = NULL;
c->m_nodeA.next = bodyA->m_contactList;
if (bodyA->m_contactList != NULL)
{
bodyA->m_contactList->prev = &c->m_nodeA;
}
bodyA->m_contactList = &c->m_nodeA;
// Connect to body B
c->m_nodeB.contact = c;
c->m_nodeB.other = bodyA;
c->m_nodeB.prev = NULL;
c->m_nodeB.next = bodyB->m_contactList;
if (bodyB->m_contactList != NULL)
{
bodyB->m_contactList->prev = &c->m_nodeB;
}
bodyB->m_contactList = &c->m_nodeB;
// Wake up the bodies
if (fixtureA->IsSensor() == false && fixtureB->IsSensor() == false)
{
bodyA->SetAwake(true);
bodyB->SetAwake(true);
}
++m_contactCount;
}
================================================
FILE: app/src/main/cpp/b2ContactSolver.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ContactSolver.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Common/b2StackAllocator.h"
#define B2_DEBUG_SOLVER 0
struct b2ContactPositionConstraint
{
b2Vec2 localPoints[b2_maxManifoldPoints];
b2Vec2 localNormal;
b2Vec2 localPoint;
int32 indexA;
int32 indexB;
float32 invMassA, invMassB;
b2Vec2 localCenterA, localCenterB;
float32 invIA, invIB;
b2Manifold::Type type;
float32 radiusA, radiusB;
int32 pointCount;
};
b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def)
{
m_step = def->step;
m_allocator = def->allocator;
m_count = def->count;
m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint));
m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint));
m_positions = def->positions;
m_velocities = def->velocities;
m_contacts = def->contacts;
// Initialize position independent portions of the constraints.
for (int32 i = 0; i < m_count; ++i)
{
b2Contact* contact = m_contacts[i];
b2Fixture* fixtureA = contact->m_fixtureA;
b2Fixture* fixtureB = contact->m_fixtureB;
b2Shape* shapeA = fixtureA->GetShape();
b2Shape* shapeB = fixtureB->GetShape();
float32 radiusA = shapeA->m_radius;
float32 radiusB = shapeB->m_radius;
b2Body* bodyA = fixtureA->GetBody();
b2Body* bodyB = fixtureB->GetBody();
b2Manifold* manifold = contact->GetManifold();
int32 pointCount = manifold->pointCount;
b2Assert(pointCount > 0);
b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
vc->friction = contact->m_friction;
vc->restitution = contact->m_restitution;
vc->tangentSpeed = contact->m_tangentSpeed;
vc->indexA = bodyA->m_islandIndex;
vc->indexB = bodyB->m_islandIndex;
vc->invMassA = bodyA->m_invMass;
vc->invMassB = bodyB->m_invMass;
vc->invIA = bodyA->m_invI;
vc->invIB = bodyB->m_invI;
vc->contactIndex = i;
vc->pointCount = pointCount;
vc->K.SetZero();
vc->normalMass.SetZero();
b2ContactPositionConstraint* pc = m_positionConstraints + i;
pc->indexA = bodyA->m_islandIndex;
pc->indexB = bodyB->m_islandIndex;
pc->invMassA = bodyA->m_invMass;
pc->invMassB = bodyB->m_invMass;
pc->localCenterA = bodyA->m_sweep.localCenter;
pc->localCenterB = bodyB->m_sweep.localCenter;
pc->invIA = bodyA->m_invI;
pc->invIB = bodyB->m_invI;
pc->localNormal = manifold->localNormal;
pc->localPoint = manifold->localPoint;
pc->pointCount = pointCount;
pc->radiusA = radiusA;
pc->radiusB = radiusB;
pc->type = manifold->type;
for (int32 j = 0; j < pointCount; ++j)
{
b2ManifoldPoint* cp = manifold->points + j;
b2VelocityConstraintPoint* vcp = vc->points + j;
if (m_step.warmStarting)
{
vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse;
vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse;
}
else
{
vcp->normalImpulse = 0.0f;
vcp->tangentImpulse = 0.0f;
}
vcp->rA.SetZero();
vcp->rB.SetZero();
vcp->normalMass = 0.0f;
vcp->tangentMass = 0.0f;
vcp->velocityBias = 0.0f;
pc->localPoints[j] = cp->localPoint;
}
}
}
b2ContactSolver::~b2ContactSolver()
{
m_allocator->Free(m_velocityConstraints);
m_allocator->Free(m_positionConstraints);
}
// Initialize position dependent portions of the velocity constraints.
void b2ContactSolver::InitializeVelocityConstraints()
{
for (int32 i = 0; i < m_count; ++i)
{
b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
b2ContactPositionConstraint* pc = m_positionConstraints + i;
float32 radiusA = pc->radiusA;
float32 radiusB = pc->radiusB;
b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
int32 indexA = vc->indexA;
int32 indexB = vc->indexB;
float32 mA = vc->invMassA;
float32 mB = vc->invMassB;
float32 iA = vc->invIA;
float32 iB = vc->invIB;
b2Vec2 localCenterA = pc->localCenterA;
b2Vec2 localCenterB = pc->localCenterB;
b2Vec2 cA = m_positions[indexA].c;
float32 aA = m_positions[indexA].a;
b2Vec2 vA = m_velocities[indexA].v;
float32 wA = m_velocities[indexA].w;
b2Vec2 cB = m_positions[indexB].c;
float32 aB = m_positions[indexB].a;
b2Vec2 vB = m_velocities[indexB].v;
float32 wB = m_velocities[indexB].w;
b2Assert(manifold->pointCount > 0);
b2Transform xfA, xfB;
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - b2Mul(xfA.q, localCenterA);
xfB.p = cB - b2Mul(xfB.q, localCenterB);
b2WorldManifold worldManifold;
worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB);
vc->normal = worldManifold.normal;
int32 pointCount = vc->pointCount;
for (int32 j = 0; j < pointCount; ++j)
{
b2VelocityConstraintPoint* vcp = vc->points + j;
vcp->rA = worldManifold.points[j] - cA;
vcp->rB = worldManifold.points[j] - cB;
float32 rnA = b2Cross(vcp->rA, vc->normal);
float32 rnB = b2Cross(vcp->rB, vc->normal);
float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
b2Vec2 tangent = b2Cross(vc->normal, 1.0f);
float32 rtA = b2Cross(vcp->rA, tangent);
float32 rtB = b2Cross(vcp->rB, tangent);
float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
// Setup a velocity bias for restitution.
vcp->velocityBias = 0.0f;
float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA));
if (vRel < -b2_velocityThreshold)
{
vcp->velocityBias = -vc->restitution * vRel;
}
}
// If we have two points, then prepare the block solver.
if (vc->pointCount == 2)
{
b2VelocityConstraintPoint* vcp1 = vc->points + 0;
b2VelocityConstraintPoint* vcp2 = vc->points + 1;
float32 rn1A = b2Cross(vcp1->rA, vc->normal);
float32 rn1B = b2Cross(vcp1->rB, vc->normal);
float32 rn2A = b2Cross(vcp2->rA, vc->normal);
float32 rn2B = b2Cross(vcp2->rB, vc->normal);
float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
// Ensure a reasonable condition number.
const float32 k_maxConditionNumber = 1000.0f;
if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
{
// K is safe to invert.
vc->K.ex.Set(k11, k12);
vc->K.ey.Set(k12, k22);
vc->normalMass = vc->K.GetInverse();
}
else
{
// The constraints are redundant, just use one.
// TODO_ERIN use deepest?
vc->pointCount = 1;
}
}
}
}
void b2ContactSolver::WarmStart()
{
// Warm start.
for (int32 i = 0; i < m_count; ++i)
{
b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
int32 indexA = vc->indexA;
int32 indexB = vc->indexB;
float32 mA = vc->invMassA;
float32 iA = vc->invIA;
float32 mB = vc->invMassB;
float32 iB = vc->invIB;
int32 pointCount = vc->pointCount;
b2Vec2 vA = m_velocities[indexA].v;
float32 wA = m_velocities[indexA].w;
b2Vec2 vB = m_velocities[indexB].v;
float32 wB = m_velocities[indexB].w;
b2Vec2 normal = vc->normal;
b2Vec2 tangent = b2Cross(normal, 1.0f);
for (int32 j = 0; j < pointCount; ++j)
{
b2VelocityConstraintPoint* vcp = vc->points + j;
b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent;
wA -= iA * b2Cross(vcp->rA, P);
vA -= mA * P;
wB += iB * b2Cross(vcp->rB, P);
vB += mB * P;
}
m_velocities[indexA].v = vA;
m_velocities[indexA].w = wA;
m_velocities[indexB].v = vB;
m_velocities[indexB].w = wB;
}
}
void b2ContactSolver::SolveVelocityConstraints()
{
for (int32 i = 0; i < m_count; ++i)
{
b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
int32 indexA = vc->indexA;
int32 indexB = vc->indexB;
float32 mA = vc->invMassA;
float32 iA = vc->invIA;
float32 mB = vc->invMassB;
float32 iB = vc->invIB;
int32 pointCount = vc->pointCount;
b2Vec2 vA = m_velocities[indexA].v;
float32 wA = m_velocities[indexA].w;
b2Vec2 vB = m_velocities[indexB].v;
float32 wB = m_velocities[indexB].w;
b2Vec2 normal = vc->normal;
b2Vec2 tangent = b2Cross(normal, 1.0f);
float32 friction = vc->friction;
b2Assert(pointCount == 1 || pointCount == 2);
// Solve tangent constraints first because non-penetration is more important
// than friction.
for (int32 j = 0; j < pointCount; ++j)
{
b2VelocityConstraintPoint* vcp = vc->points + j;
// Relative velocity at contact
b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
// Compute tangent force
float32 vt = b2Dot(dv, tangent) - vc->tangentSpeed;
float32 lambda = vcp->tangentMass * (-vt);
// b2Clamp the accumulated force
float32 maxFriction = friction * vcp->normalImpulse;
float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction);
lambda = newImpulse - vcp->tangentImpulse;
vcp->tangentImpulse = newImpulse;
// Apply contact impulse
b2Vec2 P = lambda * tangent;
vA -= mA * P;
wA -= iA * b2Cross(vcp->rA, P);
vB += mB * P;
wB += iB * b2Cross(vcp->rB, P);
}
// Solve normal constraints
if (vc->pointCount == 1)
{
b2VelocityConstraintPoint* vcp = vc->points + 0;
// Relative velocity at contact
b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
// Compute normal impulse
float32 vn = b2Dot(dv, normal);
float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias);
// b2Clamp the accumulated impulse
float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f);
lambda = newImpulse - vcp->normalImpulse;
vcp->normalImpulse = newImpulse;
// Apply contact impulse
b2Vec2 P = lambda * normal;
vA -= mA * P;
wA -= iA * b2Cross(vcp->rA, P);
vB += mB * P;
wB += iB * b2Cross(vcp->rB, P);
}
else
{
// Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
// Build the mini LCP for this contact patch
//
// vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
//
// A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
// b = vn0 - velocityBias
//
// The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
// implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
// vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
// solution that satisfies the problem is chosen.
//
// In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
// that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
//
// Substitute:
//
// x = a + d
//
// a := old total impulse
// x := new total impulse
// d := incremental impulse
//
// For the current iteration we extend the formula for the incremental impulse
// to compute the new total impulse:
//
// vn = A * d + b
// = A * (x - a) + b
// = A * x + b - A * a
// = A * x + b'
// b' = b - A * a;
b2VelocityConstraintPoint* cp1 = vc->points + 0;
b2VelocityConstraintPoint* cp2 = vc->points + 1;
b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse);
b2Assert(a.x >= 0.0f && a.y >= 0.0f);
// Relative velocity at contact
b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
float32 vn1 = b2Dot(dv1, normal);
float32 vn2 = b2Dot(dv2, normal);
b2Vec2 b;
b.x = vn1 - cp1->velocityBias;
b.y = vn2 - cp2->velocityBias;
// Compute b'
b -= b2Mul(vc->K, a);
const float32 k_errorTol = 1e-3f;
B2_NOT_USED(k_errorTol);
for (;;)
{
//
// Case 1: vn = 0
//
// 0 = A * x + b'
//
// Solve for x:
//
// x = - inv(A) * b'
//
b2Vec2 x = - b2Mul(vc->normalMass, b);
if (x.x >= 0.0f && x.y >= 0.0f)
{
// Get the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += mB * (P1 + P2);
wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
vn1 = b2Dot(dv1, normal);
vn2 = b2Dot(dv2, normal);
b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 2: vn1 = 0 and x2 = 0
//
// 0 = a11 * x1 + a12 * 0 + b1'
// vn2 = a21 * x1 + a22 * 0 + b2'
//
x.x = - cp1->normalMass * b.x;
x.y = 0.0f;
vn1 = 0.0f;
vn2 = vc->K.ex.y * x.x + b.y;
if (x.x >= 0.0f && vn2 >= 0.0f)
{
// Get the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += mB * (P1 + P2);
wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
// Compute normal velocity
vn1 = b2Dot(dv1, normal);
b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 3: vn2 = 0 and x1 = 0
//
// vn1 = a11 * 0 + a12 * x2 + b1'
// 0 = a21 * 0 + a22 * x2 + b2'
//
x.x = 0.0f;
x.y = - cp2->normalMass * b.y;
vn1 = vc->K.ey.x * x.y + b.x;
vn2 = 0.0f;
if (x.y >= 0.0f && vn1 >= 0.0f)
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += mB * (P1 + P2);
wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
#if B2_DEBUG_SOLVER == 1
// Postconditions
dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
// Compute normal velocity
vn2 = b2Dot(dv2, normal);
b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
#endif
break;
}
//
// Case 4: x1 = 0 and x2 = 0
//
// vn1 = b1
// vn2 = b2;
x.x = 0.0f;
x.y = 0.0f;
vn1 = b.x;
vn2 = b.y;
if (vn1 >= 0.0f && vn2 >= 0.0f )
{
// Resubstitute for the incremental impulse
b2Vec2 d = x - a;
// Apply incremental impulse
b2Vec2 P1 = d.x * normal;
b2Vec2 P2 = d.y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
vB += mB * (P1 + P2);
wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
// Accumulate
cp1->normalImpulse = x.x;
cp2->normalImpulse = x.y;
break;
}
// No solution, give up. This is hit sometimes, but it doesn't seem to matter.
break;
}
}
m_velocities[indexA].v = vA;
m_velocities[indexA].w = wA;
m_velocities[indexB].v = vB;
m_velocities[indexB].w = wB;
}
}
void b2ContactSolver::StoreImpulses()
{
for (int32 i = 0; i < m_count; ++i)
{
b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
for (int32 j = 0; j < vc->pointCount; ++j)
{
manifold->points[j].normalImpulse = vc->points[j].normalImpulse;
manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse;
}
}
}
struct b2PositionSolverManifold
{
void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index)
{
b2Assert(pc->pointCount > 0);
switch (pc->type)
{
case b2Manifold::e_circles:
{
b2Vec2 pointA = b2Mul(xfA, pc->localPoint);
b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]);
normal = pointB - pointA;
normal.Normalize();
point = 0.5f * (pointA + pointB);
separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB;
}
break;
case b2Manifold::e_faceA:
{
normal = b2Mul(xfA.q, pc->localNormal);
b2Vec2 planePoint = b2Mul(xfA, pc->localPoint);
b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]);
separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
point = clipPoint;
}
break;
case b2Manifold::e_faceB:
{
normal = b2Mul(xfB.q, pc->localNormal);
b2Vec2 planePoint = b2Mul(xfB, pc->localPoint);
b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]);
separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
point = clipPoint;
// Ensure normal points from A to B
normal = -normal;
}
break;
}
}
b2Vec2 normal;
b2Vec2 point;
float32 separation;
};
// Sequential solver.
bool b2ContactSolver::SolvePositionConstraints()
{
float32 minSeparation = 0.0f;
for (int32 i = 0; i < m_count; ++i)
{
b2ContactPositionConstraint* pc = m_positionConstraints + i;
int32 indexA = pc->indexA;
int32 indexB = pc->indexB;
b2Vec2 localCenterA = pc->localCenterA;
float32 mA = pc->invMassA;
float32 iA = pc->invIA;
b2Vec2 localCenterB = pc->localCenterB;
float32 mB = pc->invMassB;
float32 iB = pc->invIB;
int32 pointCount = pc->pointCount;
b2Vec2 cA = m_positions[indexA].c;
float32 aA = m_positions[indexA].a;
b2Vec2 cB = m_positions[indexB].c;
float32 aB = m_positions[indexB].a;
// Solve normal constraints
for (int32 j = 0; j < pointCount; ++j)
{
b2Transform xfA, xfB;
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - b2Mul(xfA.q, localCenterA);
xfB.p = cB - b2Mul(xfB.q, localCenterB);
b2PositionSolverManifold psm;
psm.Initialize(pc, xfA, xfB, j);
b2Vec2 normal = psm.normal;
b2Vec2 point = psm.point;
float32 separation = psm.separation;
b2Vec2 rA = point - cA;
b2Vec2 rB = point - cB;
// Track max constraint error.
minSeparation = b2Min(minSeparation, separation);
// Prevent large corrections and allow slop.
float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
// Compute the effective mass.
float32 rnA = b2Cross(rA, normal);
float32 rnB = b2Cross(rB, normal);
float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
// Compute normal impulse
float32 impulse = K > 0.0f ? - C / K : 0.0f;
b2Vec2 P = impulse * normal;
cA -= mA * P;
aA -= iA * b2Cross(rA, P);
cB += mB * P;
aB += iB * b2Cross(rB, P);
}
m_positions[indexA].c = cA;
m_positions[indexA].a = aA;
m_positions[indexB].c = cB;
m_positions[indexB].a = aB;
}
// We can't expect minSpeparation >= -b2_linearSlop because we don't
// push the separation above -b2_linearSlop.
return minSeparation >= -3.0f * b2_linearSlop;
}
// Sequential position solver for position constraints.
bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB)
{
float32 minSeparation = 0.0f;
for (int32 i = 0; i < m_count; ++i)
{
b2ContactPositionConstraint* pc = m_positionConstraints + i;
int32 indexA = pc->indexA;
int32 indexB = pc->indexB;
b2Vec2 localCenterA = pc->localCenterA;
b2Vec2 localCenterB = pc->localCenterB;
int32 pointCount = pc->pointCount;
float32 mA = 0.0f;
float32 iA = 0.0f;
if (indexA == toiIndexA || indexA == toiIndexB)
{
mA = pc->invMassA;
iA = pc->invIA;
}
float32 mB = 0.0f;
float32 iB = 0.;
if (indexB == toiIndexA || indexB == toiIndexB)
{
mB = pc->invMassB;
iB = pc->invIB;
}
b2Vec2 cA = m_positions[indexA].c;
float32 aA = m_positions[indexA].a;
b2Vec2 cB = m_positions[indexB].c;
float32 aB = m_positions[indexB].a;
// Solve normal constraints
for (int32 j = 0; j < pointCount; ++j)
{
b2Transform xfA, xfB;
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - b2Mul(xfA.q, localCenterA);
xfB.p = cB - b2Mul(xfB.q, localCenterB);
b2PositionSolverManifold psm;
psm.Initialize(pc, xfA, xfB, j);
b2Vec2 normal = psm.normal;
b2Vec2 point = psm.point;
float32 separation = psm.separation;
b2Vec2 rA = point - cA;
b2Vec2 rB = point - cB;
// Track max constraint error.
minSeparation = b2Min(minSeparation, separation);
// Prevent large corrections and allow slop.
float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
// Compute the effective mass.
float32 rnA = b2Cross(rA, normal);
float32 rnB = b2Cross(rB, normal);
float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
// Compute normal impulse
float32 impulse = K > 0.0f ? - C / K : 0.0f;
b2Vec2 P = impulse * normal;
cA -= mA * P;
aA -= iA * b2Cross(rA, P);
cB += mB * P;
aB += iB * b2Cross(rB, P);
}
m_positions[indexA].c = cA;
m_positions[indexA].a = aA;
m_positions[indexB].c = cB;
m_positions[indexB].a = aB;
}
// We can't expect minSpeparation >= -b2_linearSlop because we don't
// push the separation above -b2_linearSlop.
return minSeparation >= -1.5f * b2_linearSlop;
}
================================================
FILE: app/src/main/cpp/b2Distance.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Distance.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
void b2DistanceProxy::Set(const b2Shape* shape, int32 index)
{
switch (shape->GetType())
{
case b2Shape::e_circle:
{
const b2CircleShape* circle = static_cast(shape);
m_vertices = &circle->m_p;
m_count = 1;
m_radius = circle->m_radius;
}
break;
case b2Shape::e_polygon:
{
const b2PolygonShape* polygon = static_cast(shape);
m_vertices = polygon->m_vertices;
m_count = polygon->m_count;
m_radius = polygon->m_radius;
}
break;
case b2Shape::e_chain:
{
const b2ChainShape* chain = static_cast(shape);
b2Assert(0 <= index && index < chain->m_count);
m_buffer[0] = chain->m_vertices[index];
if (index + 1 < chain->m_count)
{
m_buffer[1] = chain->m_vertices[index + 1];
}
else
{
m_buffer[1] = chain->m_vertices[0];
}
m_vertices = m_buffer;
m_count = 2;
m_radius = chain->m_radius;
}
break;
case b2Shape::e_edge:
{
const b2EdgeShape* edge = static_cast(shape);
m_vertices = &edge->m_vertex1;
m_count = 2;
m_radius = edge->m_radius;
}
break;
default:
b2Assert(false);
}
}
struct b2SimplexVertex
{
b2Vec2 wA; // support point in proxyA
b2Vec2 wB; // support point in proxyB
b2Vec2 w; // wB - wA
float32 a; // barycentric coordinate for closest point
int32 indexA; // wA index
int32 indexB; // wB index
};
struct b2Simplex
{
void ReadCache( const b2SimplexCache* cache,
const b2DistanceProxy* proxyA, const b2Transform& transformA,
const b2DistanceProxy* proxyB, const b2Transform& transformB)
{
b2Assert(cache->count <= 3);
// Copy data from cache.
m_count = cache->count;
b2SimplexVertex* vertices = &m_v1;
for (int32 i = 0; i < m_count; ++i)
{
b2SimplexVertex* v = vertices + i;
v->indexA = cache->indexA[i];
v->indexB = cache->indexB[i];
b2Vec2 wALocal = proxyA->GetVertex(v->indexA);
b2Vec2 wBLocal = proxyB->GetVertex(v->indexB);
v->wA = b2Mul(transformA, wALocal);
v->wB = b2Mul(transformB, wBLocal);
v->w = v->wB - v->wA;
v->a = 0.0f;
}
// Compute the new simplex metric, if it is substantially different than
// old metric then flush the simplex.
if (m_count > 1)
{
float32 metric1 = cache->metric;
float32 metric2 = GetMetric();
if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon)
{
// Reset the simplex.
m_count = 0;
}
}
// If the cache is empty or invalid ...
if (m_count == 0)
{
b2SimplexVertex* v = vertices + 0;
v->indexA = 0;
v->indexB = 0;
b2Vec2 wALocal = proxyA->GetVertex(0);
b2Vec2 wBLocal = proxyB->GetVertex(0);
v->wA = b2Mul(transformA, wALocal);
v->wB = b2Mul(transformB, wBLocal);
v->w = v->wB - v->wA;
v->a = 1.0f;
m_count = 1;
}
}
void WriteCache(b2SimplexCache* cache) const
{
cache->metric = GetMetric();
cache->count = uint16(m_count);
const b2SimplexVertex* vertices = &m_v1;
for (int32 i = 0; i < m_count; ++i)
{
cache->indexA[i] = uint8(vertices[i].indexA);
cache->indexB[i] = uint8(vertices[i].indexB);
}
}
b2Vec2 GetSearchDirection() const
{
switch (m_count)
{
case 1:
return -m_v1.w;
case 2:
{
b2Vec2 e12 = m_v2.w - m_v1.w;
float32 sgn = b2Cross(e12, -m_v1.w);
if (sgn > 0.0f)
{
// Origin is left of e12.
return b2Cross(1.0f, e12);
}
else
{
// Origin is right of e12.
return b2Cross(e12, 1.0f);
}
}
default:
b2Assert(false);
return b2Vec2_zero;
}
}
b2Vec2 GetClosestPoint() const
{
switch (m_count)
{
case 0:
b2Assert(false);
return b2Vec2_zero;
case 1:
return m_v1.w;
case 2:
return m_v1.a * m_v1.w + m_v2.a * m_v2.w;
case 3:
return b2Vec2_zero;
default:
b2Assert(false);
return b2Vec2_zero;
}
}
void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const
{
switch (m_count)
{
case 0:
b2Assert(false);
break;
case 1:
*pA = m_v1.wA;
*pB = m_v1.wB;
break;
case 2:
*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;
*pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;
break;
case 3:
*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
*pB = *pA;
break;
default:
b2Assert(false);
break;
}
}
float32 GetMetric() const
{
switch (m_count)
{
case 0:
b2Assert(false);
return 0.0f;
case 1:
return 0.0f;
case 2:
return b2Distance(m_v1.w, m_v2.w);
case 3:
return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);
default:
b2Assert(false);
return 0.0f;
}
}
void Solve2();
void Solve3();
b2SimplexVertex m_v1, m_v2, m_v3;
int32 m_count;
};
// Solve a line segment using barycentric coordinates.
//
// p = a1 * w1 + a2 * w2
// a1 + a2 = 1
//
// The vector from the origin to the closest point on the line is
// perpendicular to the line.
// e12 = w2 - w1
// dot(p, e) = 0
// a1 * dot(w1, e) + a2 * dot(w2, e) = 0
//
// 2-by-2 linear system
// [1 1 ][a1] = [1]
// [w1.e12 w2.e12][a2] = [0]
//
// Define
// d12_1 = dot(w2, e12)
// d12_2 = -dot(w1, e12)
// d12 = d12_1 + d12_2
//
// Solution
// a1 = d12_1 / d12
// a2 = d12_2 / d12
void b2Simplex::Solve2()
{
b2Vec2 w1 = m_v1.w;
b2Vec2 w2 = m_v2.w;
b2Vec2 e12 = w2 - w1;
// w1 region
float32 d12_2 = -b2Dot(w1, e12);
if (d12_2 <= 0.0f)
{
// a2 <= 0, so we clamp it to 0
m_v1.a = 1.0f;
m_count = 1;
return;
}
// w2 region
float32 d12_1 = b2Dot(w2, e12);
if (d12_1 <= 0.0f)
{
// a1 <= 0, so we clamp it to 0
m_v2.a = 1.0f;
m_count = 1;
m_v1 = m_v2;
return;
}
// Must be in e12 region.
float32 inv_d12 = 1.0f / (d12_1 + d12_2);
m_v1.a = d12_1 * inv_d12;
m_v2.a = d12_2 * inv_d12;
m_count = 2;
}
// Possible regions:
// - points[2]
// - edge points[0]-points[2]
// - edge points[1]-points[2]
// - inside the triangle
void b2Simplex::Solve3()
{
b2Vec2 w1 = m_v1.w;
b2Vec2 w2 = m_v2.w;
b2Vec2 w3 = m_v3.w;
// Edge12
// [1 1 ][a1] = [1]
// [w1.e12 w2.e12][a2] = [0]
// a3 = 0
b2Vec2 e12 = w2 - w1;
float32 w1e12 = b2Dot(w1, e12);
float32 w2e12 = b2Dot(w2, e12);
float32 d12_1 = w2e12;
float32 d12_2 = -w1e12;
// Edge13
// [1 1 ][a1] = [1]
// [w1.e13 w3.e13][a3] = [0]
// a2 = 0
b2Vec2 e13 = w3 - w1;
float32 w1e13 = b2Dot(w1, e13);
float32 w3e13 = b2Dot(w3, e13);
float32 d13_1 = w3e13;
float32 d13_2 = -w1e13;
// Edge23
// [1 1 ][a2] = [1]
// [w2.e23 w3.e23][a3] = [0]
// a1 = 0
b2Vec2 e23 = w3 - w2;
float32 w2e23 = b2Dot(w2, e23);
float32 w3e23 = b2Dot(w3, e23);
float32 d23_1 = w3e23;
float32 d23_2 = -w2e23;
// Triangle123
float32 n123 = b2Cross(e12, e13);
float32 d123_1 = n123 * b2Cross(w2, w3);
float32 d123_2 = n123 * b2Cross(w3, w1);
float32 d123_3 = n123 * b2Cross(w1, w2);
// w1 region
if (d12_2 <= 0.0f && d13_2 <= 0.0f)
{
m_v1.a = 1.0f;
m_count = 1;
return;
}
// e12
if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
{
float32 inv_d12 = 1.0f / (d12_1 + d12_2);
m_v1.a = d12_1 * inv_d12;
m_v2.a = d12_2 * inv_d12;
m_count = 2;
return;
}
// e13
if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
{
float32 inv_d13 = 1.0f / (d13_1 + d13_2);
m_v1.a = d13_1 * inv_d13;
m_v3.a = d13_2 * inv_d13;
m_count = 2;
m_v2 = m_v3;
return;
}
// w2 region
if (d12_1 <= 0.0f && d23_2 <= 0.0f)
{
m_v2.a = 1.0f;
m_count = 1;
m_v1 = m_v2;
return;
}
// w3 region
if (d13_1 <= 0.0f && d23_1 <= 0.0f)
{
m_v3.a = 1.0f;
m_count = 1;
m_v1 = m_v3;
return;
}
// e23
if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
{
float32 inv_d23 = 1.0f / (d23_1 + d23_2);
m_v2.a = d23_1 * inv_d23;
m_v3.a = d23_2 * inv_d23;
m_count = 2;
m_v1 = m_v3;
return;
}
// Must be in triangle123
float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);
m_v1.a = d123_1 * inv_d123;
m_v2.a = d123_2 * inv_d123;
m_v3.a = d123_3 * inv_d123;
m_count = 3;
}
void b2Distance(b2DistanceOutput* output,
b2SimplexCache* cache,
const b2DistanceInput* input)
{
++b2_gjkCalls;
const b2DistanceProxy* proxyA = &input->proxyA;
const b2DistanceProxy* proxyB = &input->proxyB;
b2Transform transformA = input->transformA;
b2Transform transformB = input->transformB;
// Initialize the simplex.
b2Simplex simplex;
simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);
// Get simplex vertices as an array.
b2SimplexVertex* vertices = &simplex.m_v1;
const int32 k_maxIters = 20;
// These store the vertices of the last simplex so that we
// can check for duplicates and prevent cycling.
int32 saveA[3], saveB[3];
int32 saveCount = 0;
float32 distanceSqr1 = b2_maxFloat;
float32 distanceSqr2 = distanceSqr1;
// Main iteration loop.
int32 iter = 0;
while (iter < k_maxIters)
{
// Copy simplex so we can identify duplicates.
saveCount = simplex.m_count;
for (int32 i = 0; i < saveCount; ++i)
{
saveA[i] = vertices[i].indexA;
saveB[i] = vertices[i].indexB;
}
switch (simplex.m_count)
{
case 1:
break;
case 2:
simplex.Solve2();
break;
case 3:
simplex.Solve3();
break;
default:
b2Assert(false);
}
// If we have 3 points, then the origin is in the corresponding triangle.
if (simplex.m_count == 3)
{
break;
}
// Compute closest point.
b2Vec2 p = simplex.GetClosestPoint();
distanceSqr2 = p.LengthSquared();
// Ensure progress
if (distanceSqr2 >= distanceSqr1)
{
//break;
}
distanceSqr1 = distanceSqr2;
// Get search direction.
b2Vec2 d = simplex.GetSearchDirection();
// Ensure the search direction is numerically fit.
if (d.LengthSquared() < b2_epsilon * b2_epsilon)
{
// The origin is probably contained by a line segment
// or triangle. Thus the shapes are overlapped.
// We can't return zero here even though there may be overlap.
// In case the simplex is a point, segment, or triangle it is difficult
// to determine if the origin is contained in the CSO or very close to it.
break;
}
// Compute a tentative new simplex vertex using support points.
b2SimplexVertex* vertex = vertices + simplex.m_count;
vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d));
vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA));
b2Vec2 wBLocal;
vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d));
vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB));
vertex->w = vertex->wB - vertex->wA;
// Iteration count is equated to the number of support point calls.
++iter;
++b2_gjkIters;
// Check for duplicate support points. This is the main termination criteria.
bool duplicate = false;
for (int32 i = 0; i < saveCount; ++i)
{
if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])
{
duplicate = true;
break;
}
}
// If we found a duplicate support point we must exit to avoid cycling.
if (duplicate)
{
break;
}
// New vertex is ok and needed.
++simplex.m_count;
}
b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter);
// Prepare output.
simplex.GetWitnessPoints(&output->pointA, &output->pointB);
output->distance = b2Distance(output->pointA, output->pointB);
output->iterations = iter;
// Cache the simplex.
simplex.WriteCache(cache);
// Apply radii if requested.
if (input->useRadii)
{
float32 rA = proxyA->m_radius;
float32 rB = proxyB->m_radius;
if (output->distance > rA + rB && output->distance > b2_epsilon)
{
// Shapes are still no overlapped.
// Move the witness points to the outer surface.
output->distance -= rA + rB;
b2Vec2 normal = output->pointB - output->pointA;
normal.Normalize();
output->pointA += rA * normal;
output->pointB -= rB * normal;
}
else
{
// Shapes are overlapped when radii are considered.
// Move the witness points to the middle.
b2Vec2 p = 0.5f * (output->pointA + output->pointB);
output->pointA = p;
output->pointB = p;
output->distance = 0.0f;
}
}
}
================================================
FILE: app/src/main/cpp/b2DistanceJoint.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2DistanceJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// 1-D constrained system
// m (v2 - v1) = lambda
// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
// x2 = x1 + h * v2
// 1-D mass-damper-spring system
// m (v2 - v1) + h * d * v2 + h * k *
// C = norm(p2 - p1) - L
// u = (p2 - p1) / norm(p2 - p1)
// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// J = [-u -cross(r1, u) u cross(r2, u)]
// K = J * invM * JT
// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
const b2Vec2& anchor1, const b2Vec2& anchor2)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor1);
localAnchorB = bodyB->GetLocalPoint(anchor2);
b2Vec2 d = anchor2 - anchor1;
length = d.Length();
}
b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_length = def->length;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_impulse = 0.0f;
m_gamma = 0.0f;
m_bias = 0.0f;
}
void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
m_u = cB + m_rB - cA - m_rA;
// Handle singularity.
float32 length = m_u.Length();
if (length > b2_linearSlop)
{
m_u *= 1.0f / length;
}
else
{
m_u.Set(0.0f, 0.0f);
}
float32 crAu = b2Cross(m_rA, m_u);
float32 crBu = b2Cross(m_rB, m_u);
float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
// Compute the effective mass matrix.
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (m_frequencyHz > 0.0f)
{
float32 C = length - m_length;
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m_mass * m_dampingRatio * omega;
// Spring stiffness
float32 k = m_mass * omega * omega;
// magic formulas
float32 h = data.step.dt;
m_gamma = h * (d + h * k);
m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
m_bias = C * h * k * m_gamma;
invMass += m_gamma;
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
}
else
{
m_gamma = 0.0f;
m_bias = 0.0f;
}
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
m_impulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Cdot = dot(u, v + cross(w, r))
b2Vec2 vpA = vA + b2Cross(wA, m_rA);
b2Vec2 vpB = vB + b2Cross(wB, m_rB);
float32 Cdot = b2Dot(m_u, vpB - vpA);
float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
m_impulse += impulse;
b2Vec2 P = impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
{
if (m_frequencyHz > 0.0f)
{
// There is no position correction for soft distance constraints.
return true;
}
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 u = cB + rB - cA - rA;
float32 length = u.Normalize();
float32 C = length - m_length;
C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
float32 impulse = -m_mass * C;
b2Vec2 P = impulse * u;
cA -= m_invMassA * P;
aA -= m_invIA * b2Cross(rA, P);
cB += m_invMassB * P;
aB += m_invIB * b2Cross(rB, P);
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return b2Abs(C) < b2_linearSlop;
}
b2Vec2 b2DistanceJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2DistanceJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 F = (inv_dt * m_impulse) * m_u;
return F;
}
float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
void b2DistanceJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2DistanceJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.length = %.15lef;\n", m_length);
b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2Draw.cpp
================================================
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2Draw.h"
b2Draw::b2Draw()
{
m_drawFlags = 0;
}
void b2Draw::SetFlags(uint32 flags)
{
m_drawFlags = flags;
}
uint32 b2Draw::GetFlags() const
{
return m_drawFlags;
}
void b2Draw::AppendFlags(uint32 flags)
{
m_drawFlags |= flags;
}
void b2Draw::ClearFlags(uint32 flags)
{
m_drawFlags &= ~flags;
}
================================================
FILE: app/src/main/cpp/b2DynamicTree.cpp
================================================
/*
* Copyright (c) 2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2DynamicTree.h"
#include
#include
b2DynamicTree::b2DynamicTree()
{
m_root = b2_nullNode;
m_nodeCapacity = 16;
m_nodeCount = 0;
m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode));
// Build a linked list for the free list.
for (int32 i = 0; i < m_nodeCapacity - 1; ++i)
{
m_nodes[i].next = i + 1;
m_nodes[i].height = -1;
}
m_nodes[m_nodeCapacity-1].next = b2_nullNode;
m_nodes[m_nodeCapacity-1].height = -1;
m_freeList = 0;
m_path = 0;
m_insertionCount = 0;
}
b2DynamicTree::~b2DynamicTree()
{
// This frees the entire tree in one shot.
b2Free(m_nodes);
}
// Allocate a node from the pool. Grow the pool if necessary.
int32 b2DynamicTree::AllocateNode()
{
// Expand the node pool as needed.
if (m_freeList == b2_nullNode)
{
b2Assert(m_nodeCount == m_nodeCapacity);
// The free list is empty. Rebuild a bigger pool.
b2TreeNode* oldNodes = m_nodes;
m_nodeCapacity *= 2;
m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode));
b2Free(oldNodes);
// Build a linked list for the free list. The parent
// pointer becomes the "next" pointer.
for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
{
m_nodes[i].next = i + 1;
m_nodes[i].height = -1;
}
m_nodes[m_nodeCapacity-1].next = b2_nullNode;
m_nodes[m_nodeCapacity-1].height = -1;
m_freeList = m_nodeCount;
}
// Peel a node off the free list.
int32 nodeId = m_freeList;
m_freeList = m_nodes[nodeId].next;
m_nodes[nodeId].parent = b2_nullNode;
m_nodes[nodeId].child1 = b2_nullNode;
m_nodes[nodeId].child2 = b2_nullNode;
m_nodes[nodeId].height = 0;
m_nodes[nodeId].userData = NULL;
++m_nodeCount;
return nodeId;
}
// Return a node to the pool.
void b2DynamicTree::FreeNode(int32 nodeId)
{
b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
b2Assert(0 < m_nodeCount);
m_nodes[nodeId].next = m_freeList;
m_nodes[nodeId].height = -1;
m_freeList = nodeId;
--m_nodeCount;
}
// Create a proxy in the tree as a leaf node. We return the index
// of the node instead of a pointer so that we can grow
// the node pool.
int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)
{
int32 proxyId = AllocateNode();
// Fatten the aabb.
b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;
m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;
m_nodes[proxyId].userData = userData;
m_nodes[proxyId].height = 0;
InsertLeaf(proxyId);
return proxyId;
}
void b2DynamicTree::DestroyProxy(int32 proxyId)
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
b2Assert(m_nodes[proxyId].IsLeaf());
RemoveLeaf(proxyId);
FreeNode(proxyId);
}
bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
b2Assert(m_nodes[proxyId].IsLeaf());
if (m_nodes[proxyId].aabb.Contains(aabb))
{
return false;
}
RemoveLeaf(proxyId);
// Extend AABB.
b2AABB b = aabb;
b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
b.lowerBound = b.lowerBound - r;
b.upperBound = b.upperBound + r;
// Predict AABB displacement.
b2Vec2 d = b2_aabbMultiplier * displacement;
if (d.x < 0.0f)
{
b.lowerBound.x += d.x;
}
else
{
b.upperBound.x += d.x;
}
if (d.y < 0.0f)
{
b.lowerBound.y += d.y;
}
else
{
b.upperBound.y += d.y;
}
m_nodes[proxyId].aabb = b;
InsertLeaf(proxyId);
return true;
}
void b2DynamicTree::InsertLeaf(int32 leaf)
{
++m_insertionCount;
if (m_root == b2_nullNode)
{
m_root = leaf;
m_nodes[m_root].parent = b2_nullNode;
return;
}
// Find the best sibling for this node
b2AABB leafAABB = m_nodes[leaf].aabb;
int32 index = m_root;
while (m_nodes[index].IsLeaf() == false)
{
int32 child1 = m_nodes[index].child1;
int32 child2 = m_nodes[index].child2;
float32 area = m_nodes[index].aabb.GetPerimeter();
b2AABB combinedAABB;
combinedAABB.Combine(m_nodes[index].aabb, leafAABB);
float32 combinedArea = combinedAABB.GetPerimeter();
// Cost of creating a new parent for this node and the new leaf
float32 cost = 2.0f * combinedArea;
// Minimum cost of pushing the leaf further down the tree
float32 inheritanceCost = 2.0f * (combinedArea - area);
// Cost of descending into child1
float32 cost1;
if (m_nodes[child1].IsLeaf())
{
b2AABB aabb;
aabb.Combine(leafAABB, m_nodes[child1].aabb);
cost1 = aabb.GetPerimeter() + inheritanceCost;
}
else
{
b2AABB aabb;
aabb.Combine(leafAABB, m_nodes[child1].aabb);
float32 oldArea = m_nodes[child1].aabb.GetPerimeter();
float32 newArea = aabb.GetPerimeter();
cost1 = (newArea - oldArea) + inheritanceCost;
}
// Cost of descending into child2
float32 cost2;
if (m_nodes[child2].IsLeaf())
{
b2AABB aabb;
aabb.Combine(leafAABB, m_nodes[child2].aabb);
cost2 = aabb.GetPerimeter() + inheritanceCost;
}
else
{
b2AABB aabb;
aabb.Combine(leafAABB, m_nodes[child2].aabb);
float32 oldArea = m_nodes[child2].aabb.GetPerimeter();
float32 newArea = aabb.GetPerimeter();
cost2 = newArea - oldArea + inheritanceCost;
}
// Descend according to the minimum cost.
if (cost < cost1 && cost < cost2)
{
break;
}
// Descend
if (cost1 < cost2)
{
index = child1;
}
else
{
index = child2;
}
}
int32 sibling = index;
// Create a new parent.
int32 oldParent = m_nodes[sibling].parent;
int32 newParent = AllocateNode();
m_nodes[newParent].parent = oldParent;
m_nodes[newParent].userData = NULL;
m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb);
m_nodes[newParent].height = m_nodes[sibling].height + 1;
if (oldParent != b2_nullNode)
{
// The sibling was not the root.
if (m_nodes[oldParent].child1 == sibling)
{
m_nodes[oldParent].child1 = newParent;
}
else
{
m_nodes[oldParent].child2 = newParent;
}
m_nodes[newParent].child1 = sibling;
m_nodes[newParent].child2 = leaf;
m_nodes[sibling].parent = newParent;
m_nodes[leaf].parent = newParent;
}
else
{
// The sibling was the root.
m_nodes[newParent].child1 = sibling;
m_nodes[newParent].child2 = leaf;
m_nodes[sibling].parent = newParent;
m_nodes[leaf].parent = newParent;
m_root = newParent;
}
// Walk back up the tree fixing heights and AABBs
index = m_nodes[leaf].parent;
while (index != b2_nullNode)
{
index = Balance(index);
int32 child1 = m_nodes[index].child1;
int32 child2 = m_nodes[index].child2;
b2Assert(child1 != b2_nullNode);
b2Assert(child2 != b2_nullNode);
m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
index = m_nodes[index].parent;
}
//Validate();
}
void b2DynamicTree::RemoveLeaf(int32 leaf)
{
if (leaf == m_root)
{
m_root = b2_nullNode;
return;
}
int32 parent = m_nodes[leaf].parent;
int32 grandParent = m_nodes[parent].parent;
int32 sibling;
if (m_nodes[parent].child1 == leaf)
{
sibling = m_nodes[parent].child2;
}
else
{
sibling = m_nodes[parent].child1;
}
if (grandParent != b2_nullNode)
{
// Destroy parent and connect sibling to grandParent.
if (m_nodes[grandParent].child1 == parent)
{
m_nodes[grandParent].child1 = sibling;
}
else
{
m_nodes[grandParent].child2 = sibling;
}
m_nodes[sibling].parent = grandParent;
FreeNode(parent);
// Adjust ancestor bounds.
int32 index = grandParent;
while (index != b2_nullNode)
{
index = Balance(index);
int32 child1 = m_nodes[index].child1;
int32 child2 = m_nodes[index].child2;
m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
index = m_nodes[index].parent;
}
}
else
{
m_root = sibling;
m_nodes[sibling].parent = b2_nullNode;
FreeNode(parent);
}
//Validate();
}
// Perform a left or right rotation if node A is imbalanced.
// Returns the new root index.
int32 b2DynamicTree::Balance(int32 iA)
{
b2Assert(iA != b2_nullNode);
b2TreeNode* A = m_nodes + iA;
if (A->IsLeaf() || A->height < 2)
{
return iA;
}
int32 iB = A->child1;
int32 iC = A->child2;
b2Assert(0 <= iB && iB < m_nodeCapacity);
b2Assert(0 <= iC && iC < m_nodeCapacity);
b2TreeNode* B = m_nodes + iB;
b2TreeNode* C = m_nodes + iC;
int32 balance = C->height - B->height;
// Rotate C up
if (balance > 1)
{
int32 iF = C->child1;
int32 iG = C->child2;
b2TreeNode* F = m_nodes + iF;
b2TreeNode* G = m_nodes + iG;
b2Assert(0 <= iF && iF < m_nodeCapacity);
b2Assert(0 <= iG && iG < m_nodeCapacity);
// Swap A and C
C->child1 = iA;
C->parent = A->parent;
A->parent = iC;
// A's old parent should point to C
if (C->parent != b2_nullNode)
{
if (m_nodes[C->parent].child1 == iA)
{
m_nodes[C->parent].child1 = iC;
}
else
{
b2Assert(m_nodes[C->parent].child2 == iA);
m_nodes[C->parent].child2 = iC;
}
}
else
{
m_root = iC;
}
// Rotate
if (F->height > G->height)
{
C->child2 = iF;
A->child2 = iG;
G->parent = iA;
A->aabb.Combine(B->aabb, G->aabb);
C->aabb.Combine(A->aabb, F->aabb);
A->height = 1 + b2Max(B->height, G->height);
C->height = 1 + b2Max(A->height, F->height);
}
else
{
C->child2 = iG;
A->child2 = iF;
F->parent = iA;
A->aabb.Combine(B->aabb, F->aabb);
C->aabb.Combine(A->aabb, G->aabb);
A->height = 1 + b2Max(B->height, F->height);
C->height = 1 + b2Max(A->height, G->height);
}
return iC;
}
// Rotate B up
if (balance < -1)
{
int32 iD = B->child1;
int32 iE = B->child2;
b2TreeNode* D = m_nodes + iD;
b2TreeNode* E = m_nodes + iE;
b2Assert(0 <= iD && iD < m_nodeCapacity);
b2Assert(0 <= iE && iE < m_nodeCapacity);
// Swap A and B
B->child1 = iA;
B->parent = A->parent;
A->parent = iB;
// A's old parent should point to B
if (B->parent != b2_nullNode)
{
if (m_nodes[B->parent].child1 == iA)
{
m_nodes[B->parent].child1 = iB;
}
else
{
b2Assert(m_nodes[B->parent].child2 == iA);
m_nodes[B->parent].child2 = iB;
}
}
else
{
m_root = iB;
}
// Rotate
if (D->height > E->height)
{
B->child2 = iD;
A->child1 = iE;
E->parent = iA;
A->aabb.Combine(C->aabb, E->aabb);
B->aabb.Combine(A->aabb, D->aabb);
A->height = 1 + b2Max(C->height, E->height);
B->height = 1 + b2Max(A->height, D->height);
}
else
{
B->child2 = iE;
A->child1 = iD;
D->parent = iA;
A->aabb.Combine(C->aabb, D->aabb);
B->aabb.Combine(A->aabb, E->aabb);
A->height = 1 + b2Max(C->height, D->height);
B->height = 1 + b2Max(A->height, E->height);
}
return iB;
}
return iA;
}
int32 b2DynamicTree::GetHeight() const
{
if (m_root == b2_nullNode)
{
return 0;
}
return m_nodes[m_root].height;
}
//
float32 b2DynamicTree::GetAreaRatio() const
{
if (m_root == b2_nullNode)
{
return 0.0f;
}
const b2TreeNode* root = m_nodes + m_root;
float32 rootArea = root->aabb.GetPerimeter();
float32 totalArea = 0.0f;
for (int32 i = 0; i < m_nodeCapacity; ++i)
{
const b2TreeNode* node = m_nodes + i;
if (node->height < 0)
{
// Free node in pool
continue;
}
totalArea += node->aabb.GetPerimeter();
}
return totalArea / rootArea;
}
// Compute the height of a sub-tree.
int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
{
b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
b2TreeNode* node = m_nodes + nodeId;
if (node->IsLeaf())
{
return 0;
}
int32 height1 = ComputeHeight(node->child1);
int32 height2 = ComputeHeight(node->child2);
return 1 + b2Max(height1, height2);
}
int32 b2DynamicTree::ComputeHeight() const
{
int32 height = ComputeHeight(m_root);
return height;
}
void b2DynamicTree::ValidateStructure(int32 index) const
{
if (index == b2_nullNode)
{
return;
}
if (index == m_root)
{
b2Assert(m_nodes[index].parent == b2_nullNode);
}
const b2TreeNode* node = m_nodes + index;
int32 child1 = node->child1;
int32 child2 = node->child2;
if (node->IsLeaf())
{
b2Assert(child1 == b2_nullNode);
b2Assert(child2 == b2_nullNode);
b2Assert(node->height == 0);
return;
}
b2Assert(0 <= child1 && child1 < m_nodeCapacity);
b2Assert(0 <= child2 && child2 < m_nodeCapacity);
b2Assert(m_nodes[child1].parent == index);
b2Assert(m_nodes[child2].parent == index);
ValidateStructure(child1);
ValidateStructure(child2);
}
void b2DynamicTree::ValidateMetrics(int32 index) const
{
if (index == b2_nullNode)
{
return;
}
const b2TreeNode* node = m_nodes + index;
int32 child1 = node->child1;
int32 child2 = node->child2;
if (node->IsLeaf())
{
b2Assert(child1 == b2_nullNode);
b2Assert(child2 == b2_nullNode);
b2Assert(node->height == 0);
return;
}
b2Assert(0 <= child1 && child1 < m_nodeCapacity);
b2Assert(0 <= child2 && child2 < m_nodeCapacity);
int32 height1 = m_nodes[child1].height;
int32 height2 = m_nodes[child2].height;
int32 height;
height = 1 + b2Max(height1, height2);
b2Assert(node->height == height);
b2AABB aabb;
aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
b2Assert(aabb.lowerBound == node->aabb.lowerBound);
b2Assert(aabb.upperBound == node->aabb.upperBound);
ValidateMetrics(child1);
ValidateMetrics(child2);
}
void b2DynamicTree::Validate() const
{
ValidateStructure(m_root);
ValidateMetrics(m_root);
int32 freeCount = 0;
int32 freeIndex = m_freeList;
while (freeIndex != b2_nullNode)
{
b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity);
freeIndex = m_nodes[freeIndex].next;
++freeCount;
}
b2Assert(GetHeight() == ComputeHeight());
b2Assert(m_nodeCount + freeCount == m_nodeCapacity);
}
int32 b2DynamicTree::GetMaxBalance() const
{
int32 maxBalance = 0;
for (int32 i = 0; i < m_nodeCapacity; ++i)
{
const b2TreeNode* node = m_nodes + i;
if (node->height <= 1)
{
continue;
}
b2Assert(node->IsLeaf() == false);
int32 child1 = node->child1;
int32 child2 = node->child2;
int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height);
maxBalance = b2Max(maxBalance, balance);
}
return maxBalance;
}
void b2DynamicTree::RebuildBottomUp()
{
int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32));
int32 count = 0;
// Build array of leaves. Free the rest.
for (int32 i = 0; i < m_nodeCapacity; ++i)
{
if (m_nodes[i].height < 0)
{
// free node in pool
continue;
}
if (m_nodes[i].IsLeaf())
{
m_nodes[i].parent = b2_nullNode;
nodes[count] = i;
++count;
}
else
{
FreeNode(i);
}
}
while (count > 1)
{
float32 minCost = b2_maxFloat;
int32 iMin = -1, jMin = -1;
for (int32 i = 0; i < count; ++i)
{
b2AABB aabbi = m_nodes[nodes[i]].aabb;
for (int32 j = i + 1; j < count; ++j)
{
b2AABB aabbj = m_nodes[nodes[j]].aabb;
b2AABB b;
b.Combine(aabbi, aabbj);
float32 cost = b.GetPerimeter();
if (cost < minCost)
{
iMin = i;
jMin = j;
minCost = cost;
}
}
}
int32 index1 = nodes[iMin];
int32 index2 = nodes[jMin];
b2TreeNode* child1 = m_nodes + index1;
b2TreeNode* child2 = m_nodes + index2;
int32 parentIndex = AllocateNode();
b2TreeNode* parent = m_nodes + parentIndex;
parent->child1 = index1;
parent->child2 = index2;
parent->height = 1 + b2Max(child1->height, child2->height);
parent->aabb.Combine(child1->aabb, child2->aabb);
parent->parent = b2_nullNode;
child1->parent = parentIndex;
child2->parent = parentIndex;
nodes[jMin] = nodes[count-1];
nodes[iMin] = parentIndex;
--count;
}
m_root = nodes[0];
b2Free(nodes);
Validate();
}
void b2DynamicTree::ShiftOrigin(const b2Vec2& newOrigin)
{
// Build array of leaves. Free the rest.
for (int32 i = 0; i < m_nodeCapacity; ++i)
{
m_nodes[i].aabb.lowerBound -= newOrigin;
m_nodes[i].aabb.upperBound -= newOrigin;
}
}
================================================
FILE: app/src/main/cpp/b2EdgeAndCircleContact.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include
b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact));
return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB);
}
void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact();
allocator->Free(contact, sizeof(b2EdgeAndCircleContact));
}
b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideEdgeAndCircle( manifold,
(b2EdgeShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2EdgeAndPolygonContact.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include
b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact));
return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB);
}
void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact();
allocator->Free(contact, sizeof(b2EdgeAndPolygonContact));
}
b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideEdgeAndPolygon( manifold,
(b2EdgeShape*)m_fixtureA->GetShape(), xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2EdgeShape.cpp
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include
void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2)
{
m_vertex1 = v1;
m_vertex2 = v2;
m_hasVertex0 = false;
m_hasVertex3 = false;
}
b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2EdgeShape));
b2EdgeShape* clone = new (mem) b2EdgeShape;
*clone = *this;
return clone;
}
int32 b2EdgeShape::GetChildCount() const
{
return 1;
}
bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
{
B2_NOT_USED(xf);
B2_NOT_USED(p);
return false;
}
// p = p1 + t * d
// v = v1 + s * e
// p1 + t * d = v1 + s * e
// s * e - t * d = p1 - v1
bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& xf, int32 childIndex) const
{
B2_NOT_USED(childIndex);
// Put the ray into the edge's frame of reference.
b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
b2Vec2 d = p2 - p1;
b2Vec2 v1 = m_vertex1;
b2Vec2 v2 = m_vertex2;
b2Vec2 e = v2 - v1;
b2Vec2 normal(e.y, -e.x);
normal.Normalize();
// q = p1 + t * d
// dot(normal, q - v1) = 0
// dot(normal, p1 - v1) + t * dot(normal, d) = 0
float32 numerator = b2Dot(normal, v1 - p1);
float32 denominator = b2Dot(normal, d);
if (denominator == 0.0f)
{
return false;
}
float32 t = numerator / denominator;
if (t < 0.0f || input.maxFraction < t)
{
return false;
}
b2Vec2 q = p1 + t * d;
// q = v1 + s * r
// s = dot(q - v1, r) / dot(r, r)
b2Vec2 r = v2 - v1;
float32 rr = b2Dot(r, r);
if (rr == 0.0f)
{
return false;
}
float32 s = b2Dot(q - v1, r) / rr;
if (s < 0.0f || 1.0f < s)
{
return false;
}
output->fraction = t;
if (numerator > 0.0f)
{
output->normal = -b2Mul(xf.q, normal);
}
else
{
output->normal = b2Mul(xf.q, normal);
}
return true;
}
void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
{
B2_NOT_USED(childIndex);
b2Vec2 v1 = b2Mul(xf, m_vertex1);
b2Vec2 v2 = b2Mul(xf, m_vertex2);
b2Vec2 lower = b2Min(v1, v2);
b2Vec2 upper = b2Max(v1, v2);
b2Vec2 r(m_radius, m_radius);
aabb->lowerBound = lower - r;
aabb->upperBound = upper + r;
}
void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const
{
B2_NOT_USED(density);
massData->mass = 0.0f;
massData->center = 0.5f * (m_vertex1 + m_vertex2);
massData->I = 0.0f;
}
================================================
FILE: app/src/main/cpp/b2Fixture.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/b2BroadPhase.h"
#include "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
b2Fixture::b2Fixture()
{
m_userData = NULL;
m_body = NULL;
m_next = NULL;
m_proxies = NULL;
m_proxyCount = 0;
m_shape = NULL;
m_density = 0.0f;
}
void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)
{
m_userData = def->userData;
m_friction = def->friction;
m_restitution = def->restitution;
m_body = body;
m_next = NULL;
m_filter = def->filter;
m_isSensor = def->isSensor;
m_shape = def->shape->Clone(allocator);
// Reserve proxy space
int32 childCount = m_shape->GetChildCount();
m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy));
for (int32 i = 0; i < childCount; ++i)
{
m_proxies[i].fixture = NULL;
m_proxies[i].proxyId = b2BroadPhase::e_nullProxy;
}
m_proxyCount = 0;
m_density = def->density;
}
void b2Fixture::Destroy(b2BlockAllocator* allocator)
{
// The proxies must be destroyed before calling this.
b2Assert(m_proxyCount == 0);
// Free the proxy array.
int32 childCount = m_shape->GetChildCount();
allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy));
m_proxies = NULL;
// Free the child shape.
switch (m_shape->m_type)
{
case b2Shape::e_circle:
{
b2CircleShape* s = (b2CircleShape*)m_shape;
s->~b2CircleShape();
allocator->Free(s, sizeof(b2CircleShape));
}
break;
case b2Shape::e_edge:
{
b2EdgeShape* s = (b2EdgeShape*)m_shape;
s->~b2EdgeShape();
allocator->Free(s, sizeof(b2EdgeShape));
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* s = (b2PolygonShape*)m_shape;
s->~b2PolygonShape();
allocator->Free(s, sizeof(b2PolygonShape));
}
break;
case b2Shape::e_chain:
{
b2ChainShape* s = (b2ChainShape*)m_shape;
s->~b2ChainShape();
allocator->Free(s, sizeof(b2ChainShape));
}
break;
default:
b2Assert(false);
break;
}
m_shape = NULL;
}
void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf)
{
b2Assert(m_proxyCount == 0);
// Create proxies in the broad-phase.
m_proxyCount = m_shape->GetChildCount();
for (int32 i = 0; i < m_proxyCount; ++i)
{
b2FixtureProxy* proxy = m_proxies + i;
m_shape->ComputeAABB(&proxy->aabb, xf, i);
proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy);
proxy->fixture = this;
proxy->childIndex = i;
}
}
void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase)
{
// Destroy proxies in the broad-phase.
for (int32 i = 0; i < m_proxyCount; ++i)
{
b2FixtureProxy* proxy = m_proxies + i;
broadPhase->DestroyProxy(proxy->proxyId);
proxy->proxyId = b2BroadPhase::e_nullProxy;
}
m_proxyCount = 0;
}
void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2)
{
if (m_proxyCount == 0)
{
return;
}
for (int32 i = 0; i < m_proxyCount; ++i)
{
b2FixtureProxy* proxy = m_proxies + i;
// Compute an AABB that covers the swept shape (may miss some rotation effect).
b2AABB aabb1, aabb2;
m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex);
m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex);
proxy->aabb.Combine(aabb1, aabb2);
b2Vec2 displacement = transform2.p - transform1.p;
broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement);
}
}
void b2Fixture::SetFilterData(const b2Filter& filter)
{
m_filter = filter;
Refilter();
}
void b2Fixture::Refilter()
{
if (m_body == NULL)
{
return;
}
// Flag associated contacts for filtering.
b2ContactEdge* edge = m_body->GetContactList();
while (edge)
{
b2Contact* contact = edge->contact;
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
if (fixtureA == this || fixtureB == this)
{
contact->FlagForFiltering();
}
edge = edge->next;
}
b2World* world = m_body->GetWorld();
if (world == NULL)
{
return;
}
// Touch each proxy so that new pairs may be created
b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase;
for (int32 i = 0; i < m_proxyCount; ++i)
{
broadPhase->TouchProxy(m_proxies[i].proxyId);
}
}
void b2Fixture::SetSensor(bool sensor)
{
if (sensor != m_isSensor)
{
m_body->SetAwake(true);
m_isSensor = sensor;
}
}
void b2Fixture::Dump(int32 bodyIndex)
{
b2Log(" b2FixtureDef fd;\n");
b2Log(" fd.friction = %.15lef;\n", m_friction);
b2Log(" fd.restitution = %.15lef;\n", m_restitution);
b2Log(" fd.density = %.15lef;\n", m_density);
b2Log(" fd.isSensor = bool(%d);\n", m_isSensor);
b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits);
b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits);
b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex);
switch (m_shape->m_type)
{
case b2Shape::e_circle:
{
b2CircleShape* s = (b2CircleShape*)m_shape;
b2Log(" b2CircleShape shape;\n");
b2Log(" shape.m_radius = %.15lef;\n", s->m_radius);
b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y);
}
break;
case b2Shape::e_edge:
{
b2EdgeShape* s = (b2EdgeShape*)m_shape;
b2Log(" b2EdgeShape shape;\n");
b2Log(" shape.m_radius = %.15lef;\n", s->m_radius);
b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y);
b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y);
b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y);
b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y);
b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0);
b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3);
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* s = (b2PolygonShape*)m_shape;
b2Log(" b2PolygonShape shape;\n");
b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices);
for (int32 i = 0; i < s->m_count; ++i)
{
b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y);
}
b2Log(" shape.Set(vs, %d);\n", s->m_count);
}
break;
case b2Shape::e_chain:
{
b2ChainShape* s = (b2ChainShape*)m_shape;
b2Log(" b2ChainShape shape;\n");
b2Log(" b2Vec2 vs[%d];\n", s->m_count);
for (int32 i = 0; i < s->m_count; ++i)
{
b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y);
}
b2Log(" shape.CreateChain(vs, %d);\n", s->m_count);
b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y);
b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y);
b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex);
b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex);
}
break;
default:
return;
}
b2Log("\n");
b2Log(" fd.shape = &shape;\n");
b2Log("\n");
b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex);
}
================================================
FILE: app/src/main/cpp/b2FrictionJoint.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2FrictionJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Point-to-point constraint
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Angle constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
}
b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
m_maxForce = def->maxForce;
m_maxTorque = def->maxTorque;
}
void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective mass matrix.
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Mat22 K;
K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
K.ey.x = K.ex.y;
K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
m_linearMass = K.GetInverse();
m_angularMass = iA + iB;
if (m_angularMass > 0.0f)
{
m_angularMass = 1.0f / m_angularMass;
}
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
m_linearImpulse *= data.step.dtRatio;
m_angularImpulse *= data.step.dtRatio;
b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
}
else
{
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
float32 h = data.step.dt;
// Solve angular friction
{
float32 Cdot = wB - wA;
float32 impulse = -m_angularMass * Cdot;
float32 oldImpulse = m_angularImpulse;
float32 maxImpulse = h * m_maxTorque;
m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_angularImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve linear friction
{
b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
b2Vec2 oldImpulse = m_linearImpulse;
m_linearImpulse += impulse;
float32 maxImpulse = h * m_maxForce;
if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
{
m_linearImpulse.Normalize();
m_linearImpulse *= maxImpulse;
}
impulse = m_linearImpulse - oldImpulse;
vA -= mA * impulse;
wA -= iA * b2Cross(m_rA, impulse);
vB += mB * impulse;
wB += iB * b2Cross(m_rB, impulse);
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data)
{
B2_NOT_USED(data);
return true;
}
b2Vec2 b2FrictionJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2FrictionJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * m_linearImpulse;
}
float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_angularImpulse;
}
void b2FrictionJoint::SetMaxForce(float32 force)
{
b2Assert(b2IsValid(force) && force >= 0.0f);
m_maxForce = force;
}
float32 b2FrictionJoint::GetMaxForce() const
{
return m_maxForce;
}
void b2FrictionJoint::SetMaxTorque(float32 torque)
{
b2Assert(b2IsValid(torque) && torque >= 0.0f);
m_maxTorque = torque;
}
float32 b2FrictionJoint::GetMaxTorque() const
{
return m_maxTorque;
}
void b2FrictionJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2FrictionJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2GearJoint.cpp
================================================
/*
* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2GearJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2RevoluteJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PrismaticJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Gear Joint:
// C0 = (coordinate1 + ratio * coordinate2)_initial
// C = (coordinate1 + ratio * coordinate2) - C0 = 0
// J = [J1 ratio * J2]
// K = J * invM * JT
// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T
//
// Revolute:
// coordinate = rotation
// Cdot = angularVelocity
// J = [0 0 1]
// K = J * invM * JT = invI
//
// Prismatic:
// coordinate = dot(p - pg, ug)
// Cdot = dot(v + cross(w, r), ug)
// J = [ug cross(r, ug)]
// K = J * invM * JT = invMass + invI * cross(r, ug)^2
b2GearJoint::b2GearJoint(const b2GearJointDef* def)
: b2Joint(def)
{
m_joint1 = def->joint1;
m_joint2 = def->joint2;
m_typeA = m_joint1->GetType();
m_typeB = m_joint2->GetType();
b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint);
b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint);
float32 coordinateA, coordinateB;
// TODO_ERIN there might be some problem with the joint edges in b2Joint.
m_bodyC = m_joint1->GetBodyA();
m_bodyA = m_joint1->GetBodyB();
// Get geometry of joint1
b2Transform xfA = m_bodyA->m_xf;
float32 aA = m_bodyA->m_sweep.a;
b2Transform xfC = m_bodyC->m_xf;
float32 aC = m_bodyC->m_sweep.a;
if (m_typeA == e_revoluteJoint)
{
b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1;
m_localAnchorC = revolute->m_localAnchorA;
m_localAnchorA = revolute->m_localAnchorB;
m_referenceAngleA = revolute->m_referenceAngle;
m_localAxisC.SetZero();
coordinateA = aA - aC - m_referenceAngleA;
}
else
{
b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1;
m_localAnchorC = prismatic->m_localAnchorA;
m_localAnchorA = prismatic->m_localAnchorB;
m_referenceAngleA = prismatic->m_referenceAngle;
m_localAxisC = prismatic->m_localXAxisA;
b2Vec2 pC = m_localAnchorC;
b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p));
coordinateA = b2Dot(pA - pC, m_localAxisC);
}
m_bodyD = m_joint2->GetBodyA();
m_bodyB = m_joint2->GetBodyB();
// Get geometry of joint2
b2Transform xfB = m_bodyB->m_xf;
float32 aB = m_bodyB->m_sweep.a;
b2Transform xfD = m_bodyD->m_xf;
float32 aD = m_bodyD->m_sweep.a;
if (m_typeB == e_revoluteJoint)
{
b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2;
m_localAnchorD = revolute->m_localAnchorA;
m_localAnchorB = revolute->m_localAnchorB;
m_referenceAngleB = revolute->m_referenceAngle;
m_localAxisD.SetZero();
coordinateB = aB - aD - m_referenceAngleB;
}
else
{
b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2;
m_localAnchorD = prismatic->m_localAnchorA;
m_localAnchorB = prismatic->m_localAnchorB;
m_referenceAngleB = prismatic->m_referenceAngle;
m_localAxisD = prismatic->m_localXAxisA;
b2Vec2 pD = m_localAnchorD;
b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p));
coordinateB = b2Dot(pB - pD, m_localAxisD);
}
m_ratio = def->ratio;
m_constant = coordinateA + m_ratio * coordinateB;
m_impulse = 0.0f;
}
void b2GearJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_indexC = m_bodyC->m_islandIndex;
m_indexD = m_bodyD->m_islandIndex;
m_lcA = m_bodyA->m_sweep.localCenter;
m_lcB = m_bodyB->m_sweep.localCenter;
m_lcC = m_bodyC->m_sweep.localCenter;
m_lcD = m_bodyD->m_sweep.localCenter;
m_mA = m_bodyA->m_invMass;
m_mB = m_bodyB->m_invMass;
m_mC = m_bodyC->m_invMass;
m_mD = m_bodyD->m_invMass;
m_iA = m_bodyA->m_invI;
m_iB = m_bodyB->m_invI;
m_iC = m_bodyC->m_invI;
m_iD = m_bodyD->m_invI;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 aC = data.positions[m_indexC].a;
b2Vec2 vC = data.velocities[m_indexC].v;
float32 wC = data.velocities[m_indexC].w;
float32 aD = data.positions[m_indexD].a;
b2Vec2 vD = data.velocities[m_indexD].v;
float32 wD = data.velocities[m_indexD].w;
b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
m_mass = 0.0f;
if (m_typeA == e_revoluteJoint)
{
m_JvAC.SetZero();
m_JwA = 1.0f;
m_JwC = 1.0f;
m_mass += m_iA + m_iC;
}
else
{
b2Vec2 u = b2Mul(qC, m_localAxisC);
b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
m_JvAC = u;
m_JwC = b2Cross(rC, u);
m_JwA = b2Cross(rA, u);
m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA;
}
if (m_typeB == e_revoluteJoint)
{
m_JvBD.SetZero();
m_JwB = m_ratio;
m_JwD = m_ratio;
m_mass += m_ratio * m_ratio * (m_iB + m_iD);
}
else
{
b2Vec2 u = b2Mul(qD, m_localAxisD);
b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
m_JvBD = m_ratio * u;
m_JwD = m_ratio * b2Cross(rD, u);
m_JwB = m_ratio * b2Cross(rB, u);
m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB;
}
// Compute effective mass.
m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f;
if (data.step.warmStarting)
{
vA += (m_mA * m_impulse) * m_JvAC;
wA += m_iA * m_impulse * m_JwA;
vB += (m_mB * m_impulse) * m_JvBD;
wB += m_iB * m_impulse * m_JwB;
vC -= (m_mC * m_impulse) * m_JvAC;
wC -= m_iC * m_impulse * m_JwC;
vD -= (m_mD * m_impulse) * m_JvBD;
wD -= m_iD * m_impulse * m_JwD;
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
data.velocities[m_indexC].v = vC;
data.velocities[m_indexC].w = wC;
data.velocities[m_indexD].v = vD;
data.velocities[m_indexD].w = wD;
}
void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Vec2 vC = data.velocities[m_indexC].v;
float32 wC = data.velocities[m_indexC].w;
b2Vec2 vD = data.velocities[m_indexD].v;
float32 wD = data.velocities[m_indexD].w;
float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD);
Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD);
float32 impulse = -m_mass * Cdot;
m_impulse += impulse;
vA += (m_mA * impulse) * m_JvAC;
wA += m_iA * impulse * m_JwA;
vB += (m_mB * impulse) * m_JvBD;
wB += m_iB * impulse * m_JwB;
vC -= (m_mC * impulse) * m_JvAC;
wC -= m_iC * impulse * m_JwC;
vD -= (m_mD * impulse) * m_JvBD;
wD -= m_iD * impulse * m_JwD;
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
data.velocities[m_indexC].v = vC;
data.velocities[m_indexC].w = wC;
data.velocities[m_indexD].v = vD;
data.velocities[m_indexD].w = wD;
}
bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 cC = data.positions[m_indexC].c;
float32 aC = data.positions[m_indexC].a;
b2Vec2 cD = data.positions[m_indexD].c;
float32 aD = data.positions[m_indexD].a;
b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
float32 linearError = 0.0f;
float32 coordinateA, coordinateB;
b2Vec2 JvAC, JvBD;
float32 JwA, JwB, JwC, JwD;
float32 mass = 0.0f;
if (m_typeA == e_revoluteJoint)
{
JvAC.SetZero();
JwA = 1.0f;
JwC = 1.0f;
mass += m_iA + m_iC;
coordinateA = aA - aC - m_referenceAngleA;
}
else
{
b2Vec2 u = b2Mul(qC, m_localAxisC);
b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
JvAC = u;
JwC = b2Cross(rC, u);
JwA = b2Cross(rA, u);
mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA;
b2Vec2 pC = m_localAnchorC - m_lcC;
b2Vec2 pA = b2MulT(qC, rA + (cA - cC));
coordinateA = b2Dot(pA - pC, m_localAxisC);
}
if (m_typeB == e_revoluteJoint)
{
JvBD.SetZero();
JwB = m_ratio;
JwD = m_ratio;
mass += m_ratio * m_ratio * (m_iB + m_iD);
coordinateB = aB - aD - m_referenceAngleB;
}
else
{
b2Vec2 u = b2Mul(qD, m_localAxisD);
b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
JvBD = m_ratio * u;
JwD = m_ratio * b2Cross(rD, u);
JwB = m_ratio * b2Cross(rB, u);
mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB;
b2Vec2 pD = m_localAnchorD - m_lcD;
b2Vec2 pB = b2MulT(qD, rB + (cB - cD));
coordinateB = b2Dot(pB - pD, m_localAxisD);
}
float32 C = (coordinateA + m_ratio * coordinateB) - m_constant;
float32 impulse = 0.0f;
if (mass > 0.0f)
{
impulse = -C / mass;
}
cA += m_mA * impulse * JvAC;
aA += m_iA * impulse * JwA;
cB += m_mB * impulse * JvBD;
aB += m_iB * impulse * JwB;
cC -= m_mC * impulse * JvAC;
aC -= m_iC * impulse * JwC;
cD -= m_mD * impulse * JvBD;
aD -= m_iD * impulse * JwD;
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
data.positions[m_indexC].c = cC;
data.positions[m_indexC].a = aC;
data.positions[m_indexD].c = cD;
data.positions[m_indexD].a = aD;
// TODO_ERIN not implemented
return linearError < b2_linearSlop;
}
b2Vec2 b2GearJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2GearJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P = m_impulse * m_JvAC;
return inv_dt * P;
}
float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const
{
float32 L = m_impulse * m_JwA;
return inv_dt * L;
}
void b2GearJoint::SetRatio(float32 ratio)
{
b2Assert(b2IsValid(ratio));
m_ratio = ratio;
}
float32 b2GearJoint::GetRatio() const
{
return m_ratio;
}
void b2GearJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
int32 index1 = m_joint1->m_index;
int32 index2 = m_joint2->m_index;
b2Log(" b2GearJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.joint1 = joints[%d];\n", index1);
b2Log(" jd.joint2 = joints[%d];\n", index2);
b2Log(" jd.ratio = %.15lef;\n", m_ratio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2Island.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Distance.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Island.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ContactSolver.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2Joint.h"
#include "isEngine/ext_lib/Box2D/Common/b2StackAllocator.h"
#include "isEngine/ext_lib/Box2D/Common/b2Timer.h"
/*
Position Correction Notes
=========================
I tried the several algorithms for position correction of the 2D revolute joint.
I looked at these systems:
- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
- suspension bridge with 30 1m long planks of length 1m.
- multi-link chain with 30 1m long links.
Here are the algorithms:
Baumgarte - A fraction of the position error is added to the velocity error. There is no
separate position solver.
Pseudo Velocities - After the velocity solver and position integration,
the position error, Jacobian, and effective mass are recomputed. Then
the velocity constraints are solved with pseudo velocities and a fraction
of the position error is added to the pseudo velocity error. The pseudo
velocities are initialized to zero and there is no warm-starting. After
the position solver, the pseudo velocities are added to the positions.
This is also called the First Order World method or the Position LCP method.
Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
position error is re-computed for each constraint and the positions are updated
after the constraint is solved. The radius vectors (aka Jacobians) are
re-computed too (otherwise the algorithm has horrible instability). The pseudo
velocity states are not needed because they are effectively zero at the beginning
of each iteration. Since we have the current position error, we allow the
iterations to terminate early if the error becomes smaller than b2_linearSlop.
Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
each time a constraint is solved.
Here are the results:
Baumgarte - this is the cheapest algorithm but it has some stability problems,
especially with the bridge. The chain links separate easily close to the root
and they jitter as they struggle to pull together. This is one of the most common
methods in the field. The big drawback is that the position correction artificially
affects the momentum, thus leading to instabilities and false bounce. I used a
bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
factor makes joints and contacts more spongy.
Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
stable. However, joints still separate with large angular velocities. Drag the
simple pendulum in a circle quickly and the joint will separate. The chain separates
easily and does not recover. I used a bias factor of 0.2. A larger value lead to
the bridge collapsing when a heavy cube drops on it.
Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
Velocities, but in other ways it is worse. The bridge and chain are much more
stable, but the simple pendulum goes unstable at high angular velocities.
Full NGS - stable in all tests. The joints display good stiffness. The bridge
still sags, but this is better than infinite forces.
Recommendations
Pseudo Velocities are not really worthwhile because the bridge and chain cannot
recover from joint separation. In other cases the benefit over Baumgarte is small.
Modified NGS is not a robust method for the revolute joint due to the violent
instability seen in the simple pendulum. Perhaps it is viable with other constraint
types, especially scalar constraints where the effective mass is a scalar.
This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
and is very fast. I don't think we can escape Baumgarte, especially in highly
demanding cases where high constraint fidelity is not needed.
Full NGS is robust and easy on the eyes. I recommend this as an option for
higher fidelity simulation and certainly for suspension bridges and long chains.
Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
joint separation can be problematic. The number of NGS iterations can be reduced
for better performance without harming robustness much.
Each joint in a can be handled differently in the position solver. So I recommend
a system where the user can select the algorithm on a per joint basis. I would
probably default to the slower Full NGS and let the user select the faster
Baumgarte method in performance critical scenarios.
*/
/*
Cache Performance
The Box2D solvers are dominated by cache misses. Data structures are designed
to increase the number of cache hits. Much of misses are due to random access
to body data. The constraint structures are iterated over linearly, which leads
to few cache misses.
The bodies are not accessed during iteration. Instead read only data, such as
the mass values are stored with the constraints. The mutable data are the constraint
impulses and the bodies velocities/positions. The impulses are held inside the
constraint structures. The body velocities/positions are held in compact, temporary
arrays to increase the number of cache hits. Linear and angular velocity are
stored in a single array since multiple arrays lead to multiple misses.
*/
/*
2D Rotation
R = [cos(theta) -sin(theta)]
[sin(theta) cos(theta) ]
thetaDot = omega
Let q1 = cos(theta), q2 = sin(theta).
R = [q1 -q2]
[q2 q1]
q1Dot = -thetaDot * q2
q2Dot = thetaDot * q1
q1_new = q1_old - dt * w * q2
q2_new = q2_old + dt * w * q1
then normalize.
This might be faster than computing sin+cos.
However, we can compute sin+cos of the same angle fast.
*/
b2Island::b2Island(
int32 bodyCapacity,
int32 contactCapacity,
int32 jointCapacity,
b2StackAllocator* allocator,
b2ContactListener* listener)
{
m_bodyCapacity = bodyCapacity;
m_contactCapacity = contactCapacity;
m_jointCapacity = jointCapacity;
m_bodyCount = 0;
m_contactCount = 0;
m_jointCount = 0;
m_allocator = allocator;
m_listener = listener;
m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*));
m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*));
m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*));
m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity));
m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position));
}
b2Island::~b2Island()
{
// Warning: the order should reverse the constructor order.
m_allocator->Free(m_positions);
m_allocator->Free(m_velocities);
m_allocator->Free(m_joints);
m_allocator->Free(m_contacts);
m_allocator->Free(m_bodies);
}
void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep)
{
b2Timer timer;
float32 h = step.dt;
// Integrate velocities and apply damping. Initialize the body state.
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
b2Vec2 c = b->m_sweep.c;
float32 a = b->m_sweep.a;
b2Vec2 v = b->m_linearVelocity;
float32 w = b->m_angularVelocity;
// Store positions for continuous collision.
b->m_sweep.c0 = b->m_sweep.c;
b->m_sweep.a0 = b->m_sweep.a;
if (b->m_type == b2_dynamicBody)
{
// Integrate velocities.
v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force);
w += h * b->m_invI * b->m_torque;
// Apply damping.
// ODE: dv/dt + c * v = 0
// Solution: v(t) = v0 * exp(-c * t)
// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
// v2 = exp(-c * dt) * v1
// Pade approximation:
// v2 = v1 * 1 / (1 + c * dt)
v *= 1.0f / (1.0f + h * b->m_linearDamping);
w *= 1.0f / (1.0f + h * b->m_angularDamping);
}
m_positions[i].c = c;
m_positions[i].a = a;
m_velocities[i].v = v;
m_velocities[i].w = w;
}
timer.Reset();
// Solver data
b2SolverData solverData;
solverData.step = step;
solverData.positions = m_positions;
solverData.velocities = m_velocities;
// Initialize velocity constraints.
b2ContactSolverDef contactSolverDef;
contactSolverDef.step = step;
contactSolverDef.contacts = m_contacts;
contactSolverDef.count = m_contactCount;
contactSolverDef.positions = m_positions;
contactSolverDef.velocities = m_velocities;
contactSolverDef.allocator = m_allocator;
b2ContactSolver contactSolver(&contactSolverDef);
contactSolver.InitializeVelocityConstraints();
if (step.warmStarting)
{
contactSolver.WarmStart();
}
for (int32 i = 0; i < m_jointCount; ++i)
{
m_joints[i]->InitVelocityConstraints(solverData);
}
profile->solveInit = timer.GetMilliseconds();
// Solve velocity constraints
timer.Reset();
for (int32 i = 0; i < step.velocityIterations; ++i)
{
for (int32 j = 0; j < m_jointCount; ++j)
{
m_joints[j]->SolveVelocityConstraints(solverData);
}
contactSolver.SolveVelocityConstraints();
}
// Store impulses for warm starting
contactSolver.StoreImpulses();
profile->solveVelocity = timer.GetMilliseconds();
// Integrate positions
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Vec2 c = m_positions[i].c;
float32 a = m_positions[i].a;
b2Vec2 v = m_velocities[i].v;
float32 w = m_velocities[i].w;
// Check for large velocities
b2Vec2 translation = h * v;
if (b2Dot(translation, translation) > b2_maxTranslationSquared)
{
float32 ratio = b2_maxTranslation / translation.Length();
v *= ratio;
}
float32 rotation = h * w;
if (rotation * rotation > b2_maxRotationSquared)
{
float32 ratio = b2_maxRotation / b2Abs(rotation);
w *= ratio;
}
// Integrate
c += h * v;
a += h * w;
m_positions[i].c = c;
m_positions[i].a = a;
m_velocities[i].v = v;
m_velocities[i].w = w;
}
// Solve position constraints
timer.Reset();
bool positionSolved = false;
for (int32 i = 0; i < step.positionIterations; ++i)
{
bool contactsOkay = contactSolver.SolvePositionConstraints();
bool jointsOkay = true;
for (int32 i = 0; i < m_jointCount; ++i)
{
bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData);
jointsOkay = jointsOkay && jointOkay;
}
if (contactsOkay && jointsOkay)
{
// Exit early if the position errors are small.
positionSolved = true;
break;
}
}
// Copy state buffers back to the bodies
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* body = m_bodies[i];
body->m_sweep.c = m_positions[i].c;
body->m_sweep.a = m_positions[i].a;
body->m_linearVelocity = m_velocities[i].v;
body->m_angularVelocity = m_velocities[i].w;
body->SynchronizeTransform();
}
profile->solvePosition = timer.GetMilliseconds();
Report(contactSolver.m_velocityConstraints);
if (allowSleep)
{
float32 minSleepTime = b2_maxFloat;
const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;
const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
if (b->GetType() == b2_staticBody)
{
continue;
}
if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 ||
b->m_angularVelocity * b->m_angularVelocity > angTolSqr ||
b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr)
{
b->m_sleepTime = 0.0f;
minSleepTime = 0.0f;
}
else
{
b->m_sleepTime += h;
minSleepTime = b2Min(minSleepTime, b->m_sleepTime);
}
}
if (minSleepTime >= b2_timeToSleep && positionSolved)
{
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
b->SetAwake(false);
}
}
}
}
void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB)
{
b2Assert(toiIndexA < m_bodyCount);
b2Assert(toiIndexB < m_bodyCount);
// Initialize the body state.
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Body* b = m_bodies[i];
m_positions[i].c = b->m_sweep.c;
m_positions[i].a = b->m_sweep.a;
m_velocities[i].v = b->m_linearVelocity;
m_velocities[i].w = b->m_angularVelocity;
}
b2ContactSolverDef contactSolverDef;
contactSolverDef.contacts = m_contacts;
contactSolverDef.count = m_contactCount;
contactSolverDef.allocator = m_allocator;
contactSolverDef.step = subStep;
contactSolverDef.positions = m_positions;
contactSolverDef.velocities = m_velocities;
b2ContactSolver contactSolver(&contactSolverDef);
// Solve position constraints.
for (int32 i = 0; i < subStep.positionIterations; ++i)
{
bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);
if (contactsOkay)
{
break;
}
}
#if 0
// Is the new position really safe?
for (int32 i = 0; i < m_contactCount; ++i)
{
b2Contact* c = m_contacts[i];
b2Fixture* fA = c->GetFixtureA();
b2Fixture* fB = c->GetFixtureB();
b2Body* bA = fA->GetBody();
b2Body* bB = fB->GetBody();
int32 indexA = c->GetChildIndexA();
int32 indexB = c->GetChildIndexB();
b2DistanceInput input;
input.proxyA.Set(fA->GetShape(), indexA);
input.proxyB.Set(fB->GetShape(), indexB);
input.transformA = bA->GetTransform();
input.transformB = bB->GetTransform();
input.useRadii = false;
b2DistanceOutput output;
b2SimplexCache cache;
cache.count = 0;
b2Distance(&output, &cache, &input);
if (output.distance == 0 || cache.count == 3)
{
cache.count += 0;
}
}
#endif
// Leap of faith to new safe state.
m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c;
m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a;
m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c;
m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a;
// No warm starting is needed for TOI events because warm
// starting impulses were applied in the discrete solver.
contactSolver.InitializeVelocityConstraints();
// Solve velocity constraints.
for (int32 i = 0; i < subStep.velocityIterations; ++i)
{
contactSolver.SolveVelocityConstraints();
}
// Don't store the TOI contact forces for warm starting
// because they can be quite large.
float32 h = subStep.dt;
// Integrate positions
for (int32 i = 0; i < m_bodyCount; ++i)
{
b2Vec2 c = m_positions[i].c;
float32 a = m_positions[i].a;
b2Vec2 v = m_velocities[i].v;
float32 w = m_velocities[i].w;
// Check for large velocities
b2Vec2 translation = h * v;
if (b2Dot(translation, translation) > b2_maxTranslationSquared)
{
float32 ratio = b2_maxTranslation / translation.Length();
v *= ratio;
}
float32 rotation = h * w;
if (rotation * rotation > b2_maxRotationSquared)
{
float32 ratio = b2_maxRotation / b2Abs(rotation);
w *= ratio;
}
// Integrate
c += h * v;
a += h * w;
m_positions[i].c = c;
m_positions[i].a = a;
m_velocities[i].v = v;
m_velocities[i].w = w;
// Sync bodies
b2Body* body = m_bodies[i];
body->m_sweep.c = c;
body->m_sweep.a = a;
body->m_linearVelocity = v;
body->m_angularVelocity = w;
body->SynchronizeTransform();
}
Report(contactSolver.m_velocityConstraints);
}
void b2Island::Report(const b2ContactVelocityConstraint* constraints)
{
if (m_listener == NULL)
{
return;
}
for (int32 i = 0; i < m_contactCount; ++i)
{
b2Contact* c = m_contacts[i];
const b2ContactVelocityConstraint* vc = constraints + i;
b2ContactImpulse impulse;
impulse.count = vc->pointCount;
for (int32 j = 0; j < vc->pointCount; ++j)
{
impulse.normalImpulses[j] = vc->points[j].normalImpulse;
impulse.tangentImpulses[j] = vc->points[j].tangentImpulse;
}
m_listener->PostSolve(c, &impulse);
}
}
================================================
FILE: app/src/main/cpp/b2Joint.cpp
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2Joint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2DistanceJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2WheelJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2MouseJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2RevoluteJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PrismaticJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PulleyJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2GearJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2WeldJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2FrictionJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2RopeJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2MotorJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include
b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
{
b2Joint* joint = NULL;
switch (def->type)
{
case e_distanceJoint:
{
void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
joint = new (mem) b2DistanceJoint(static_cast(def));
}
break;
case e_mouseJoint:
{
void* mem = allocator->Allocate(sizeof(b2MouseJoint));
joint = new (mem) b2MouseJoint(static_cast(def));
}
break;
case e_prismaticJoint:
{
void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
joint = new (mem) b2PrismaticJoint(static_cast(def));
}
break;
case e_revoluteJoint:
{
void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
joint = new (mem) b2RevoluteJoint(static_cast(def));
}
break;
case e_pulleyJoint:
{
void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
joint = new (mem) b2PulleyJoint(static_cast(def));
}
break;
case e_gearJoint:
{
void* mem = allocator->Allocate(sizeof(b2GearJoint));
joint = new (mem) b2GearJoint(static_cast(def));
}
break;
case e_wheelJoint:
{
void* mem = allocator->Allocate(sizeof(b2WheelJoint));
joint = new (mem) b2WheelJoint(static_cast(def));
}
break;
case e_weldJoint:
{
void* mem = allocator->Allocate(sizeof(b2WeldJoint));
joint = new (mem) b2WeldJoint(static_cast(def));
}
break;
case e_frictionJoint:
{
void* mem = allocator->Allocate(sizeof(b2FrictionJoint));
joint = new (mem) b2FrictionJoint(static_cast(def));
}
break;
case e_ropeJoint:
{
void* mem = allocator->Allocate(sizeof(b2RopeJoint));
joint = new (mem) b2RopeJoint(static_cast(def));
}
break;
case e_motorJoint:
{
void* mem = allocator->Allocate(sizeof(b2MotorJoint));
joint = new (mem) b2MotorJoint(static_cast(def));
}
break;
default:
b2Assert(false);
break;
}
return joint;
}
void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)
{
joint->~b2Joint();
switch (joint->m_type)
{
case e_distanceJoint:
allocator->Free(joint, sizeof(b2DistanceJoint));
break;
case e_mouseJoint:
allocator->Free(joint, sizeof(b2MouseJoint));
break;
case e_prismaticJoint:
allocator->Free(joint, sizeof(b2PrismaticJoint));
break;
case e_revoluteJoint:
allocator->Free(joint, sizeof(b2RevoluteJoint));
break;
case e_pulleyJoint:
allocator->Free(joint, sizeof(b2PulleyJoint));
break;
case e_gearJoint:
allocator->Free(joint, sizeof(b2GearJoint));
break;
case e_wheelJoint:
allocator->Free(joint, sizeof(b2WheelJoint));
break;
case e_weldJoint:
allocator->Free(joint, sizeof(b2WeldJoint));
break;
case e_frictionJoint:
allocator->Free(joint, sizeof(b2FrictionJoint));
break;
case e_ropeJoint:
allocator->Free(joint, sizeof(b2RopeJoint));
break;
case e_motorJoint:
allocator->Free(joint, sizeof(b2MotorJoint));
break;
default:
b2Assert(false);
break;
}
}
b2Joint::b2Joint(const b2JointDef* def)
{
b2Assert(def->bodyA != def->bodyB);
m_type = def->type;
m_prev = NULL;
m_next = NULL;
m_bodyA = def->bodyA;
m_bodyB = def->bodyB;
m_index = 0;
m_collideConnected = def->collideConnected;
m_islandFlag = false;
m_userData = def->userData;
m_edgeA.joint = NULL;
m_edgeA.other = NULL;
m_edgeA.prev = NULL;
m_edgeA.next = NULL;
m_edgeB.joint = NULL;
m_edgeB.other = NULL;
m_edgeB.prev = NULL;
m_edgeB.next = NULL;
}
bool b2Joint::IsActive() const
{
return m_bodyA->IsActive() && m_bodyB->IsActive();
}
================================================
FILE: app/src/main/cpp/b2Math.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2Math.h"
const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
{
float32 det = b2Dot(ex, b2Cross(ey, ez));
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec3 x;
x.x = det * b2Dot(b, b2Cross(ey, ez));
x.y = det * b2Dot(ex, b2Cross(b, ez));
x.z = det * b2Dot(ex, b2Cross(ey, b));
return x;
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
{
float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
float32 det = a11 * a22 - a12 * a21;
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec2 x;
x.x = det * (a22 * b.x - a12 * b.y);
x.y = det * (a11 * b.y - a21 * b.x);
return x;
}
///
void b2Mat33::GetInverse22(b2Mat33* M) const
{
float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
float32 det = a * d - b * c;
if (det != 0.0f)
{
det = 1.0f / det;
}
M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f;
M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f;
M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f;
}
/// Returns the zero matrix if singular.
void b2Mat33::GetSymInverse33(b2Mat33* M) const
{
float32 det = b2Dot(ex, b2Cross(ey, ez));
if (det != 0.0f)
{
det = 1.0f / det;
}
float32 a11 = ex.x, a12 = ey.x, a13 = ez.x;
float32 a22 = ey.y, a23 = ez.y;
float32 a33 = ez.z;
M->ex.x = det * (a22 * a33 - a23 * a23);
M->ex.y = det * (a13 * a23 - a12 * a33);
M->ex.z = det * (a12 * a23 - a13 * a22);
M->ey.x = M->ex.y;
M->ey.y = det * (a11 * a33 - a13 * a13);
M->ey.z = det * (a13 * a12 - a11 * a23);
M->ez.x = M->ex.z;
M->ez.y = M->ey.z;
M->ez.z = det * (a11 * a22 - a12 * a12);
}
================================================
FILE: app/src/main/cpp/b2MotorJoint.cpp
================================================
/*
* Copyright (c) 2006-2012 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2MotorJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Point-to-point constraint
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Angle constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2MotorJointDef::Initialize(b2Body* bA, b2Body* bB)
{
bodyA = bA;
bodyB = bB;
b2Vec2 xB = bodyB->GetPosition();
linearOffset = bodyA->GetLocalPoint(xB);
float32 angleA = bodyA->GetAngle();
float32 angleB = bodyB->GetAngle();
angularOffset = angleB - angleA;
}
b2MotorJoint::b2MotorJoint(const b2MotorJointDef* def)
: b2Joint(def)
{
m_linearOffset = def->linearOffset;
m_angularOffset = def->angularOffset;
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
m_maxForce = def->maxForce;
m_maxTorque = def->maxTorque;
m_correctionFactor = def->correctionFactor;
}
void b2MotorJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective mass matrix.
m_rA = b2Mul(qA, -m_localCenterA);
m_rB = b2Mul(qB, -m_localCenterB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Mat22 K;
K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
K.ey.x = K.ex.y;
K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
m_linearMass = K.GetInverse();
m_angularMass = iA + iB;
if (m_angularMass > 0.0f)
{
m_angularMass = 1.0f / m_angularMass;
}
m_linearError = cB + m_rB - cA - m_rA - b2Mul(qA, m_linearOffset);
m_angularError = aB - aA - m_angularOffset;
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
m_linearImpulse *= data.step.dtRatio;
m_angularImpulse *= data.step.dtRatio;
b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
}
else
{
m_linearImpulse.SetZero();
m_angularImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2MotorJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
float32 h = data.step.dt;
float32 inv_h = data.step.inv_dt;
// Solve angular friction
{
float32 Cdot = wB - wA + inv_h * m_correctionFactor * m_angularError;
float32 impulse = -m_angularMass * Cdot;
float32 oldImpulse = m_angularImpulse;
float32 maxImpulse = h * m_maxTorque;
m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_angularImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve linear friction
{
b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA) + inv_h * m_correctionFactor * m_linearError;
b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
b2Vec2 oldImpulse = m_linearImpulse;
m_linearImpulse += impulse;
float32 maxImpulse = h * m_maxForce;
if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
{
m_linearImpulse.Normalize();
m_linearImpulse *= maxImpulse;
}
impulse = m_linearImpulse - oldImpulse;
vA -= mA * impulse;
wA -= iA * b2Cross(m_rA, impulse);
vB += mB * impulse;
wB += iB * b2Cross(m_rB, impulse);
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2MotorJoint::SolvePositionConstraints(const b2SolverData& data)
{
B2_NOT_USED(data);
return true;
}
b2Vec2 b2MotorJoint::GetAnchorA() const
{
return m_bodyA->GetPosition();
}
b2Vec2 b2MotorJoint::GetAnchorB() const
{
return m_bodyB->GetPosition();
}
b2Vec2 b2MotorJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * m_linearImpulse;
}
float32 b2MotorJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_angularImpulse;
}
void b2MotorJoint::SetMaxForce(float32 force)
{
b2Assert(b2IsValid(force) && force >= 0.0f);
m_maxForce = force;
}
float32 b2MotorJoint::GetMaxForce() const
{
return m_maxForce;
}
void b2MotorJoint::SetMaxTorque(float32 torque)
{
b2Assert(b2IsValid(torque) && torque >= 0.0f);
m_maxTorque = torque;
}
float32 b2MotorJoint::GetMaxTorque() const
{
return m_maxTorque;
}
void b2MotorJoint::SetCorrectionFactor(float32 factor)
{
b2Assert(b2IsValid(factor) && 0.0f <= factor && factor <= 1.0f);
m_correctionFactor = factor;
}
float32 b2MotorJoint::GetCorrectionFactor() const
{
return m_correctionFactor;
}
void b2MotorJoint::SetLinearOffset(const b2Vec2& linearOffset)
{
if (linearOffset.x != m_linearOffset.x || linearOffset.y != m_linearOffset.y)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_linearOffset = linearOffset;
}
}
const b2Vec2& b2MotorJoint::GetLinearOffset() const
{
return m_linearOffset;
}
void b2MotorJoint::SetAngularOffset(float32 angularOffset)
{
if (angularOffset != m_angularOffset)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_angularOffset = angularOffset;
}
}
float32 b2MotorJoint::GetAngularOffset() const
{
return m_angularOffset;
}
void b2MotorJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2MotorJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.linearOffset.Set(%.15lef, %.15lef);\n", m_linearOffset.x, m_linearOffset.y);
b2Log(" jd.angularOffset = %.15lef;\n", m_angularOffset);
b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
b2Log(" jd.correctionFactor = %.15lef;\n", m_correctionFactor);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2MouseJoint.cpp
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2MouseJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// p = attached point, m = mouse point
// C = p - m
// Cdot = v
// = v + cross(w, r)
// J = [I r_skew]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)
: b2Joint(def)
{
b2Assert(def->target.IsValid());
b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);
b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);
b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);
m_targetA = def->target;
m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA);
m_maxForce = def->maxForce;
m_impulse.SetZero();
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_beta = 0.0f;
m_gamma = 0.0f;
}
void b2MouseJoint::SetTarget(const b2Vec2& target)
{
if (m_bodyB->IsAwake() == false)
{
m_bodyB->SetAwake(true);
}
m_targetA = target;
}
const b2Vec2& b2MouseJoint::GetTarget() const
{
return m_targetA;
}
void b2MouseJoint::SetMaxForce(float32 force)
{
m_maxForce = force;
}
float32 b2MouseJoint::GetMaxForce() const
{
return m_maxForce;
}
void b2MouseJoint::SetFrequency(float32 hz)
{
m_frequencyHz = hz;
}
float32 b2MouseJoint::GetFrequency() const
{
return m_frequencyHz;
}
void b2MouseJoint::SetDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
float32 b2MouseJoint::GetDampingRatio() const
{
return m_dampingRatio;
}
void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexB = m_bodyB->m_islandIndex;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassB = m_bodyB->m_invMass;
m_invIB = m_bodyB->m_invI;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qB(aB);
float32 mass = m_bodyB->GetMass();
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * mass * m_dampingRatio * omega;
// Spring stiffness
float32 k = mass * (omega * omega);
// magic formulas
// gamma has units of inverse mass.
// beta has units of inverse time.
float32 h = data.step.dt;
b2Assert(d + h * k > b2_epsilon);
m_gamma = h * (d + h * k);
if (m_gamma != 0.0f)
{
m_gamma = 1.0f / m_gamma;
}
m_beta = h * k * m_gamma;
// Compute the effective mass matrix.
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
// = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
// [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
b2Mat22 K;
K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma;
K.ex.y = -m_invIB * m_rB.x * m_rB.y;
K.ey.x = K.ex.y;
K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma;
m_mass = K.GetInverse();
m_C = cB + m_rB - m_targetA;
m_C *= m_beta;
// Cheat with some damping
wB *= 0.98f;
if (data.step.warmStarting)
{
m_impulse *= data.step.dtRatio;
vB += m_invMassB * m_impulse;
wB += m_invIB * b2Cross(m_rB, m_impulse);
}
else
{
m_impulse.SetZero();
}
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Cdot = v + cross(w, r)
b2Vec2 Cdot = vB + b2Cross(wB, m_rB);
b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));
b2Vec2 oldImpulse = m_impulse;
m_impulse += impulse;
float32 maxImpulse = data.step.dt * m_maxForce;
if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
{
m_impulse *= maxImpulse / m_impulse.Length();
}
impulse = m_impulse - oldImpulse;
vB += m_invMassB * impulse;
wB += m_invIB * b2Cross(m_rB, impulse);
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data)
{
B2_NOT_USED(data);
return true;
}
b2Vec2 b2MouseJoint::GetAnchorA() const
{
return m_targetA;
}
b2Vec2 b2MouseJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * m_impulse;
}
float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * 0.0f;
}
void b2MouseJoint::ShiftOrigin(const b2Vec2& newOrigin)
{
m_targetA -= newOrigin;
}
================================================
FILE: app/src/main/cpp/b2PolygonAndCircleContact.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include
b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact));
return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB);
}
void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact();
allocator->Free(contact, sizeof(b2PolygonAndCircleContact));
}
b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygonAndCircle( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2PolygonContact.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonContact.h"
#include "isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h"
#include "isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2WorldCallbacks.h"
#include
b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonContact));
return new (mem) b2PolygonContact(fixtureA, fixtureB);
}
void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonContact*)contact)->~b2PolygonContact();
allocator->Free(contact, sizeof(b2PolygonContact));
}
b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygons( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
================================================
FILE: app/src/main/cpp/b2PolygonShape.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
#include
b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2PolygonShape));
b2PolygonShape* clone = new (mem) b2PolygonShape;
*clone = *this;
return clone;
}
void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
{
m_count = 4;
m_vertices[0].Set(-hx, -hy);
m_vertices[1].Set( hx, -hy);
m_vertices[2].Set( hx, hy);
m_vertices[3].Set(-hx, hy);
m_normals[0].Set(0.0f, -1.0f);
m_normals[1].Set(1.0f, 0.0f);
m_normals[2].Set(0.0f, 1.0f);
m_normals[3].Set(-1.0f, 0.0f);
m_centroid.SetZero();
}
void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
{
m_count = 4;
m_vertices[0].Set(-hx, -hy);
m_vertices[1].Set( hx, -hy);
m_vertices[2].Set( hx, hy);
m_vertices[3].Set(-hx, hy);
m_normals[0].Set(0.0f, -1.0f);
m_normals[1].Set(1.0f, 0.0f);
m_normals[2].Set(0.0f, 1.0f);
m_normals[3].Set(-1.0f, 0.0f);
m_centroid = center;
b2Transform xf;
xf.p = center;
xf.q.Set(angle);
// Transform vertices and normals.
for (int32 i = 0; i < m_count; ++i)
{
m_vertices[i] = b2Mul(xf, m_vertices[i]);
m_normals[i] = b2Mul(xf.q, m_normals[i]);
}
}
int32 b2PolygonShape::GetChildCount() const
{
return 1;
}
static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
{
b2Assert(count >= 3);
b2Vec2 c; c.Set(0.0f, 0.0f);
float32 area = 0.0f;
// pRef is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
b2Vec2 pRef(0.0f, 0.0f);
#if 0
// This code would put the reference point inside the polygon.
for (int32 i = 0; i < count; ++i)
{
pRef += vs[i];
}
pRef *= 1.0f / count;
#endif
const float32 inv3 = 1.0f / 3.0f;
for (int32 i = 0; i < count; ++i)
{
// Triangle vertices.
b2Vec2 p1 = pRef;
b2Vec2 p2 = vs[i];
b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
b2Vec2 e1 = p2 - p1;
b2Vec2 e2 = p3 - p1;
float32 D = b2Cross(e1, e2);
float32 triangleArea = 0.5f * D;
area += triangleArea;
// Area weighted centroid
c += triangleArea * inv3 * (p1 + p2 + p3);
}
// Centroid
b2Assert(area > b2_epsilon);
c *= 1.0f / area;
return c;
}
void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
{
b2Assert(3 <= count && count <= b2_maxPolygonVertices);
if (count < 3)
{
SetAsBox(1.0f, 1.0f);
return;
}
int32 n = b2Min(count, b2_maxPolygonVertices);
// Perform welding and copy vertices into local buffer.
b2Vec2 ps[b2_maxPolygonVertices];
int32 tempCount = 0;
for (int32 i = 0; i < n; ++i)
{
b2Vec2 v = vertices[i];
bool unique = true;
for (int32 j = 0; j < tempCount; ++j)
{
if (b2DistanceSquared(v, ps[j]) < 0.5f * b2_linearSlop)
{
unique = false;
break;
}
}
if (unique)
{
ps[tempCount++] = v;
}
}
n = tempCount;
if (n < 3)
{
// Polygon is degenerate.
b2Assert(false);
SetAsBox(1.0f, 1.0f);
return;
}
// Create the convex hull using the Gift wrapping algorithm
// http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
// Find the right most point on the hull
int32 i0 = 0;
float32 x0 = ps[0].x;
for (int32 i = 1; i < n; ++i)
{
float32 x = ps[i].x;
if (x > x0 || (x == x0 && ps[i].y < ps[i0].y))
{
i0 = i;
x0 = x;
}
}
int32 hull[b2_maxPolygonVertices];
int32 m = 0;
int32 ih = i0;
for (;;)
{
hull[m] = ih;
int32 ie = 0;
for (int32 j = 1; j < n; ++j)
{
if (ie == ih)
{
ie = j;
continue;
}
b2Vec2 r = ps[ie] - ps[hull[m]];
b2Vec2 v = ps[j] - ps[hull[m]];
float32 c = b2Cross(r, v);
if (c < 0.0f)
{
ie = j;
}
// Collinearity check
if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
{
ie = j;
}
}
++m;
ih = ie;
if (ie == i0)
{
break;
}
}
m_count = m;
// Copy vertices.
for (int32 i = 0; i < m; ++i)
{
m_vertices[i] = ps[hull[i]];
}
// Compute normals. Ensure the edges have non-zero length.
for (int32 i = 0; i < m; ++i)
{
int32 i1 = i;
int32 i2 = i + 1 < m ? i + 1 : 0;
b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);
m_normals[i] = b2Cross(edge, 1.0f);
m_normals[i].Normalize();
}
// Compute the polygon centroid.
m_centroid = ComputeCentroid(m_vertices, m);
}
bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
{
b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
for (int32 i = 0; i < m_count; ++i)
{
float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
if (dot > 0.0f)
{
return false;
}
}
return true;
}
bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& xf, int32 childIndex) const
{
B2_NOT_USED(childIndex);
// Put the ray into the polygon's frame of reference.
b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
b2Vec2 d = p2 - p1;
float32 lower = 0.0f, upper = input.maxFraction;
int32 index = -1;
for (int32 i = 0; i < m_count; ++i)
{
// p = p1 + a * d
// dot(normal, p - v) = 0
// dot(normal, p1 - v) + a * dot(normal, d) = 0
float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
float32 denominator = b2Dot(m_normals[i], d);
if (denominator == 0.0f)
{
if (numerator < 0.0f)
{
return false;
}
}
else
{
// Note: we want this predicate without division:
// lower < numerator / denominator, where denominator < 0
// Since denominator < 0, we have to flip the inequality:
// lower < numerator / denominator <==> denominator * lower > numerator.
if (denominator < 0.0f && numerator < lower * denominator)
{
// Increase lower.
// The segment enters this half-space.
lower = numerator / denominator;
index = i;
}
else if (denominator > 0.0f && numerator < upper * denominator)
{
// Decrease upper.
// The segment exits this half-space.
upper = numerator / denominator;
}
}
// The use of epsilon here causes the assert on lower to trip
// in some cases. Apparently the use of epsilon was to make edge
// shapes work, but now those are handled separately.
//if (upper < lower - b2_epsilon)
if (upper < lower)
{
return false;
}
}
b2Assert(0.0f <= lower && lower <= input.maxFraction);
if (index >= 0)
{
output->fraction = lower;
output->normal = b2Mul(xf.q, m_normals[index]);
return true;
}
return false;
}
void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
{
B2_NOT_USED(childIndex);
b2Vec2 lower = b2Mul(xf, m_vertices[0]);
b2Vec2 upper = lower;
for (int32 i = 1; i < m_count; ++i)
{
b2Vec2 v = b2Mul(xf, m_vertices[i]);
lower = b2Min(lower, v);
upper = b2Max(upper, v);
}
b2Vec2 r(m_radius, m_radius);
aabb->lowerBound = lower - r;
aabb->upperBound = upper + r;
}
void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const
{
// Polygon mass, centroid, and inertia.
// Let rho be the polygon density in mass per unit area.
// Then:
// mass = rho * int(dA)
// centroid.x = (1/mass) * rho * int(x * dA)
// centroid.y = (1/mass) * rho * int(y * dA)
// I = rho * int((x*x + y*y) * dA)
//
// We can compute these integrals by summing all the integrals
// for each triangle of the polygon. To evaluate the integral
// for a single triangle, we make a change of variables to
// the (u,v) coordinates of the triangle:
// x = x0 + e1x * u + e2x * v
// y = y0 + e1y * u + e2y * v
// where 0 <= u && 0 <= v && u + v <= 1.
//
// We integrate u from [0,1-v] and then v from [0,1].
// We also need to use the Jacobian of the transformation:
// D = cross(e1, e2)
//
// Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
//
// The rest of the derivation is handled by computer algebra.
b2Assert(m_count >= 3);
b2Vec2 center; center.Set(0.0f, 0.0f);
float32 area = 0.0f;
float32 I = 0.0f;
// s is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
b2Vec2 s(0.0f, 0.0f);
// This code would put the reference point inside the polygon.
for (int32 i = 0; i < m_count; ++i)
{
s += m_vertices[i];
}
s *= 1.0f / m_count;
const float32 k_inv3 = 1.0f / 3.0f;
for (int32 i = 0; i < m_count; ++i)
{
// Triangle vertices.
b2Vec2 e1 = m_vertices[i] - s;
b2Vec2 e2 = i + 1 < m_count ? m_vertices[i+1] - s : m_vertices[0] - s;
float32 D = b2Cross(e1, e2);
float32 triangleArea = 0.5f * D;
area += triangleArea;
// Area weighted centroid
center += triangleArea * k_inv3 * (e1 + e2);
float32 ex1 = e1.x, ey1 = e1.y;
float32 ex2 = e2.x, ey2 = e2.y;
float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2;
float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2;
I += (0.25f * k_inv3 * D) * (intx2 + inty2);
}
// Total mass
massData->mass = density * area;
// Center of mass
b2Assert(area > b2_epsilon);
center *= 1.0f / area;
massData->center = center + s;
// Inertia tensor relative to the local origin (point s).
massData->I = density * I;
// Shift to center of mass then to original body origin.
massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center));
}
bool b2PolygonShape::Validate() const
{
for (int32 i = 0; i < m_count; ++i)
{
int32 i1 = i;
int32 i2 = i < m_count - 1 ? i1 + 1 : 0;
b2Vec2 p = m_vertices[i1];
b2Vec2 e = m_vertices[i2] - p;
for (int32 j = 0; j < m_count; ++j)
{
if (j == i1 || j == i2)
{
continue;
}
b2Vec2 v = m_vertices[j] - p;
float32 c = b2Cross(e, v);
if (c < 0.0f)
{
return false;
}
}
}
return true;
}
================================================
FILE: app/src/main/cpp/b2PrismaticJoint.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PrismaticJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Linear constraint (point-to-line)
// d = p2 - p1 = x2 + r2 - x1 - r1
// C = dot(perp, d)
// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
//
// Angular constraint
// C = a2 - a1 + a_initial
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
//
// K = J * invM * JT
//
// J = [-a -s1 a s2]
// [0 -1 0 1]
// a = perp
// s1 = cross(d + r1, a) = cross(p2 - x1, a)
// s2 = cross(r2, a) = cross(p2 - x2, a)
// Motor/Limit linear constraint
// C = dot(ax1, d)
// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
// Block Solver
// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
// when the mass has poor distribution (leading to large torques about the joint anchor points).
//
// The Jacobian has 3 rows:
// J = [-uT -s1 uT s2] // linear
// [0 -1 0 1] // angular
// [-vT -a1 vT a2] // limit
//
// u = perp
// v = axis
// s1 = cross(d + r1, u), s2 = cross(r2, u)
// a1 = cross(d + r1, v), a2 = cross(r2, v)
// M * (v2 - v1) = JT * df
// J * v2 = bias
//
// v2 = v1 + invM * JT * df
// J * (v1 + invM * JT * df) = bias
// K * df = bias - J * v1 = -Cdot
// K = J * invM * JT
// Cdot = J * v1 - bias
//
// Now solve for f2.
// df = f2 - f1
// K * (f2 - f1) = -Cdot
// f2 = invK * (-Cdot) + f1
//
// Clamp accumulated limit impulse.
// lower: f2(3) = max(f2(3), 0)
// upper: f2(3) = min(f2(3), 0)
//
// Solve for correct f2(1:2)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
//
// Now compute impulse to be applied:
// df = f2 - f1
void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxisA = bodyA->GetLocalVector(axis);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_localXAxisA = def->localAxisA;
m_localXAxisA.Normalize();
m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
m_lowerTranslation = def->lowerTranslation;
m_upperTranslation = def->upperTranslation;
m_maxMotorForce = def->maxMotorForce;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
m_axis.SetZero();
m_perp.SetZero();
}
void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective masses.
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = (cB - cA) + rB - rA;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Compute motor Jacobian and effective mass.
{
m_axis = b2Mul(qA, m_localXAxisA);
m_a1 = b2Cross(d + rA, m_axis);
m_a2 = b2Cross(rB, m_axis);
m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
}
// Prismatic constraint.
{
m_perp = b2Mul(qA, m_localYAxisA);
m_s1 = b2Cross(d + rA, m_perp);
m_s2 = b2Cross(rB, m_perp);
float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2;
float32 k12 = iA * m_s1 + iB * m_s2;
float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
// For bodies with fixed rotation.
k22 = 1.0f;
}
float32 k23 = iA * m_a1 + iB * m_a2;
float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
m_K.ex.Set(k11, k12, k13);
m_K.ey.Set(k12, k22, k23);
m_K.ez.Set(k13, k23, k33);
}
// Compute motor and limit terms.
if (m_enableLimit)
{
float32 jointTranslation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
m_limitState = e_equalLimits;
}
else if (jointTranslation <= m_lowerTranslation)
{
if (m_limitState != e_atLowerLimit)
{
m_limitState = e_atLowerLimit;
m_impulse.z = 0.0f;
}
}
else if (jointTranslation >= m_upperTranslation)
{
if (m_limitState != e_atUpperLimit)
{
m_limitState = e_atUpperLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
if (m_enableMotor == false)
{
m_motorImpulse = 0.0f;
}
if (data.step.warmStarting)
{
// Account for variable time step.
m_impulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Solve linear motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits)
{
float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorForce;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
b2Vec2 P = impulse * m_axis;
float32 LA = impulse * m_a1;
float32 LB = impulse * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
b2Vec2 Cdot1;
Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
Cdot1.y = wB - wA;
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
// Solve prismatic and limit constraint in block form.
float32 Cdot2;
Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 f1 = m_impulse;
b2Vec3 df = m_K.Solve33(-Cdot);
m_impulse += df;
if (m_limitState == e_atLowerLimit)
{
m_impulse.z = b2Max(m_impulse.z, 0.0f);
}
else if (m_limitState == e_atUpperLimit)
{
m_impulse.z = b2Min(m_impulse.z, 0.0f);
}
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y);
b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
m_impulse.x = f2r.x;
m_impulse.y = f2r.y;
df = m_impulse - f1;
b2Vec2 P = df.x * m_perp + df.z * m_axis;
float32 LA = df.x * m_s1 + df.y + df.z * m_a1;
float32 LB = df.x * m_s2 + df.y + df.z * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
else
{
// Limit is inactive, just solve the prismatic constraint in block form.
b2Vec2 df = m_K.Solve22(-Cdot1);
m_impulse.x += df.x;
m_impulse.y += df.y;
b2Vec2 P = df.x * m_perp;
float32 LA = df.x * m_s1 + df.y;
float32 LB = df.x * m_s2 + df.y;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Compute fresh Jacobians
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = cB + rB - cA - rA;
b2Vec2 axis = b2Mul(qA, m_localXAxisA);
float32 a1 = b2Cross(d + rA, axis);
float32 a2 = b2Cross(rB, axis);
b2Vec2 perp = b2Mul(qA, m_localYAxisA);
float32 s1 = b2Cross(d + rA, perp);
float32 s2 = b2Cross(rB, perp);
b2Vec3 impulse;
b2Vec2 C1;
C1.x = b2Dot(perp, d);
C1.y = aB - aA - m_referenceAngle;
float32 linearError = b2Abs(C1.x);
float32 angularError = b2Abs(C1.y);
bool active = false;
float32 C2 = 0.0f;
if (m_enableLimit)
{
float32 translation = b2Dot(axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
// Prevent large angular corrections
C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
linearError = b2Max(linearError, b2Abs(translation));
active = true;
}
else if (translation <= m_lowerTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
linearError = b2Max(linearError, m_lowerTranslation - translation);
active = true;
}
else if (translation >= m_upperTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
linearError = b2Max(linearError, translation - m_upperTranslation);
active = true;
}
}
if (active)
{
float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
float32 k12 = iA * s1 + iB * s2;
float32 k13 = iA * s1 * a1 + iB * s2 * a2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
// For fixed rotation
k22 = 1.0f;
}
float32 k23 = iA * a1 + iB * a2;
float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
b2Mat33 K;
K.ex.Set(k11, k12, k13);
K.ey.Set(k12, k22, k23);
K.ez.Set(k13, k23, k33);
b2Vec3 C;
C.x = C1.x;
C.y = C1.y;
C.z = C2;
impulse = K.Solve33(-C);
}
else
{
float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
float32 k12 = iA * s1 + iB * s2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
k22 = 1.0f;
}
b2Mat22 K;
K.ex.Set(k11, k12);
K.ey.Set(k12, k22);
b2Vec2 impulse1 = K.Solve(-C1);
impulse.x = impulse1.x;
impulse.y = impulse1.y;
impulse.z = 0.0f;
}
b2Vec2 P = impulse.x * perp + impulse.z * axis;
float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1;
float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2;
cA -= mA * P;
aA -= iA * LA;
cB += mB * P;
aB += iB * LB;
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2PrismaticJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2PrismaticJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
}
float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.y;
}
float32 b2PrismaticJoint::GetJointTranslation() const
{
b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
b2Vec2 d = pB - pA;
b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2PrismaticJoint::GetJointSpeed() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
b2Vec2 p1 = bA->m_sweep.c + rA;
b2Vec2 p2 = bB->m_sweep.c + rB;
b2Vec2 d = p2 - p1;
b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
b2Vec2 vA = bA->m_linearVelocity;
b2Vec2 vB = bB->m_linearVelocity;
float32 wA = bA->m_angularVelocity;
float32 wB = bB->m_angularVelocity;
float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
return speed;
}
bool b2PrismaticJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2PrismaticJoint::EnableLimit(bool flag)
{
if (flag != m_enableLimit)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
m_impulse.z = 0.0f;
}
}
float32 b2PrismaticJoint::GetLowerLimit() const
{
return m_lowerTranslation;
}
float32 b2PrismaticJoint::GetUpperLimit() const
{
return m_upperTranslation;
}
void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
if (lower != m_lowerTranslation || upper != m_upperTranslation)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_lowerTranslation = lower;
m_upperTranslation = upper;
m_impulse.z = 0.0f;
}
}
bool b2PrismaticJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2PrismaticJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2PrismaticJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2PrismaticJoint::SetMaxMotorForce(float32 force)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorForce = force;
}
float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2PrismaticJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2PrismaticJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation);
b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2PulleyJoint.cpp
================================================
/*
* Copyright (c) 2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PulleyJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Pulley:
// length1 = norm(p1 - s1)
// length2 = norm(p2 - s2)
// C0 = (length1 + ratio * length2)_initial
// C = C0 - (length1 + ratio * length2)
// u1 = (p1 - s1) / norm(p1 - s1)
// u2 = (p2 - s2) / norm(p2 - s2)
// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]
// K = J * invM * JT
// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB,
const b2Vec2& groundA, const b2Vec2& groundB,
const b2Vec2& anchorA, const b2Vec2& anchorB,
float32 r)
{
bodyA = bA;
bodyB = bB;
groundAnchorA = groundA;
groundAnchorB = groundB;
localAnchorA = bodyA->GetLocalPoint(anchorA);
localAnchorB = bodyB->GetLocalPoint(anchorB);
b2Vec2 dA = anchorA - groundA;
lengthA = dA.Length();
b2Vec2 dB = anchorB - groundB;
lengthB = dB.Length();
ratio = r;
b2Assert(ratio > b2_epsilon);
}
b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
: b2Joint(def)
{
m_groundAnchorA = def->groundAnchorA;
m_groundAnchorB = def->groundAnchorB;
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_lengthA = def->lengthA;
m_lengthB = def->lengthB;
b2Assert(def->ratio != 0.0f);
m_ratio = def->ratio;
m_constant = def->lengthA + m_ratio * def->lengthB;
m_impulse = 0.0f;
}
void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// Get the pulley axes.
m_uA = cA + m_rA - m_groundAnchorA;
m_uB = cB + m_rB - m_groundAnchorB;
float32 lengthA = m_uA.Length();
float32 lengthB = m_uB.Length();
if (lengthA > 10.0f * b2_linearSlop)
{
m_uA *= 1.0f / lengthA;
}
else
{
m_uA.SetZero();
}
if (lengthB > 10.0f * b2_linearSlop)
{
m_uB *= 1.0f / lengthB;
}
else
{
m_uB.SetZero();
}
// Compute effective mass.
float32 ruA = b2Cross(m_rA, m_uA);
float32 ruB = b2Cross(m_rB, m_uB);
float32 mA = m_invMassA + m_invIA * ruA * ruA;
float32 mB = m_invMassB + m_invIB * ruB * ruB;
m_mass = mA + m_ratio * m_ratio * mB;
if (m_mass > 0.0f)
{
m_mass = 1.0f / m_mass;
}
if (data.step.warmStarting)
{
// Scale impulses to support variable time steps.
m_impulse *= data.step.dtRatio;
// Warm starting.
b2Vec2 PA = -(m_impulse) * m_uA;
b2Vec2 PB = (-m_ratio * m_impulse) * m_uB;
vA += m_invMassA * PA;
wA += m_invIA * b2Cross(m_rA, PA);
vB += m_invMassB * PB;
wB += m_invIB * b2Cross(m_rB, PB);
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Vec2 vpA = vA + b2Cross(wA, m_rA);
b2Vec2 vpB = vB + b2Cross(wB, m_rB);
float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB);
float32 impulse = -m_mass * Cdot;
m_impulse += impulse;
b2Vec2 PA = -impulse * m_uA;
b2Vec2 PB = -m_ratio * impulse * m_uB;
vA += m_invMassA * PA;
wA += m_invIA * b2Cross(m_rA, PA);
vB += m_invMassB * PB;
wB += m_invIB * b2Cross(m_rB, PB);
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// Get the pulley axes.
b2Vec2 uA = cA + rA - m_groundAnchorA;
b2Vec2 uB = cB + rB - m_groundAnchorB;
float32 lengthA = uA.Length();
float32 lengthB = uB.Length();
if (lengthA > 10.0f * b2_linearSlop)
{
uA *= 1.0f / lengthA;
}
else
{
uA.SetZero();
}
if (lengthB > 10.0f * b2_linearSlop)
{
uB *= 1.0f / lengthB;
}
else
{
uB.SetZero();
}
// Compute effective mass.
float32 ruA = b2Cross(rA, uA);
float32 ruB = b2Cross(rB, uB);
float32 mA = m_invMassA + m_invIA * ruA * ruA;
float32 mB = m_invMassB + m_invIB * ruB * ruB;
float32 mass = mA + m_ratio * m_ratio * mB;
if (mass > 0.0f)
{
mass = 1.0f / mass;
}
float32 C = m_constant - lengthA - m_ratio * lengthB;
float32 linearError = b2Abs(C);
float32 impulse = -mass * C;
b2Vec2 PA = -impulse * uA;
b2Vec2 PB = -m_ratio * impulse * uB;
cA += m_invMassA * PA;
aA += m_invIA * b2Cross(rA, PA);
cB += m_invMassB * PB;
aB += m_invIB * b2Cross(rB, PB);
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return linearError < b2_linearSlop;
}
b2Vec2 b2PulleyJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2PulleyJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P = m_impulse * m_uB;
return inv_dt * P;
}
float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
b2Vec2 b2PulleyJoint::GetGroundAnchorA() const
{
return m_groundAnchorA;
}
b2Vec2 b2PulleyJoint::GetGroundAnchorB() const
{
return m_groundAnchorB;
}
float32 b2PulleyJoint::GetLengthA() const
{
return m_lengthA;
}
float32 b2PulleyJoint::GetLengthB() const
{
return m_lengthB;
}
float32 b2PulleyJoint::GetRatio() const
{
return m_ratio;
}
float32 b2PulleyJoint::GetCurrentLengthA() const
{
b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA);
b2Vec2 s = m_groundAnchorA;
b2Vec2 d = p - s;
return d.Length();
}
float32 b2PulleyJoint::GetCurrentLengthB() const
{
b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB);
b2Vec2 s = m_groundAnchorB;
b2Vec2 d = p - s;
return d.Length();
}
void b2PulleyJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2PulleyJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y);
b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.lengthA = %.15lef;\n", m_lengthA);
b2Log(" jd.lengthB = %.15lef;\n", m_lengthB);
b2Log(" jd.ratio = %.15lef;\n", m_ratio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
void b2PulleyJoint::ShiftOrigin(const b2Vec2& newOrigin)
{
m_groundAnchorA -= newOrigin;
m_groundAnchorB -= newOrigin;
}
================================================
FILE: app/src/main/cpp/b2RevoluteJoint.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2RevoluteJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Point-to-point constraint
// C = p2 - p1
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Motor constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorImpulse = 0.0f;
m_lowerAngle = def->lowerAngle;
m_upperAngle = def->upperAngle;
m_maxMotorTorque = def->maxMotorTorque;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
}
void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
bool fixedRotation = (iA + iB == 0.0f);
m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
m_mass.ex.y = m_mass.ey.x;
m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
m_mass.ex.z = m_mass.ez.x;
m_mass.ey.z = m_mass.ez.y;
m_mass.ez.z = iA + iB;
m_motorMass = iA + iB;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
if (m_enableMotor == false || fixedRotation)
{
m_motorImpulse = 0.0f;
}
if (m_enableLimit && fixedRotation == false)
{
float32 jointAngle = aB - aA - m_referenceAngle;
if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
{
m_limitState = e_equalLimits;
}
else if (jointAngle <= m_lowerAngle)
{
if (m_limitState != e_atLowerLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atLowerLimit;
}
else if (jointAngle >= m_upperAngle)
{
if (m_limitState != e_atUpperLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atUpperLimit;
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
}
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P(m_impulse.x, m_impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z);
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
bool fixedRotation = (iA + iB == 0.0f);
// Solve motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false)
{
float32 Cdot = wB - wA - m_motorSpeed;
float32 impulse = -m_motorMass * Cdot;
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorTorque;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
{
b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
float32 Cdot2 = wB - wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 impulse = -m_mass.Solve33(Cdot);
if (m_limitState == e_equalLimits)
{
m_impulse += impulse;
}
else if (m_limitState == e_atLowerLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse < 0.0f)
{
b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
b2Vec2 reduced = m_mass.Solve22(rhs);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
else
{
m_impulse += impulse;
}
}
else if (m_limitState == e_atUpperLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse > 0.0f)
{
b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
b2Vec2 reduced = m_mass.Solve22(rhs);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
else
{
m_impulse += impulse;
}
}
b2Vec2 P(impulse.x, impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + impulse.z);
}
else
{
// Solve point-to-point constraint
b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
b2Vec2 impulse = m_mass.Solve22(-Cdot);
m_impulse.x += impulse.x;
m_impulse.y += impulse.y;
vA -= mA * impulse;
wA -= iA * b2Cross(m_rA, impulse);
vB += mB * impulse;
wB += iB * b2Cross(m_rB, impulse);
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
float32 angularError = 0.0f;
float32 positionError = 0.0f;
bool fixedRotation = (m_invIA + m_invIB == 0.0f);
// Solve angular limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
{
float32 angle = aB - aA - m_referenceAngle;
float32 limitImpulse = 0.0f;
if (m_limitState == e_equalLimits)
{
// Prevent large angular corrections
float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
angularError = b2Abs(C);
}
else if (m_limitState == e_atLowerLimit)
{
float32 C = angle - m_lowerAngle;
angularError = -C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
limitImpulse = -m_motorMass * C;
}
else if (m_limitState == e_atUpperLimit)
{
float32 C = angle - m_upperAngle;
angularError = C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
}
aA -= m_invIA * limitImpulse;
aB += m_invIB * limitImpulse;
}
// Solve point-to-point constraint.
{
qA.Set(aA);
qB.Set(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 C = cB + rB - cA - rA;
positionError = C.Length();
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Mat22 K;
K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
K.ey.x = K.ex.y;
K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
b2Vec2 impulse = -K.Solve(C);
cA -= mA * impulse;
aA -= iA * b2Cross(rA, impulse);
cB += mB * impulse;
aB += iB * b2Cross(rB, impulse);
}
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2RevoluteJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2RevoluteJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P(m_impulse.x, m_impulse.y);
return inv_dt * P;
}
float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.z;
}
float32 b2RevoluteJoint::GetJointAngle() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
}
float32 b2RevoluteJoint::GetJointSpeed() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
return bB->m_angularVelocity - bA->m_angularVelocity;
}
bool b2RevoluteJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2RevoluteJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2RevoluteJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorTorque = torque;
}
bool b2RevoluteJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2RevoluteJoint::EnableLimit(bool flag)
{
if (flag != m_enableLimit)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
m_impulse.z = 0.0f;
}
}
float32 b2RevoluteJoint::GetLowerLimit() const
{
return m_lowerAngle;
}
float32 b2RevoluteJoint::GetUpperLimit() const
{
return m_upperAngle;
}
void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
if (lower != m_lowerAngle || upper != m_upperAngle)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_impulse.z = 0.0f;
m_lowerAngle = lower;
m_upperAngle = upper;
}
}
void b2RevoluteJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2RevoluteJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle);
b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2Rope.cpp
================================================
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Rope/b2Rope.h"
#include "isEngine/ext_lib/Box2D/Common/b2Draw.h"
b2Rope::b2Rope()
{
m_count = 0;
m_ps = NULL;
m_p0s = NULL;
m_vs = NULL;
m_ims = NULL;
m_Ls = NULL;
m_as = NULL;
m_gravity.SetZero();
m_k2 = 1.0f;
m_k3 = 0.1f;
}
b2Rope::~b2Rope()
{
b2Free(m_ps);
b2Free(m_p0s);
b2Free(m_vs);
b2Free(m_ims);
b2Free(m_Ls);
b2Free(m_as);
}
void b2Rope::Initialize(const b2RopeDef* def)
{
b2Assert(def->count >= 3);
m_count = def->count;
m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
m_ims = (float32*)b2Alloc(m_count * sizeof(float32));
for (int32 i = 0; i < m_count; ++i)
{
m_ps[i] = def->vertices[i];
m_p0s[i] = def->vertices[i];
m_vs[i].SetZero();
float32 m = def->masses[i];
if (m > 0.0f)
{
m_ims[i] = 1.0f / m;
}
else
{
m_ims[i] = 0.0f;
}
}
int32 count2 = m_count - 1;
int32 count3 = m_count - 2;
m_Ls = (float32*)b2Alloc(count2 * sizeof(float32));
m_as = (float32*)b2Alloc(count3 * sizeof(float32));
for (int32 i = 0; i < count2; ++i)
{
b2Vec2 p1 = m_ps[i];
b2Vec2 p2 = m_ps[i+1];
m_Ls[i] = b2Distance(p1, p2);
}
for (int32 i = 0; i < count3; ++i)
{
b2Vec2 p1 = m_ps[i];
b2Vec2 p2 = m_ps[i + 1];
b2Vec2 p3 = m_ps[i + 2];
b2Vec2 d1 = p2 - p1;
b2Vec2 d2 = p3 - p2;
float32 a = b2Cross(d1, d2);
float32 b = b2Dot(d1, d2);
m_as[i] = b2Atan2(a, b);
}
m_gravity = def->gravity;
m_damping = def->damping;
m_k2 = def->k2;
m_k3 = def->k3;
}
void b2Rope::Step(float32 h, int32 iterations)
{
if (h == 0.0)
{
return;
}
float32 d = expf(- h * m_damping);
for (int32 i = 0; i < m_count; ++i)
{
m_p0s[i] = m_ps[i];
if (m_ims[i] > 0.0f)
{
m_vs[i] += h * m_gravity;
}
m_vs[i] *= d;
m_ps[i] += h * m_vs[i];
}
for (int32 i = 0; i < iterations; ++i)
{
SolveC2();
SolveC3();
SolveC2();
}
float32 inv_h = 1.0f / h;
for (int32 i = 0; i < m_count; ++i)
{
m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]);
}
}
void b2Rope::SolveC2()
{
int32 count2 = m_count - 1;
for (int32 i = 0; i < count2; ++i)
{
b2Vec2 p1 = m_ps[i];
b2Vec2 p2 = m_ps[i + 1];
b2Vec2 d = p2 - p1;
float32 L = d.Normalize();
float32 im1 = m_ims[i];
float32 im2 = m_ims[i + 1];
if (im1 + im2 == 0.0f)
{
continue;
}
float32 s1 = im1 / (im1 + im2);
float32 s2 = im2 / (im1 + im2);
p1 -= m_k2 * s1 * (m_Ls[i] - L) * d;
p2 += m_k2 * s2 * (m_Ls[i] - L) * d;
m_ps[i] = p1;
m_ps[i + 1] = p2;
}
}
void b2Rope::SetAngle(float32 angle)
{
int32 count3 = m_count - 2;
for (int32 i = 0; i < count3; ++i)
{
m_as[i] = angle;
}
}
void b2Rope::SolveC3()
{
int32 count3 = m_count - 2;
for (int32 i = 0; i < count3; ++i)
{
b2Vec2 p1 = m_ps[i];
b2Vec2 p2 = m_ps[i + 1];
b2Vec2 p3 = m_ps[i + 2];
float32 m1 = m_ims[i];
float32 m2 = m_ims[i + 1];
float32 m3 = m_ims[i + 2];
b2Vec2 d1 = p2 - p1;
b2Vec2 d2 = p3 - p2;
float32 L1sqr = d1.LengthSquared();
float32 L2sqr = d2.LengthSquared();
if (L1sqr * L2sqr == 0.0f)
{
continue;
}
float32 a = b2Cross(d1, d2);
float32 b = b2Dot(d1, d2);
float32 angle = b2Atan2(a, b);
b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew();
b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew();
b2Vec2 J1 = -Jd1;
b2Vec2 J2 = Jd1 - Jd2;
b2Vec2 J3 = Jd2;
float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3);
if (mass == 0.0f)
{
continue;
}
mass = 1.0f / mass;
float32 C = angle - m_as[i];
while (C > b2_pi)
{
angle -= 2 * b2_pi;
C = angle - m_as[i];
}
while (C < -b2_pi)
{
angle += 2.0f * b2_pi;
C = angle - m_as[i];
}
float32 impulse = - m_k3 * mass * C;
p1 += (m1 * impulse) * J1;
p2 += (m2 * impulse) * J2;
p3 += (m3 * impulse) * J3;
m_ps[i] = p1;
m_ps[i + 1] = p2;
m_ps[i + 2] = p3;
}
}
void b2Rope::Draw(b2Draw* draw) const
{
b2Color c(0.4f, 0.5f, 0.7f);
for (int32 i = 0; i < m_count - 1; ++i)
{
draw->DrawSegment(m_ps[i], m_ps[i+1], c);
}
}
================================================
FILE: app/src/main/cpp/b2RopeJoint.cpp
================================================
/*
* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2RopeJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Limit:
// C = norm(pB - pA) - L
// u = (pB - pA) / norm(pB - pA)
// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA))
// J = [-u -cross(rA, u) u cross(rB, u)]
// K = J * invM * JT
// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2
b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_maxLength = def->maxLength;
m_mass = 0.0f;
m_impulse = 0.0f;
m_state = e_inactiveLimit;
m_length = 0.0f;
}
void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
m_u = cB + m_rB - cA - m_rA;
m_length = m_u.Length();
float32 C = m_length - m_maxLength;
if (C > 0.0f)
{
m_state = e_atUpperLimit;
}
else
{
m_state = e_inactiveLimit;
}
if (m_length > b2_linearSlop)
{
m_u *= 1.0f / m_length;
}
else
{
m_u.SetZero();
m_mass = 0.0f;
m_impulse = 0.0f;
return;
}
// Compute effective mass.
float32 crA = b2Cross(m_rA, m_u);
float32 crB = b2Cross(m_rB, m_u);
float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB;
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
m_impulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Cdot = dot(u, v + cross(w, r))
b2Vec2 vpA = vA + b2Cross(wA, m_rA);
b2Vec2 vpB = vB + b2Cross(wB, m_rB);
float32 C = m_length - m_maxLength;
float32 Cdot = b2Dot(m_u, vpB - vpA);
// Predictive constraint.
if (C < 0.0f)
{
Cdot += data.step.inv_dt * C;
}
float32 impulse = -m_mass * Cdot;
float32 oldImpulse = m_impulse;
m_impulse = b2Min(0.0f, m_impulse + impulse);
impulse = m_impulse - oldImpulse;
b2Vec2 P = impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 u = cB + rB - cA - rA;
float32 length = u.Normalize();
float32 C = length - m_maxLength;
C = b2Clamp(C, 0.0f, b2_maxLinearCorrection);
float32 impulse = -m_mass * C;
b2Vec2 P = impulse * u;
cA -= m_invMassA * P;
aA -= m_invIA * b2Cross(rA, P);
cB += m_invMassB * P;
aB += m_invIB * b2Cross(rB, P);
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return length - m_maxLength < b2_linearSlop;
}
b2Vec2 b2RopeJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2RopeJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 F = (inv_dt * m_impulse) * m_u;
return F;
}
float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
float32 b2RopeJoint::GetMaxLength() const
{
return m_maxLength;
}
b2LimitState b2RopeJoint::GetLimitState() const
{
return m_state;
}
void b2RopeJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2RopeJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.maxLength = %.15lef;\n", m_maxLength);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2Settings.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2Settings.h"
#include
#include
#include
b2Version b2_version = {2, 3, 0};
// Memory allocators. Modify these to use your own allocator.
void* b2Alloc(int32 size)
{
return malloc(size);
}
void b2Free(void* mem)
{
free(mem);
}
// You can modify this to use your logging facility.
void b2Log(const char* string, ...)
{
va_list args;
va_start(args, string);
vprintf(string, args);
va_end(args);
}
================================================
FILE: app/src/main/cpp/b2StackAllocator.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2StackAllocator.h"
#include "isEngine/ext_lib/Box2D/Common/b2Math.h"
b2StackAllocator::b2StackAllocator()
{
m_index = 0;
m_allocation = 0;
m_maxAllocation = 0;
m_entryCount = 0;
}
b2StackAllocator::~b2StackAllocator()
{
b2Assert(m_index == 0);
b2Assert(m_entryCount == 0);
}
void* b2StackAllocator::Allocate(int32 size)
{
b2Assert(m_entryCount < b2_maxStackEntries);
b2StackEntry* entry = m_entries + m_entryCount;
entry->size = size;
if (m_index + size > b2_stackSize)
{
entry->data = (char*)b2Alloc(size);
entry->usedMalloc = true;
}
else
{
entry->data = m_data + m_index;
entry->usedMalloc = false;
m_index += size;
}
m_allocation += size;
m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
++m_entryCount;
return entry->data;
}
void b2StackAllocator::Free(void* p)
{
b2Assert(m_entryCount > 0);
b2StackEntry* entry = m_entries + m_entryCount - 1;
b2Assert(p == entry->data);
if (entry->usedMalloc)
{
b2Free(p);
}
else
{
m_index -= entry->size;
}
m_allocation -= entry->size;
--m_entryCount;
p = NULL;
}
int32 b2StackAllocator::GetMaxAllocation() const
{
return m_maxAllocation;
}
================================================
FILE: app/src/main/cpp/b2TimeOfImpact.cpp
================================================
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/b2Distance.h"
#include "isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
#include "isEngine/ext_lib/Box2D/Common/b2Timer.h"
#include
float32 b2_toiTime, b2_toiMaxTime;
int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
int32 b2_toiRootIters, b2_toiMaxRootIters;
//
struct b2SeparationFunction
{
enum Type
{
e_points,
e_faceA,
e_faceB
};
// TODO_ERIN might not need to return the separation
float32 Initialize(const b2SimplexCache* cache,
const b2DistanceProxy* proxyA, const b2Sweep& sweepA,
const b2DistanceProxy* proxyB, const b2Sweep& sweepB,
float32 t1)
{
m_proxyA = proxyA;
m_proxyB = proxyB;
int32 count = cache->count;
b2Assert(0 < count && count < 3);
m_sweepA = sweepA;
m_sweepB = sweepB;
b2Transform xfA, xfB;
m_sweepA.GetTransform(&xfA, t1);
m_sweepB.GetTransform(&xfB, t1);
if (count == 1)
{
m_type = e_points;
b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);
b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
b2Vec2 pointA = b2Mul(xfA, localPointA);
b2Vec2 pointB = b2Mul(xfB, localPointB);
m_axis = pointB - pointA;
float32 s = m_axis.Normalize();
return s;
}
else if (cache->indexA[0] == cache->indexA[1])
{
// Two points on B and one on A.
m_type = e_faceB;
b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);
b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);
m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);
m_axis.Normalize();
b2Vec2 normal = b2Mul(xfB.q, m_axis);
m_localPoint = 0.5f * (localPointB1 + localPointB2);
b2Vec2 pointB = b2Mul(xfB, m_localPoint);
b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);
b2Vec2 pointA = b2Mul(xfA, localPointA);
float32 s = b2Dot(pointA - pointB, normal);
if (s < 0.0f)
{
m_axis = -m_axis;
s = -s;
}
return s;
}
else
{
// Two points on A and one or two points on B.
m_type = e_faceA;
b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);
b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);
m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);
m_axis.Normalize();
b2Vec2 normal = b2Mul(xfA.q, m_axis);
m_localPoint = 0.5f * (localPointA1 + localPointA2);
b2Vec2 pointA = b2Mul(xfA, m_localPoint);
b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
b2Vec2 pointB = b2Mul(xfB, localPointB);
float32 s = b2Dot(pointB - pointA, normal);
if (s < 0.0f)
{
m_axis = -m_axis;
s = -s;
}
return s;
}
}
//
float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const
{
b2Transform xfA, xfB;
m_sweepA.GetTransform(&xfA, t);
m_sweepB.GetTransform(&xfB, t);
switch (m_type)
{
case e_points:
{
b2Vec2 axisA = b2MulT(xfA.q, m_axis);
b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
*indexA = m_proxyA->GetSupport(axisA);
*indexB = m_proxyB->GetSupport(axisB);
b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
b2Vec2 pointA = b2Mul(xfA, localPointA);
b2Vec2 pointB = b2Mul(xfB, localPointB);
float32 separation = b2Dot(pointB - pointA, m_axis);
return separation;
}
case e_faceA:
{
b2Vec2 normal = b2Mul(xfA.q, m_axis);
b2Vec2 pointA = b2Mul(xfA, m_localPoint);
b2Vec2 axisB = b2MulT(xfB.q, -normal);
*indexA = -1;
*indexB = m_proxyB->GetSupport(axisB);
b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
b2Vec2 pointB = b2Mul(xfB, localPointB);
float32 separation = b2Dot(pointB - pointA, normal);
return separation;
}
case e_faceB:
{
b2Vec2 normal = b2Mul(xfB.q, m_axis);
b2Vec2 pointB = b2Mul(xfB, m_localPoint);
b2Vec2 axisA = b2MulT(xfA.q, -normal);
*indexB = -1;
*indexA = m_proxyA->GetSupport(axisA);
b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
b2Vec2 pointA = b2Mul(xfA, localPointA);
float32 separation = b2Dot(pointA - pointB, normal);
return separation;
}
default:
b2Assert(false);
*indexA = -1;
*indexB = -1;
return 0.0f;
}
}
//
float32 Evaluate(int32 indexA, int32 indexB, float32 t) const
{
b2Transform xfA, xfB;
m_sweepA.GetTransform(&xfA, t);
m_sweepB.GetTransform(&xfB, t);
switch (m_type)
{
case e_points:
{
b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
b2Vec2 pointA = b2Mul(xfA, localPointA);
b2Vec2 pointB = b2Mul(xfB, localPointB);
float32 separation = b2Dot(pointB - pointA, m_axis);
return separation;
}
case e_faceA:
{
b2Vec2 normal = b2Mul(xfA.q, m_axis);
b2Vec2 pointA = b2Mul(xfA, m_localPoint);
b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
b2Vec2 pointB = b2Mul(xfB, localPointB);
float32 separation = b2Dot(pointB - pointA, normal);
return separation;
}
case e_faceB:
{
b2Vec2 normal = b2Mul(xfB.q, m_axis);
b2Vec2 pointB = b2Mul(xfB, m_localPoint);
b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
b2Vec2 pointA = b2Mul(xfA, localPointA);
float32 separation = b2Dot(pointA - pointB, normal);
return separation;
}
default:
b2Assert(false);
return 0.0f;
}
}
const b2DistanceProxy* m_proxyA;
const b2DistanceProxy* m_proxyB;
b2Sweep m_sweepA, m_sweepB;
Type m_type;
b2Vec2 m_localPoint;
b2Vec2 m_axis;
};
// CCD via the local separating axis method. This seeks progression
// by computing the largest time at which separation is maintained.
void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)
{
b2Timer timer;
++b2_toiCalls;
output->state = b2TOIOutput::e_unknown;
output->t = input->tMax;
const b2DistanceProxy* proxyA = &input->proxyA;
const b2DistanceProxy* proxyB = &input->proxyB;
b2Sweep sweepA = input->sweepA;
b2Sweep sweepB = input->sweepB;
// Large rotations can make the root finder fail, so we normalize the
// sweep angles.
sweepA.Normalize();
sweepB.Normalize();
float32 tMax = input->tMax;
float32 totalRadius = proxyA->m_radius + proxyB->m_radius;
float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);
float32 tolerance = 0.25f * b2_linearSlop;
b2Assert(target > tolerance);
float32 t1 = 0.0f;
const int32 k_maxIterations = 20; // TODO_ERIN b2Settings
int32 iter = 0;
// Prepare input for distance query.
b2SimplexCache cache;
cache.count = 0;
b2DistanceInput distanceInput;
distanceInput.proxyA = input->proxyA;
distanceInput.proxyB = input->proxyB;
distanceInput.useRadii = false;
// The outer loop progressively attempts to compute new separating axes.
// This loop terminates when an axis is repeated (no progress is made).
for(;;)
{
b2Transform xfA, xfB;
sweepA.GetTransform(&xfA, t1);
sweepB.GetTransform(&xfB, t1);
// Get the distance between shapes. We can also use the results
// to get a separating axis.
distanceInput.transformA = xfA;
distanceInput.transformB = xfB;
b2DistanceOutput distanceOutput;
b2Distance(&distanceOutput, &cache, &distanceInput);
// If the shapes are overlapped, we give up on continuous collision.
if (distanceOutput.distance <= 0.0f)
{
// Failure!
output->state = b2TOIOutput::e_overlapped;
output->t = 0.0f;
break;
}
if (distanceOutput.distance < target + tolerance)
{
// Victory!
output->state = b2TOIOutput::e_touching;
output->t = t1;
break;
}
// Initialize the separating axis.
b2SeparationFunction fcn;
fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
#if 0
// Dump the curve seen by the root finder
{
const int32 N = 100;
float32 dx = 1.0f / N;
float32 xs[N+1];
float32 fs[N+1];
float32 x = 0.0f;
for (int32 i = 0; i <= N; ++i)
{
sweepA.GetTransform(&xfA, x);
sweepB.GetTransform(&xfB, x);
float32 f = fcn.Evaluate(xfA, xfB) - target;
printf("%g %g\n", x, f);
xs[i] = x;
fs[i] = f;
x += dx;
}
}
#endif
// Compute the TOI on the separating axis. We do this by successively
// resolving the deepest point. This loop is bounded by the number of vertices.
bool done = false;
float32 t2 = tMax;
int32 pushBackIter = 0;
for (;;)
{
// Find the deepest point at t2. Store the witness point indices.
int32 indexA, indexB;
float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);
// Is the final configuration separated?
if (s2 > target + tolerance)
{
// Victory!
output->state = b2TOIOutput::e_separated;
output->t = tMax;
done = true;
break;
}
// Has the separation reached tolerance?
if (s2 > target - tolerance)
{
// Advance the sweeps
t1 = t2;
break;
}
// Compute the initial separation of the witness points.
float32 s1 = fcn.Evaluate(indexA, indexB, t1);
// Check for initial overlap. This might happen if the root finder
// runs out of iterations.
if (s1 < target - tolerance)
{
output->state = b2TOIOutput::e_failed;
output->t = t1;
done = true;
break;
}
// Check for touching
if (s1 <= target + tolerance)
{
// Victory! t1 should hold the TOI (could be 0.0).
output->state = b2TOIOutput::e_touching;
output->t = t1;
done = true;
break;
}
// Compute 1D root of: f(x) - target = 0
int32 rootIterCount = 0;
float32 a1 = t1, a2 = t2;
for (;;)
{
// Use a mix of the secant rule and bisection.
float32 t;
if (rootIterCount & 1)
{
// Secant rule to improve convergence.
t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
}
else
{
// Bisection to guarantee progress.
t = 0.5f * (a1 + a2);
}
++rootIterCount;
++b2_toiRootIters;
float32 s = fcn.Evaluate(indexA, indexB, t);
if (b2Abs(s - target) < tolerance)
{
// t2 holds a tentative value for t1
t2 = t;
break;
}
// Ensure we continue to bracket the root.
if (s > target)
{
a1 = t;
s1 = s;
}
else
{
a2 = t;
s2 = s;
}
if (rootIterCount == 50)
{
break;
}
}
b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
++pushBackIter;
if (pushBackIter == b2_maxPolygonVertices)
{
break;
}
}
++iter;
++b2_toiIters;
if (done)
{
break;
}
if (iter == k_maxIterations)
{
// Root finder got stuck. Semi-victory.
output->state = b2TOIOutput::e_failed;
output->t = t1;
break;
}
}
b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);
float32 time = timer.GetMilliseconds();
b2_toiMaxTime = b2Max(b2_toiMaxTime, time);
b2_toiTime += time;
}
================================================
FILE: app/src/main/cpp/b2Timer.cpp
================================================
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Common/b2Timer.h"
#if defined(_WIN32)
float64 b2Timer::s_invFrequency = 0.0f;
#define WIN32_LEAN_AND_MEAN
#include
b2Timer::b2Timer()
{
LARGE_INTEGER largeInteger;
if (s_invFrequency == 0.0f)
{
QueryPerformanceFrequency(&largeInteger);
s_invFrequency = float64(largeInteger.QuadPart);
if (s_invFrequency > 0.0f)
{
s_invFrequency = 1000.0f / s_invFrequency;
}
}
QueryPerformanceCounter(&largeInteger);
m_start = float64(largeInteger.QuadPart);
}
void b2Timer::Reset()
{
LARGE_INTEGER largeInteger;
QueryPerformanceCounter(&largeInteger);
m_start = float64(largeInteger.QuadPart);
}
float32 b2Timer::GetMilliseconds() const
{
LARGE_INTEGER largeInteger;
QueryPerformanceCounter(&largeInteger);
float64 count = float64(largeInteger.QuadPart);
float32 ms = float32(s_invFrequency * (count - m_start));
return ms;
}
#elif defined(__linux__) || defined (__APPLE__)
#include
b2Timer::b2Timer()
{
Reset();
}
void b2Timer::Reset()
{
timeval t;
gettimeofday(&t, 0);
m_start_sec = t.tv_sec;
m_start_usec = t.tv_usec;
}
float32 b2Timer::GetMilliseconds() const
{
timeval t;
gettimeofday(&t, 0);
return 1000.0f * (t.tv_sec - m_start_sec) + 0.001f * (t.tv_usec - m_start_usec);
}
#else
b2Timer::b2Timer()
{
}
void b2Timer::Reset()
{
}
float32 b2Timer::GetMilliseconds() const
{
return 0.0f;
}
#endif
================================================
FILE: app/src/main/cpp/b2WeldJoint.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2WeldJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Point-to-point constraint
// C = p2 - p1
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Angle constraint
// C = angle2 - angle1 - referenceAngle
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_referenceAngle = def->referenceAngle;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_impulse.SetZero();
}
void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Mat33 K;
K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
K.ez.x = -m_rA.y * iA - m_rB.y * iB;
K.ex.y = K.ey.x;
K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
K.ez.y = m_rA.x * iA + m_rB.x * iB;
K.ex.z = K.ez.x;
K.ey.z = K.ez.y;
K.ez.z = iA + iB;
if (m_frequencyHz > 0.0f)
{
K.GetInverse22(&m_mass);
float32 invM = iA + iB;
float32 m = invM > 0.0f ? 1.0f / invM : 0.0f;
float32 C = aB - aA - m_referenceAngle;
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m * m_dampingRatio * omega;
// Spring stiffness
float32 k = m * omega * omega;
// magic formulas
float32 h = data.step.dt;
m_gamma = h * (d + h * k);
m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
m_bias = C * h * k * m_gamma;
invM += m_gamma;
m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f;
}
else
{
K.GetSymInverse33(&m_mass);
m_gamma = 0.0f;
m_bias = 0.0f;
}
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse *= data.step.dtRatio;
b2Vec2 P(m_impulse.x, m_impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + m_impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + m_impulse.z);
}
else
{
m_impulse.SetZero();
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
if (m_frequencyHz > 0.0f)
{
float32 Cdot2 = wB - wA;
float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z);
m_impulse.z += impulse2;
wA -= iA * impulse2;
wB += iB * impulse2;
b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1);
m_impulse.x += impulse1.x;
m_impulse.y += impulse1.y;
b2Vec2 P = impulse1;
vA -= mA * P;
wA -= iA * b2Cross(m_rA, P);
vB += mB * P;
wB += iB * b2Cross(m_rB, P);
}
else
{
b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
float32 Cdot2 = wB - wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 impulse = -b2Mul(m_mass, Cdot);
m_impulse += impulse;
b2Vec2 P(impulse.x, impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + impulse.z);
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
float32 positionError, angularError;
b2Mat33 K;
K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
K.ez.x = -rA.y * iA - rB.y * iB;
K.ex.y = K.ey.x;
K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
K.ez.y = rA.x * iA + rB.x * iB;
K.ex.z = K.ez.x;
K.ey.z = K.ez.y;
K.ez.z = iA + iB;
if (m_frequencyHz > 0.0f)
{
b2Vec2 C1 = cB + rB - cA - rA;
positionError = C1.Length();
angularError = 0.0f;
b2Vec2 P = -K.Solve22(C1);
cA -= mA * P;
aA -= iA * b2Cross(rA, P);
cB += mB * P;
aB += iB * b2Cross(rB, P);
}
else
{
b2Vec2 C1 = cB + rB - cA - rA;
float32 C2 = aB - aA - m_referenceAngle;
positionError = C1.Length();
angularError = b2Abs(C2);
b2Vec3 C(C1.x, C1.y, C2);
b2Vec3 impulse = -K.Solve33(C);
b2Vec2 P(impulse.x, impulse.y);
cA -= mA * P;
aA -= iA * (b2Cross(rA, P) + impulse.z);
cB += mB * P;
aB += iB * (b2Cross(rB, P) + impulse.z);
}
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2WeldJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2WeldJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P(m_impulse.x, m_impulse.y);
return inv_dt * P;
}
float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.z;
}
void b2WeldJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2WeldJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2WheelJoint.cpp
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/Joints/b2WheelJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h"
// Linear constraint (point-to-line)
// d = pB - pA = xB + rB - xA - rA
// C = dot(ay, d)
// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
// Spring linear constraint
// C = dot(ax, d)
// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
// Motor rotational constraint
// Cdot = wB - wA
// J = [0 0 -1 0 0 1]
void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxisA = bodyA->GetLocalVector(axis);
}
b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_localXAxisA = def->localAxisA;
m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
m_mass = 0.0f;
m_impulse = 0.0f;
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
m_springMass = 0.0f;
m_springImpulse = 0.0f;
m_maxMotorTorque = def->maxMotorTorque;
m_motorSpeed = def->motorSpeed;
m_enableMotor = def->enableMotor;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_bias = 0.0f;
m_gamma = 0.0f;
m_ax.SetZero();
m_ay.SetZero();
}
void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective masses.
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = cB + rB - cA - rA;
// Point to line constraint
{
m_ay = b2Mul(qA, m_localYAxisA);
m_sAy = b2Cross(d + rA, m_ay);
m_sBy = b2Cross(rB, m_ay);
m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy;
if (m_mass > 0.0f)
{
m_mass = 1.0f / m_mass;
}
}
// Spring constraint
m_springMass = 0.0f;
m_bias = 0.0f;
m_gamma = 0.0f;
if (m_frequencyHz > 0.0f)
{
m_ax = b2Mul(qA, m_localXAxisA);
m_sAx = b2Cross(d + rA, m_ax);
m_sBx = b2Cross(rB, m_ax);
float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx;
if (invMass > 0.0f)
{
m_springMass = 1.0f / invMass;
float32 C = b2Dot(d, m_ax);
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m_springMass * m_dampingRatio * omega;
// Spring stiffness
float32 k = m_springMass * omega * omega;
// magic formulas
float32 h = data.step.dt;
m_gamma = h * (d + h * k);
if (m_gamma > 0.0f)
{
m_gamma = 1.0f / m_gamma;
}
m_bias = C * h * k * m_gamma;
m_springMass = invMass + m_gamma;
if (m_springMass > 0.0f)
{
m_springMass = 1.0f / m_springMass;
}
}
}
else
{
m_springImpulse = 0.0f;
}
// Rotational motor
if (m_enableMotor)
{
m_motorMass = iA + iB;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
}
else
{
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
}
if (data.step.warmStarting)
{
// Account for variable time step.
m_impulse *= data.step.dtRatio;
m_springImpulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax;
float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse;
float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse;
vA -= m_invMassA * P;
wA -= m_invIA * LA;
vB += m_invMassB * P;
wB += m_invIB * LB;
}
else
{
m_impulse = 0.0f;
m_springImpulse = 0.0f;
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data)
{
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Solve spring constraint
{
float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA;
float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse);
m_springImpulse += impulse;
b2Vec2 P = impulse * m_ax;
float32 LA = impulse * m_sAx;
float32 LB = impulse * m_sBx;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
// Solve rotational motor constraint
{
float32 Cdot = wB - wA - m_motorSpeed;
float32 impulse = -m_motorMass * Cdot;
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorTorque;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve point to line constraint
{
float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA;
float32 impulse = -m_mass * Cdot;
m_impulse += impulse;
b2Vec2 P = impulse * m_ay;
float32 LA = impulse * m_sAy;
float32 LB = impulse * m_sBy;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = (cB - cA) + rB - rA;
b2Vec2 ay = b2Mul(qA, m_localYAxisA);
float32 sAy = b2Cross(d + rA, ay);
float32 sBy = b2Cross(rB, ay);
float32 C = b2Dot(d, ay);
float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy;
float32 impulse;
if (k != 0.0f)
{
impulse = - C / k;
}
else
{
impulse = 0.0f;
}
b2Vec2 P = impulse * ay;
float32 LA = impulse * sAy;
float32 LB = impulse * sBy;
cA -= m_invMassA * P;
aA -= m_invIA * LA;
cB += m_invMassB * P;
aB += m_invIB * LB;
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return b2Abs(C) <= b2_linearSlop;
}
b2Vec2 b2WheelJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2WheelJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax);
}
float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
float32 b2WheelJoint::GetJointTranslation() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA);
b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB);
b2Vec2 d = pB - pA;
b2Vec2 axis = bA->GetWorldVector(m_localXAxisA);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2WheelJoint::GetJointSpeed() const
{
float32 wA = m_bodyA->m_angularVelocity;
float32 wB = m_bodyB->m_angularVelocity;
return wB - wA;
}
bool b2WheelJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2WheelJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2WheelJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2WheelJoint::SetMaxMotorTorque(float32 torque)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorTorque = torque;
}
float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2WheelJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2WheelJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
================================================
FILE: app/src/main/cpp/b2World.cpp
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/b2World.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Body.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Island.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Joints/b2PulleyJoint.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h"
#include "isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ContactSolver.h"
#include "isEngine/ext_lib/Box2D/Collision/b2Collision.h"
#include "isEngine/ext_lib/Box2D/Collision/b2BroadPhase.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h"
#include "isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h"
#include "isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h"
#include "isEngine/ext_lib/Box2D/Common/b2Draw.h"
#include "isEngine/ext_lib/Box2D/Common/b2Timer.h"
#include
b2World::b2World(const b2Vec2& gravity)
{
m_destructionListener = NULL;
m_debugDraw = NULL;
m_bodyList = NULL;
m_jointList = NULL;
m_bodyCount = 0;
m_jointCount = 0;
m_warmStarting = true;
m_continuousPhysics = true;
m_subStepping = false;
m_stepComplete = true;
m_allowSleep = true;
m_gravity = gravity;
m_flags = e_clearForces;
m_inv_dt0 = 0.0f;
m_contactManager.m_allocator = &m_blockAllocator;
memset(&m_profile, 0, sizeof(b2Profile));
}
b2World::~b2World()
{
// Some shapes allocate using b2Alloc.
b2Body* b = m_bodyList;
while (b)
{
b2Body* bNext = b->m_next;
b2Fixture* f = b->m_fixtureList;
while (f)
{
b2Fixture* fNext = f->m_next;
f->m_proxyCount = 0;
f->Destroy(&m_blockAllocator);
f = fNext;
}
b = bNext;
}
}
void b2World::SetDestructionListener(b2DestructionListener* listener)
{
m_destructionListener = listener;
}
void b2World::SetContactFilter(b2ContactFilter* filter)
{
m_contactManager.m_contactFilter = filter;
}
void b2World::SetContactListener(b2ContactListener* listener)
{
m_contactManager.m_contactListener = listener;
}
void b2World::SetDebugDraw(b2Draw* debugDraw)
{
m_debugDraw = debugDraw;
}
b2Body* b2World::CreateBody(const b2BodyDef* def)
{
b2Assert(IsLocked() == false);
if (IsLocked())
{
return NULL;
}
void* mem = m_blockAllocator.Allocate(sizeof(b2Body));
b2Body* b = new (mem) b2Body(def, this);
// Add to world doubly linked list.
b->m_prev = NULL;
b->m_next = m_bodyList;
if (m_bodyList)
{
m_bodyList->m_prev = b;
}
m_bodyList = b;
++m_bodyCount;
return b;
}
void b2World::DestroyBody(b2Body* b)
{
b2Assert(m_bodyCount > 0);
b2Assert(IsLocked() == false);
if (IsLocked())
{
return;
}
// Delete the attached joints.
b2JointEdge* je = b->m_jointList;
while (je)
{
b2JointEdge* je0 = je;
je = je->next;
if (m_destructionListener)
{
m_destructionListener->SayGoodbye(je0->joint);
}
DestroyJoint(je0->joint);
b->m_jointList = je;
}
b->m_jointList = NULL;
// Delete the attached contacts.
b2ContactEdge* ce = b->m_contactList;
while (ce)
{
b2ContactEdge* ce0 = ce;
ce = ce->next;
m_contactManager.Destroy(ce0->contact);
}
b->m_contactList = NULL;
// Delete the attached fixtures. This destroys broad-phase proxies.
b2Fixture* f = b->m_fixtureList;
while (f)
{
b2Fixture* f0 = f;
f = f->m_next;
if (m_destructionListener)
{
m_destructionListener->SayGoodbye(f0);
}
f0->DestroyProxies(&m_contactManager.m_broadPhase);
f0->Destroy(&m_blockAllocator);
f0->~b2Fixture();
m_blockAllocator.Free(f0, sizeof(b2Fixture));
b->m_fixtureList = f;
b->m_fixtureCount -= 1;
}
b->m_fixtureList = NULL;
b->m_fixtureCount = 0;
// Remove world body list.
if (b->m_prev)
{
b->m_prev->m_next = b->m_next;
}
if (b->m_next)
{
b->m_next->m_prev = b->m_prev;
}
if (b == m_bodyList)
{
m_bodyList = b->m_next;
}
--m_bodyCount;
b->~b2Body();
m_blockAllocator.Free(b, sizeof(b2Body));
}
b2Joint* b2World::CreateJoint(const b2JointDef* def)
{
b2Assert(IsLocked() == false);
if (IsLocked())
{
return NULL;
}
b2Joint* j = b2Joint::Create(def, &m_blockAllocator);
// Connect to the world list.
j->m_prev = NULL;
j->m_next = m_jointList;
if (m_jointList)
{
m_jointList->m_prev = j;
}
m_jointList = j;
++m_jointCount;
// Connect to the bodies' doubly linked lists.
j->m_edgeA.joint = j;
j->m_edgeA.other = j->m_bodyB;
j->m_edgeA.prev = NULL;
j->m_edgeA.next = j->m_bodyA->m_jointList;
if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA;
j->m_bodyA->m_jointList = &j->m_edgeA;
j->m_edgeB.joint = j;
j->m_edgeB.other = j->m_bodyA;
j->m_edgeB.prev = NULL;
j->m_edgeB.next = j->m_bodyB->m_jointList;
if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB;
j->m_bodyB->m_jointList = &j->m_edgeB;
b2Body* bodyA = def->bodyA;
b2Body* bodyB = def->bodyB;
// If the joint prevents collisions, then flag any contacts for filtering.
if (def->collideConnected == false)
{
b2ContactEdge* edge = bodyB->GetContactList();
while (edge)
{
if (edge->other == bodyA)
{
// Flag the contact for filtering at the next time step (where either
// body is awake).
edge->contact->FlagForFiltering();
}
edge = edge->next;
}
}
// Note: creating a joint doesn't wake the bodies.
return j;
}
void b2World::DestroyJoint(b2Joint* j)
{
b2Assert(IsLocked() == false);
if (IsLocked())
{
return;
}
bool collideConnected = j->m_collideConnected;
// Remove from the doubly linked list.
if (j->m_prev)
{
j->m_prev->m_next = j->m_next;
}
if (j->m_next)
{
j->m_next->m_prev = j->m_prev;
}
if (j == m_jointList)
{
m_jointList = j->m_next;
}
// Disconnect from island graph.
b2Body* bodyA = j->m_bodyA;
b2Body* bodyB = j->m_bodyB;
// Wake up connected bodies.
bodyA->SetAwake(true);
bodyB->SetAwake(true);
// Remove from body 1.
if (j->m_edgeA.prev)
{
j->m_edgeA.prev->next = j->m_edgeA.next;
}
if (j->m_edgeA.next)
{
j->m_edgeA.next->prev = j->m_edgeA.prev;
}
if (&j->m_edgeA == bodyA->m_jointList)
{
bodyA->m_jointList = j->m_edgeA.next;
}
j->m_edgeA.prev = NULL;
j->m_edgeA.next = NULL;
// Remove from body 2
if (j->m_edgeB.prev)
{
j->m_edgeB.prev->next = j->m_edgeB.next;
}
if (j->m_edgeB.next)
{
j->m_edgeB.next->prev = j->m_edgeB.prev;
}
if (&j->m_edgeB == bodyB->m_jointList)
{
bodyB->m_jointList = j->m_edgeB.next;
}
j->m_edgeB.prev = NULL;
j->m_edgeB.next = NULL;
b2Joint::Destroy(j, &m_blockAllocator);
b2Assert(m_jointCount > 0);
--m_jointCount;
// If the joint prevents collisions, then flag any contacts for filtering.
if (collideConnected == false)
{
b2ContactEdge* edge = bodyB->GetContactList();
while (edge)
{
if (edge->other == bodyA)
{
// Flag the contact for filtering at the next time step (where either
// body is awake).
edge->contact->FlagForFiltering();
}
edge = edge->next;
}
}
}
//
void b2World::SetAllowSleeping(bool flag)
{
if (flag == m_allowSleep)
{
return;
}
m_allowSleep = flag;
if (m_allowSleep == false)
{
for (b2Body* b = m_bodyList; b; b = b->m_next)
{
b->SetAwake(true);
}
}
}
// Find islands, integrate and solve constraints, solve position constraints
void b2World::Solve(const b2TimeStep& step)
{
m_profile.solveInit = 0.0f;
m_profile.solveVelocity = 0.0f;
m_profile.solvePosition = 0.0f;
// Size the island for the worst case.
b2Island island(m_bodyCount,
m_contactManager.m_contactCount,
m_jointCount,
&m_stackAllocator,
m_contactManager.m_contactListener);
// Clear all the island flags.
for (b2Body* b = m_bodyList; b; b = b->m_next)
{
b->m_flags &= ~b2Body::e_islandFlag;
}
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
{
c->m_flags &= ~b2Contact::e_islandFlag;
}
for (b2Joint* j = m_jointList; j; j = j->m_next)
{
j->m_islandFlag = false;
}
// Build and simulate all awake islands.
int32 stackSize = m_bodyCount;
b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));
for (b2Body* seed = m_bodyList; seed; seed = seed->m_next)
{
if (seed->m_flags & b2Body::e_islandFlag)
{
continue;
}
if (seed->IsAwake() == false || seed->IsActive() == false)
{
continue;
}
// The seed can be dynamic or kinematic.
if (seed->GetType() == b2_staticBody)
{
continue;
}
// Reset island and stack.
island.Clear();
int32 stackCount = 0;
stack[stackCount++] = seed;
seed->m_flags |= b2Body::e_islandFlag;
// Perform a depth first search (DFS) on the constraint graph.
while (stackCount > 0)
{
// Grab the next body off the stack and add it to the island.
b2Body* b = stack[--stackCount];
b2Assert(b->IsActive() == true);
island.Add(b);
// Make sure the body is awake.
b->SetAwake(true);
// To keep islands as small as possible, we don't
// propagate islands across static bodies.
if (b->GetType() == b2_staticBody)
{
continue;
}
// Search all contacts connected to this body.
for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next)
{
b2Contact* contact = ce->contact;
// Has this contact already been added to an island?
if (contact->m_flags & b2Contact::e_islandFlag)
{
continue;
}
// Is this contact solid and touching?
if (contact->IsEnabled() == false ||
contact->IsTouching() == false)
{
continue;
}
// Skip sensors.
bool sensorA = contact->m_fixtureA->m_isSensor;
bool sensorB = contact->m_fixtureB->m_isSensor;
if (sensorA || sensorB)
{
continue;
}
island.Add(contact);
contact->m_flags |= b2Contact::e_islandFlag;
b2Body* other = ce->other;
// Was the other body already added to this island?
if (other->m_flags & b2Body::e_islandFlag)
{
continue;
}
b2Assert(stackCount < stackSize);
stack[stackCount++] = other;
other->m_flags |= b2Body::e_islandFlag;
}
// Search all joints connect to this body.
for (b2JointEdge* je = b->m_jointList; je; je = je->next)
{
if (je->joint->m_islandFlag == true)
{
continue;
}
b2Body* other = je->other;
// Don't simulate joints connected to inactive bodies.
if (other->IsActive() == false)
{
continue;
}
island.Add(je->joint);
je->joint->m_islandFlag = true;
if (other->m_flags & b2Body::e_islandFlag)
{
continue;
}
b2Assert(stackCount < stackSize);
stack[stackCount++] = other;
other->m_flags |= b2Body::e_islandFlag;
}
}
b2Profile profile;
island.Solve(&profile, step, m_gravity, m_allowSleep);
m_profile.solveInit += profile.solveInit;
m_profile.solveVelocity += profile.solveVelocity;
m_profile.solvePosition += profile.solvePosition;
// Post solve cleanup.
for (int32 i = 0; i < island.m_bodyCount; ++i)
{
// Allow static bodies to participate in other islands.
b2Body* b = island.m_bodies[i];
if (b->GetType() == b2_staticBody)
{
b->m_flags &= ~b2Body::e_islandFlag;
}
}
}
m_stackAllocator.Free(stack);
{
b2Timer timer;
// Synchronize fixtures, check for out of range bodies.
for (b2Body* b = m_bodyList; b; b = b->GetNext())
{
// If a body was not in an island then it did not move.
if ((b->m_flags & b2Body::e_islandFlag) == 0)
{
continue;
}
if (b->GetType() == b2_staticBody)
{
continue;
}
// Update fixtures (for broad-phase).
b->SynchronizeFixtures();
}
// Look for new contacts.
m_contactManager.FindNewContacts();
m_profile.broadphase = timer.GetMilliseconds();
}
}
// Find TOI contacts and solve them.
void b2World::SolveTOI(const b2TimeStep& step)
{
b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener);
if (m_stepComplete)
{
for (b2Body* b = m_bodyList; b; b = b->m_next)
{
b->m_flags &= ~b2Body::e_islandFlag;
b->m_sweep.alpha0 = 0.0f;
}
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
{
// Invalidate TOI
c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
c->m_toiCount = 0;
c->m_toi = 1.0f;
}
}
// Find TOI events and solve them.
for (;;)
{
// Find the first TOI.
b2Contact* minContact = NULL;
float32 minAlpha = 1.0f;
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
{
// Is this contact disabled?
if (c->IsEnabled() == false)
{
continue;
}
// Prevent excessive sub-stepping.
if (c->m_toiCount > b2_maxSubSteps)
{
continue;
}
float32 alpha = 1.0f;
if (c->m_flags & b2Contact::e_toiFlag)
{
// This contact has a valid cached TOI.
alpha = c->m_toi;
}
else
{
b2Fixture* fA = c->GetFixtureA();
b2Fixture* fB = c->GetFixtureB();
// Is there a sensor?
if (fA->IsSensor() || fB->IsSensor())
{
continue;
}
b2Body* bA = fA->GetBody();
b2Body* bB = fB->GetBody();
b2BodyType typeA = bA->m_type;
b2BodyType typeB = bB->m_type;
b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody);
bool activeA = bA->IsAwake() && typeA != b2_staticBody;
bool activeB = bB->IsAwake() && typeB != b2_staticBody;
// Is at least one body active (awake and dynamic or kinematic)?
if (activeA == false && activeB == false)
{
continue;
}
bool collideA = bA->IsBullet() || typeA != b2_dynamicBody;
bool collideB = bB->IsBullet() || typeB != b2_dynamicBody;
// Are these two non-bullet dynamic bodies?
if (collideA == false && collideB == false)
{
continue;
}
// Compute the TOI for this contact.
// Put the sweeps onto the same time interval.
float32 alpha0 = bA->m_sweep.alpha0;
if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0)
{
alpha0 = bB->m_sweep.alpha0;
bA->m_sweep.Advance(alpha0);
}
else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0)
{
alpha0 = bA->m_sweep.alpha0;
bB->m_sweep.Advance(alpha0);
}
b2Assert(alpha0 < 1.0f);
int32 indexA = c->GetChildIndexA();
int32 indexB = c->GetChildIndexB();
// Compute the time of impact in interval [0, minTOI]
b2TOIInput input;
input.proxyA.Set(fA->GetShape(), indexA);
input.proxyB.Set(fB->GetShape(), indexB);
input.sweepA = bA->m_sweep;
input.sweepB = bB->m_sweep;
input.tMax = 1.0f;
b2TOIOutput output;
b2TimeOfImpact(&output, &input);
// Beta is the fraction of the remaining portion of the .
float32 beta = output.t;
if (output.state == b2TOIOutput::e_touching)
{
alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
}
else
{
alpha = 1.0f;
}
c->m_toi = alpha;
c->m_flags |= b2Contact::e_toiFlag;
}
if (alpha < minAlpha)
{
// This is the minimum TOI found so far.
minContact = c;
minAlpha = alpha;
}
}
if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha)
{
// No more TOI events. Done!
m_stepComplete = true;
break;
}
// Advance the bodies to the TOI.
b2Fixture* fA = minContact->GetFixtureA();
b2Fixture* fB = minContact->GetFixtureB();
b2Body* bA = fA->GetBody();
b2Body* bB = fB->GetBody();
b2Sweep backup1 = bA->m_sweep;
b2Sweep backup2 = bB->m_sweep;
bA->Advance(minAlpha);
bB->Advance(minAlpha);
// The TOI contact likely has some new contact points.
minContact->Update(m_contactManager.m_contactListener);
minContact->m_flags &= ~b2Contact::e_toiFlag;
++minContact->m_toiCount;
// Is the contact solid?
if (minContact->IsEnabled() == false || minContact->IsTouching() == false)
{
// Restore the sweeps.
minContact->SetEnabled(false);
bA->m_sweep = backup1;
bB->m_sweep = backup2;
bA->SynchronizeTransform();
bB->SynchronizeTransform();
continue;
}
bA->SetAwake(true);
bB->SetAwake(true);
// Build the island
island.Clear();
island.Add(bA);
island.Add(bB);
island.Add(minContact);
bA->m_flags |= b2Body::e_islandFlag;
bB->m_flags |= b2Body::e_islandFlag;
minContact->m_flags |= b2Contact::e_islandFlag;
// Get contacts on bodyA and bodyB.
b2Body* bodies[2] = {bA, bB};
for (int32 i = 0; i < 2; ++i)
{
b2Body* body = bodies[i];
if (body->m_type == b2_dynamicBody)
{
for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
{
if (island.m_bodyCount == island.m_bodyCapacity)
{
break;
}
if (island.m_contactCount == island.m_contactCapacity)
{
break;
}
b2Contact* contact = ce->contact;
// Has this contact already been added to the island?
if (contact->m_flags & b2Contact::e_islandFlag)
{
continue;
}
// Only add static, kinematic, or bullet bodies.
b2Body* other = ce->other;
if (other->m_type == b2_dynamicBody &&
body->IsBullet() == false && other->IsBullet() == false)
{
continue;
}
// Skip sensors.
bool sensorA = contact->m_fixtureA->m_isSensor;
bool sensorB = contact->m_fixtureB->m_isSensor;
if (sensorA || sensorB)
{
continue;
}
// Tentatively advance the body to the TOI.
b2Sweep backup = other->m_sweep;
if ((other->m_flags & b2Body::e_islandFlag) == 0)
{
other->Advance(minAlpha);
}
// Update the contact points
contact->Update(m_contactManager.m_contactListener);
// Was the contact disabled by the user?
if (contact->IsEnabled() == false)
{
other->m_sweep = backup;
other->SynchronizeTransform();
continue;
}
// Are there contact points?
if (contact->IsTouching() == false)
{
other->m_sweep = backup;
other->SynchronizeTransform();
continue;
}
// Add the contact to the island
contact->m_flags |= b2Contact::e_islandFlag;
island.Add(contact);
// Has the other body already been added to the island?
if (other->m_flags & b2Body::e_islandFlag)
{
continue;
}
// Add the other body to the island.
other->m_flags |= b2Body::e_islandFlag;
if (other->m_type != b2_staticBody)
{
other->SetAwake(true);
}
island.Add(other);
}
}
}
b2TimeStep subStep;
subStep.dt = (1.0f - minAlpha) * step.dt;
subStep.inv_dt = 1.0f / subStep.dt;
subStep.dtRatio = 1.0f;
subStep.positionIterations = 20;
subStep.velocityIterations = step.velocityIterations;
subStep.warmStarting = false;
island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex);
// Reset island flags and synchronize broad-phase proxies.
for (int32 i = 0; i < island.m_bodyCount; ++i)
{
b2Body* body = island.m_bodies[i];
body->m_flags &= ~b2Body::e_islandFlag;
if (body->m_type != b2_dynamicBody)
{
continue;
}
body->SynchronizeFixtures();
// Invalidate all contact TOIs on this displaced body.
for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
{
ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
}
}
// Commit fixture proxy movements to the broad-phase so that new contacts are created.
// Also, some contacts can be destroyed.
m_contactManager.FindNewContacts();
if (m_subStepping)
{
m_stepComplete = false;
break;
}
}
}
void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations)
{
b2Timer stepTimer;
// If new fixtures were added, we need to find the new contacts.
if (m_flags & e_newFixture)
{
m_contactManager.FindNewContacts();
m_flags &= ~e_newFixture;
}
m_flags |= e_locked;
b2TimeStep step;
step.dt = dt;
step.velocityIterations = velocityIterations;
step.positionIterations = positionIterations;
if (dt > 0.0f)
{
step.inv_dt = 1.0f / dt;
}
else
{
step.inv_dt = 0.0f;
}
step.dtRatio = m_inv_dt0 * dt;
step.warmStarting = m_warmStarting;
// Update contacts. This is where some contacts are destroyed.
{
b2Timer timer;
m_contactManager.Collide();
m_profile.collide = timer.GetMilliseconds();
}
// Integrate velocities, solve velocity constraints, and integrate positions.
if (m_stepComplete && step.dt > 0.0f)
{
b2Timer timer;
Solve(step);
m_profile.solve = timer.GetMilliseconds();
}
// Handle TOI events.
if (m_continuousPhysics && step.dt > 0.0f)
{
b2Timer timer;
SolveTOI(step);
m_profile.solveTOI = timer.GetMilliseconds();
}
if (step.dt > 0.0f)
{
m_inv_dt0 = step.inv_dt;
}
if (m_flags & e_clearForces)
{
ClearForces();
}
m_flags &= ~e_locked;
m_profile.step = stepTimer.GetMilliseconds();
}
void b2World::ClearForces()
{
for (b2Body* body = m_bodyList; body; body = body->GetNext())
{
body->m_force.SetZero();
body->m_torque = 0.0f;
}
}
struct b2WorldQueryWrapper
{
bool QueryCallback(int32 proxyId)
{
b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId);
return callback->ReportFixture(proxy->fixture);
}
const b2BroadPhase* broadPhase;
b2QueryCallback* callback;
};
void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const
{
b2WorldQueryWrapper wrapper;
wrapper.broadPhase = &m_contactManager.m_broadPhase;
wrapper.callback = callback;
m_contactManager.m_broadPhase.Query(&wrapper, aabb);
}
struct b2WorldRayCastWrapper
{
float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)
{
void* userData = broadPhase->GetUserData(proxyId);
b2FixtureProxy* proxy = (b2FixtureProxy*)userData;
b2Fixture* fixture = proxy->fixture;
int32 index = proxy->childIndex;
b2RayCastOutput output;
bool hit = fixture->RayCast(&output, input, index);
if (hit)
{
float32 fraction = output.fraction;
b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2;
return callback->ReportFixture(fixture, point, output.normal, fraction);
}
return input.maxFraction;
}
const b2BroadPhase* broadPhase;
b2RayCastCallback* callback;
};
void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const
{
b2WorldRayCastWrapper wrapper;
wrapper.broadPhase = &m_contactManager.m_broadPhase;
wrapper.callback = callback;
b2RayCastInput input;
input.maxFraction = 1.0f;
input.p1 = point1;
input.p2 = point2;
m_contactManager.m_broadPhase.RayCast(&wrapper, input);
}
void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color)
{
switch (fixture->GetType())
{
case b2Shape::e_circle:
{
b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
b2Vec2 center = b2Mul(xf, circle->m_p);
float32 radius = circle->m_radius;
b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f));
m_debugDraw->DrawSolidCircle(center, radius, axis, color);
}
break;
case b2Shape::e_edge:
{
b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape();
b2Vec2 v1 = b2Mul(xf, edge->m_vertex1);
b2Vec2 v2 = b2Mul(xf, edge->m_vertex2);
m_debugDraw->DrawSegment(v1, v2, color);
}
break;
case b2Shape::e_chain:
{
b2ChainShape* chain = (b2ChainShape*)fixture->GetShape();
int32 count = chain->m_count;
const b2Vec2* vertices = chain->m_vertices;
b2Vec2 v1 = b2Mul(xf, vertices[0]);
for (int32 i = 1; i < count; ++i)
{
b2Vec2 v2 = b2Mul(xf, vertices[i]);
m_debugDraw->DrawSegment(v1, v2, color);
m_debugDraw->DrawCircle(v1, 0.05f, color);
v1 = v2;
}
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
int32 vertexCount = poly->m_count;
b2Assert(vertexCount <= b2_maxPolygonVertices);
b2Vec2 vertices[b2_maxPolygonVertices];
for (int32 i = 0; i < vertexCount; ++i)
{
vertices[i] = b2Mul(xf, poly->m_vertices[i]);
}
m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color);
}
break;
default:
break;
}
}
void b2World::DrawJoint(b2Joint* joint)
{
b2Body* bodyA = joint->GetBodyA();
b2Body* bodyB = joint->GetBodyB();
const b2Transform& xf1 = bodyA->GetTransform();
const b2Transform& xf2 = bodyB->GetTransform();
b2Vec2 x1 = xf1.p;
b2Vec2 x2 = xf2.p;
b2Vec2 p1 = joint->GetAnchorA();
b2Vec2 p2 = joint->GetAnchorB();
b2Color color(0.5f, 0.8f, 0.8f);
switch (joint->GetType())
{
case e_distanceJoint:
m_debugDraw->DrawSegment(p1, p2, color);
break;
case e_pulleyJoint:
{
b2PulleyJoint* pulley = (b2PulleyJoint*)joint;
b2Vec2 s1 = pulley->GetGroundAnchorA();
b2Vec2 s2 = pulley->GetGroundAnchorB();
m_debugDraw->DrawSegment(s1, p1, color);
m_debugDraw->DrawSegment(s2, p2, color);
m_debugDraw->DrawSegment(s1, s2, color);
}
break;
case e_mouseJoint:
// don't draw this
break;
default:
m_debugDraw->DrawSegment(x1, p1, color);
m_debugDraw->DrawSegment(p1, p2, color);
m_debugDraw->DrawSegment(x2, p2, color);
}
}
void b2World::DrawDebugData()
{
if (m_debugDraw == NULL)
{
return;
}
uint32 flags = m_debugDraw->GetFlags();
if (flags & b2Draw::e_shapeBit)
{
for (b2Body* b = m_bodyList; b; b = b->GetNext())
{
const b2Transform& xf = b->GetTransform();
for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
{
if (b->IsActive() == false)
{
DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f));
}
else if (b->GetType() == b2_staticBody)
{
DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f));
}
else if (b->GetType() == b2_kinematicBody)
{
DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f));
}
else if (b->IsAwake() == false)
{
DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f));
}
else
{
DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f));
}
}
}
}
if (flags & b2Draw::e_jointBit)
{
for (b2Joint* j = m_jointList; j; j = j->GetNext())
{
DrawJoint(j);
}
}
if (flags & b2Draw::e_pairBit)
{
b2Color color(0.3f, 0.9f, 0.9f);
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext())
{
//b2Fixture* fixtureA = c->GetFixtureA();
//b2Fixture* fixtureB = c->GetFixtureB();
//b2Vec2 cA = fixtureA->GetAABB().GetCenter();
//b2Vec2 cB = fixtureB->GetAABB().GetCenter();
//m_debugDraw->DrawSegment(cA, cB, color);
}
}
if (flags & b2Draw::e_aabbBit)
{
b2Color color(0.9f, 0.3f, 0.9f);
b2BroadPhase* bp = &m_contactManager.m_broadPhase;
for (b2Body* b = m_bodyList; b; b = b->GetNext())
{
if (b->IsActive() == false)
{
continue;
}
for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
{
for (int32 i = 0; i < f->m_proxyCount; ++i)
{
b2FixtureProxy* proxy = f->m_proxies + i;
b2AABB aabb = bp->GetFatAABB(proxy->proxyId);
b2Vec2 vs[4];
vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y);
vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y);
vs[2].Set(aabb.upperBound.x, aabb.upperBound.y);
vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y);
m_debugDraw->DrawPolygon(vs, 4, color);
}
}
}
}
if (flags & b2Draw::e_centerOfMassBit)
{
for (b2Body* b = m_bodyList; b; b = b->GetNext())
{
b2Transform xf = b->GetTransform();
xf.p = b->GetWorldCenter();
m_debugDraw->DrawTransform(xf);
}
}
}
int32 b2World::GetProxyCount() const
{
return m_contactManager.m_broadPhase.GetProxyCount();
}
int32 b2World::GetTreeHeight() const
{
return m_contactManager.m_broadPhase.GetTreeHeight();
}
int32 b2World::GetTreeBalance() const
{
return m_contactManager.m_broadPhase.GetTreeBalance();
}
float32 b2World::GetTreeQuality() const
{
return m_contactManager.m_broadPhase.GetTreeQuality();
}
void b2World::ShiftOrigin(const b2Vec2& newOrigin)
{
b2Assert((m_flags & e_locked) == 0);
if ((m_flags & e_locked) == e_locked)
{
return;
}
for (b2Body* b = m_bodyList; b; b = b->m_next)
{
b->m_xf.p -= newOrigin;
b->m_sweep.c0 -= newOrigin;
b->m_sweep.c -= newOrigin;
}
for (b2Joint* j = m_jointList; j; j = j->m_next)
{
j->ShiftOrigin(newOrigin);
}
m_contactManager.m_broadPhase.ShiftOrigin(newOrigin);
}
void b2World::Dump()
{
if ((m_flags & e_locked) == e_locked)
{
return;
}
b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y);
b2Log("m_world->SetGravity(g);\n");
b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount);
b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount);
int32 i = 0;
for (b2Body* b = m_bodyList; b; b = b->m_next)
{
b->m_islandIndex = i;
b->Dump();
++i;
}
i = 0;
for (b2Joint* j = m_jointList; j; j = j->m_next)
{
j->m_index = i;
++i;
}
// First pass on joints, skip gear joints.
for (b2Joint* j = m_jointList; j; j = j->m_next)
{
if (j->m_type == e_gearJoint)
{
continue;
}
b2Log("{\n");
j->Dump();
b2Log("}\n");
}
// Second pass on joints, only gear joints.
for (b2Joint* j = m_jointList; j; j = j->m_next)
{
if (j->m_type != e_gearJoint)
{
continue;
}
b2Log("{\n");
j->Dump();
b2Log("}\n");
}
b2Log("b2Free(joints);\n");
b2Log("b2Free(bodies);\n");
b2Log("joints = NULL;\n");
b2Log("bodies = NULL;\n");
}
================================================
FILE: app/src/main/cpp/b2WorldCallbacks.cpp
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as 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 "isEngine/ext_lib/Box2D/Dynamics/b2WorldCallbacks.h"
#include "isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h"
// Return true if contact calculations should be performed between these two shapes.
// If you implement your own collision filter you may want to build from this implementation.
bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
{
const b2Filter& filterA = fixtureA->GetFilterData();
const b2Filter& filterB = fixtureB->GetFilterData();
if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)
{
return filterA.groupIndex > 0;
}
bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
return collide;
}
================================================
FILE: app/src/main/cpp/basicSFMLmain.cpp
================================================
#include "isEngine/core/GameEngine.h"
namespace is
{
bool GameEngine::basicSFMLmain()
{
////////////////////////////////////////////////////////////
// WINDOW CREATION
////////////////////////////////////////////////////////////
#if defined(__ANDROID__)
m_window.create(sf::VideoMode::getDesktopMode(), "");
#else
m_window.create(sf::VideoMode(is::GameConfig::WINDOW_WIDTH,
is::GameConfig::WINDOW_HEIGHT),
is::GameConfig::GAME_NAME,
is::getWindowStyle());
// load application icon
sf::Image iconTex;
if (!iconTex.loadFromFile(is::GameConfig::GUI_DIR + "icon.png")) return false;
#if !defined (IS_ENGINE_SDL_2) && !defined(IS_ENGINE_VS)
m_window.setIcon(32, 32, iconTex.getPixelsPtr());
#endif
#endif // defined
setFPS(m_window, is::GameConfig::FPS); // set frames per second (FPS)
sf::View m_view(sf::Vector2f(is::GameConfig::VIEW_WIDTH / 2.f, is::GameConfig::VIEW_HEIGHT / 2.f), sf::Vector2f(is::GameConfig::VIEW_WIDTH, is::GameConfig::VIEW_HEIGHT));
m_window.setView(m_view);
////////////////////////////////////////////////////////////
// INITIALIZATION
////////////////////////////////////////////////////////////
// is::GameConfig::MUSIC_DIR, is::GameConfig::GUI_DIR, is::GameConfig::FONT_DIR
// Are variables that return the path of resources located in the "assets" folder
// Load music buffer
sf::SoundBuffer musicBuffer; // Music is played in the render loop. See line 172
is::loadSFMLSoundBuffer(musicBuffer, is::GameConfig::MUSIC_DIR + "game_music.wav");
sf::Sound music(musicBuffer);
music.play();
// Load texture
sf::Texture texture;
is::loadSFMLTexture(texture, is::GameConfig::GUI_DIR + "icon.png");
// Create Sprite and set Texture
sf::Sprite image(texture);
is::centerSFMLObj(image); // Allows to center the sprite
image.setPosition(is::GameConfig::VIEW_WIDTH / 2.f, is::GameConfig::VIEW_HEIGHT / 2.f);
// Load font
sf::Font font;
is::loadSFMLFont(font, is::GameConfig::FONT_DIR + "font_system.ttf", 16); // When you develop for the Web you must define
// the size that the texts will have with this font
// Create text and set font
sf::Text text;
text.setFont(font);
text.setString("Hello World !");
is::centerSFMLObj(text); // Allows to center the text
text.setPosition(is::GameConfig::VIEW_WIDTH / 2.f, 64.f);
bool focus = true; // Doesn't work when you're on the web version
////////////////////////////////////////////////////////////
// RENDER LOOP //
////////////////////////////////////////////////////////////
// This starts the render loop. //
// Don't touch unless you know what you're doing. //
#if !defined(IS_ENGINE_HTML_5) //
while (m_window.isOpen() //
#ifdef __SWITCH__ //
&& appletMainLoop() //
#endif //
) //
#else //
EM_ASM(console.log("Start successfully!");, 0); //
execMainLoop([&] //
{ //
if (emscripten_run_script_int("Module.syncdone") == 1)//
#endif //
{ //
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// EVENT
////////////////////////////////////////////////////////////
sf::Vector2i mousePosition(-1, -1); // Allows to get mouse or touch position
// A negative value means that no position has been recorded
sf::Event event;
while (m_window.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
m_window.close();
break;
#if (defined(__ANDROID__) || defined(__SWITCH__))
case sf::Event::TouchBegan:
if (event.touch.finger == 0)
{
mousePosition.x = is::getCursor(m_window, 0).x;
mousePosition.y = is::getCursor(m_window, 0).y;
is::vibrate(100);
}
break;
#else
case sf::Event::MouseButtonPressed:
mousePosition.x = is::getCursor(m_window).x;
mousePosition.y = is::getCursor(m_window).y;
break;
#endif // defined
case sf::Event::LostFocus:
focus = false; //don't draw, if the window is not shown
is::showLog("LOST FOCUS!");
break;
case sf::Event::GainedFocus:
focus = true; //draw if the window is shown
is::showLog("GAINED FOCUS!");
break;
default: break;
}
}
////////////////////////////////////////////////////////////
// UPDATE OBJECTS
////////////////////////////////////////////////////////////
if (mousePosition.x != -1 && mousePosition.y != -1) image.setPosition(mousePosition.x, mousePosition.y);
////////////////////////////////////////////////////////////
// DRAW OBJECTS
////////////////////////////////////////////////////////////
if (focus)
{
m_window.clear(sf::Color::Blue);
m_window.draw(text);
m_window.draw(image);
m_window.display();
}
}
////////////////////////////////////////////////////////////
// Don't touch unless you know what you're doing. //
#if defined(IS_ENGINE_HTML_5) //
}); //
#endif //
////////////////////////////////////////////////////////////
return true;
}
}
================================================
FILE: app/src/main/cpp/isEngine/core/ActivityController.h
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2025 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ACTIVITYCONTROLLER_H_INCLUDED
#define ACTIVITYCONTROLLER_H_INCLUDED
#include "../../app_src/activity/GameActivity.h"
class ActivityController
{
public:
ActivityController(is::GameSystemExtended &gameSysExt):
m_gameSysExt(gameSysExt)
{
m_gameActivity = std::make_shared(m_gameSysExt);
}
void update()
{
m_gameActivity->onUpdate();
}
void draw()
{
m_gameActivity->onDraw();
if (m_gameActivity->m_changeActivity)
{
m_gameActivity.reset();
m_gameActivity = std::make_shared(m_gameSysExt);
}
}
private:
is::GameSystemExtended &m_gameSysExt;
std::shared_ptr m_gameActivity;
};
#endif // ACTIVITYCONTROLLER_H_INCLUDED
================================================
FILE: app/src/main/cpp/isEngine/core/GameEngine.h
================================================
/*
is::Engine (Infinity Solutions Engine)
Copyright (C) 2018-2025 Is Daouda
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef GAMEENGINE_H_INCLUDED
#define GAMEENGINE_H_INCLUDED
#include "ActivityController.h"
#include
////////////////////////////////////////////////////////////
// PC version code
#if !defined(__ANDROID__)
#if !defined(SFML_SYSTEM_LINUX) && !defined(IS_ENGINE_HTML_5) && !defined(IS_ENGINE_LINUX) && !defined(IS_ENGINE_SWITCH)
#include
#else
#include
#endif // defined
#endif // defined
////////////////////////////////////////////////////////////
namespace is
{
////////////////////////////////////////////////////////////
/// \brief Class to operate the entire game system
///
/// It allows the interconnection of different engine components
////////////////////////////////////////////////////////////
class GameEngine
{
private:
sf::RenderWindow m_window;
is::GameSystemExtended m_gameSysExt;
public:
GameEngine();
~GameEngine();
/// Initialize game engine
void initEngine();
#if defined(IS_ENGINE_HTML_5)
/// Allow to launch main loop
void execMainLoop(std::function loop);
void execMainLoop(std::function loop);
#endif
/// Starts the engine rendering loop
bool play();
////////////////////////////////////////////////////////////
/// \brief Starts the SFML classic rendering loop
///
/// Useful for implementing a custom rendering loop to facilitate
/// the integration of other projects with the engine
////////////////////////////////////////////////////////////
bool basicSFMLmain();
/// return Render Window
sf::RenderWindow& getRenderWindow() {return m_window;}
};
}
#endif // GAMEENGINE_H_INCLUDED
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Box2D.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX2D_H
#define BOX2D_H
/**
\mainpage Box2D API Documentation
\section intro_sec Getting Started
For documentation please see http://box2d.org/documentation.html
For discussion please visit http://box2d.org/forum
*/
// These include files constitute the main Box2D API
#include "Common/b2Settings.h"
#include "Common/b2Draw.h"
#include "Common/b2Timer.h"
#include "Collision/Shapes/b2CircleShape.h"
#include "Collision/Shapes/b2EdgeShape.h"
#include "Collision/Shapes/b2ChainShape.h"
#include "Collision/Shapes/b2PolygonShape.h"
#include "Collision/b2BroadPhase.h"
#include "Collision/b2Distance.h"
#include "Collision/b2DynamicTree.h"
#include "Collision/b2TimeOfImpact.h"
#include "Dynamics/b2Body.h"
#include "Dynamics/b2Fixture.h"
#include "Dynamics/b2WorldCallbacks.h"
#include "Dynamics/b2TimeStep.h"
#include "Dynamics/b2World.h"
#include "Dynamics/Contacts/b2Contact.h"
#include "Dynamics/Joints/b2DistanceJoint.h"
#include "Dynamics/Joints/b2FrictionJoint.h"
#include "Dynamics/Joints/b2GearJoint.h"
#include "Dynamics/Joints/b2MotorJoint.h"
#include "Dynamics/Joints/b2MouseJoint.h"
#include "Dynamics/Joints/b2PrismaticJoint.h"
#include "Dynamics/Joints/b2PulleyJoint.h"
#include "Dynamics/Joints/b2RevoluteJoint.h"
#include "Dynamics/Joints/b2RopeJoint.h"
#include "Dynamics/Joints/b2WeldJoint.h"
#include "Dynamics/Joints/b2WheelJoint.h"
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/Shapes/b2ChainShape.h
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_SHAPE_H
#define B2_CHAIN_SHAPE_H
#include "b2Shape.h"
class b2EdgeShape;
/// A chain shape is a free form sequence of line segments.
/// The chain has two-sided collision, so you can use inside and outside collision.
/// Therefore, you may use any winding order.
/// Since there may be many vertices, they are allocated using b2Alloc.
/// Connectivity information is used to create smooth collisions.
/// WARNING: The chain will not collide properly if there are self-intersections.
class b2ChainShape : public b2Shape
{
public:
b2ChainShape();
/// The destructor frees the vertices using b2Free.
~b2ChainShape();
/// Create a loop. This automatically adjusts connectivity.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateLoop(const b2Vec2* vertices, int32 count);
/// Create a chain with isolated end vertices.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateChain(const b2Vec2* vertices, int32 count);
/// Establish connectivity to a vertex that precedes the first vertex.
/// Don't call this for loops.
void SetPrevVertex(const b2Vec2& prevVertex);
/// Establish connectivity to a vertex that follows the last vertex.
/// Don't call this for loops.
void SetNextVertex(const b2Vec2& nextVertex);
/// Implement b2Shape. Vertices are cloned using b2Alloc.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Get a child edge.
void GetChildEdge(b2EdgeShape* edge, int32 index) const;
/// This always return false.
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// Chains have zero mass.
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// The vertices. Owned by this class.
b2Vec2* m_vertices;
/// The vertex count.
int32 m_count;
b2Vec2 m_prevVertex, m_nextVertex;
bool m_hasPrevVertex, m_hasNextVertex;
};
inline b2ChainShape::b2ChainShape()
{
m_type = e_chain;
m_radius = b2_polygonRadius;
m_vertices = NULL;
m_count = 0;
m_hasPrevVertex = false;
m_hasNextVertex = false;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/Shapes/b2CircleShape.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_SHAPE_H
#define B2_CIRCLE_SHAPE_H
#include "b2Shape.h"
/// A circle shape.
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Implement b2Shape.
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const { return 1; }
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
/// Position
b2Vec2 m_p;
};
inline b2CircleShape::b2CircleShape()
{
m_type = e_circle;
m_radius = 0.0f;
m_p.SetZero();
}
inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return 0;
}
inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return m_p;
}
inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
{
B2_NOT_USED(index);
b2Assert(index == 0);
return m_p;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/Shapes/b2EdgeShape.h
================================================
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_SHAPE_H
#define B2_EDGE_SHAPE_H
#include "b2Shape.h"
/// A line segment (edge) shape. These can be connected in chains or loops
/// to other edge shapes. The connectivity information is used to ensure
/// correct contact normals.
class b2EdgeShape : public b2Shape
{
public:
b2EdgeShape();
/// Set this as an isolated edge.
void Set(const b2Vec2& v1, const b2Vec2& v2);
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// These are the edge vertices
b2Vec2 m_vertex1, m_vertex2;
/// Optional adjacent vertices. These are used for smooth collision.
b2Vec2 m_vertex0, m_vertex3;
bool m_hasVertex0, m_hasVertex3;
};
inline b2EdgeShape::b2EdgeShape()
{
m_type = e_edge;
m_radius = b2_polygonRadius;
m_vertex0.x = 0.0f;
m_vertex0.y = 0.0f;
m_vertex3.x = 0.0f;
m_vertex3.y = 0.0f;
m_hasVertex0 = false;
m_hasVertex3 = false;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/Shapes/b2PolygonShape.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_SHAPE_H
#define B2_POLYGON_SHAPE_H
#include "b2Shape.h"
/// A convex polygon. It is assumed that the interior of the polygon is to
/// the left of each edge.
/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
/// In most cases you should not need many vertices for a convex polygon.
class b2PolygonShape : public b2Shape
{
public:
b2PolygonShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Create a convex hull from the given array of local points.
/// The count must be in the range [3, b2_maxPolygonVertices].
/// @warning the points may be re-ordered, even if they form a convex polygon
/// @warning collinear points are handled but not removed. Collinear points
/// may lead to poor stacking behavior.
void Set(const b2Vec2* points, int32 count);
/// Build vertices to represent an axis-aligned box centered on the local origin.
/// @param hx the half-width.
/// @param hy the half-height.
void SetAsBox(float32 hx, float32 hy);
/// Build vertices to represent an oriented box.
/// @param hx the half-width.
/// @param hy the half-height.
/// @param center the center of the box in local coordinates.
/// @param angle the rotation of the box in local coordinates.
void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the vertex count.
int32 GetVertexCount() const { return m_count; }
/// Get a vertex by index.
const b2Vec2& GetVertex(int32 index) const;
/// Validate convexity. This is a very time consuming operation.
/// @returns true if valid
bool Validate() const;
b2Vec2 m_centroid;
b2Vec2 m_vertices[b2_maxPolygonVertices];
b2Vec2 m_normals[b2_maxPolygonVertices];
int32 m_count;
};
inline b2PolygonShape::b2PolygonShape()
{
m_type = e_polygon;
m_radius = b2_polygonRadius;
m_count = 0;
m_centroid.SetZero();
}
inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/Shapes/b2Shape.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_SHAPE_H
#define B2_SHAPE_H
#include "../../Common/b2BlockAllocator.h"
#include "../../Common/b2Math.h"
#include "../b2Collision.h"
/// This holds the mass data computed for a shape.
struct b2MassData
{
/// The mass of the shape, usually in kilograms.
float32 mass;
/// The position of the shape's centroid relative to the shape's origin.
b2Vec2 center;
/// The rotational inertia of the shape about the local origin.
float32 I;
};
/// A shape is used for collision detection. You can create a shape however you like.
/// Shapes used for simulation in b2World are created automatically when a b2Fixture
/// is created. Shapes may encapsulate a one or more child shapes.
class b2Shape
{
public:
enum Type
{
e_circle = 0,
e_edge = 1,
e_polygon = 2,
e_chain = 3,
e_typeCount = 4
};
virtual ~b2Shape() {}
/// Clone the concrete shape using the provided allocator.
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
/// Get the type of this shape. You can use this to down cast to the concrete shape.
/// @return the shape type.
Type GetType() const;
/// Get the number of child primitives.
virtual int32 GetChildCount() const = 0;
/// Test a point for containment in this shape. This only works for convex shapes.
/// @param xf the shape world transform.
/// @param p a point in world coordinates.
virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
/// Cast a ray against a child shape.
/// @param output the ray-cast results.
/// @param input the ray-cast input parameters.
/// @param transform the transform to be applied to the shape.
/// @param childIndex the child shape index
virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const = 0;
/// Given a transform, compute the associated axis aligned bounding box for a child shape.
/// @param aabb returns the axis aligned box.
/// @param xf the world transform of the shape.
/// @param childIndex the child shape
virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0;
/// Compute the mass properties of this shape using its dimensions and density.
/// The inertia tensor is computed about the local origin.
/// @param massData returns the mass data for this shape.
/// @param density the density in kilograms per meter squared.
virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;
Type m_type;
float32 m_radius;
};
inline b2Shape::Type b2Shape::GetType() const
{
return m_type;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/b2BroadPhase.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_BROAD_PHASE_H
#define B2_BROAD_PHASE_H
#include "../Common/b2Settings.h"
#include "b2Collision.h"
#include "b2DynamicTree.h"
#include
struct b2Pair
{
int32 proxyIdA;
int32 proxyIdB;
};
/// The broad-phase is used for computing pairs and performing volume queries and ray casts.
/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
/// It is up to the client to consume the new pairs and to track subsequent overlap.
class b2BroadPhase
{
public:
enum
{
e_nullProxy = -1
};
b2BroadPhase();
~b2BroadPhase();
/// Create a proxy with an initial AABB. Pairs are not reported until
/// UpdatePairs is called.
int32 CreateProxy(const b2AABB& aabb, void* userData);
/// Destroy a proxy. It is up to the client to remove any pairs.
void DestroyProxy(int32 proxyId);
/// Call MoveProxy as many times as you like, then when you are done
/// call UpdatePairs to finalized the proxy pairs (for your time step).
void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);
/// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
void TouchProxy(int32 proxyId);
/// Get the fat AABB for a proxy.
const b2AABB& GetFatAABB(int32 proxyId) const;
/// Get user data from a proxy. Returns NULL if the id is invalid.
void* GetUserData(int32 proxyId) const;
/// Test overlap of fat AABBs.
bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const;
/// Get the number of proxies.
int32 GetProxyCount() const;
/// Update the pairs. This results in pair callbacks. This can only add pairs.
template
void UpdatePairs(T* callback);
/// Query an AABB for overlapping proxies. The callback class
/// is called for each proxy that overlaps the supplied AABB.
template
void Query(T* callback, const b2AABB& aabb) const;
/// Ray-cast against the proxies in the tree. This relies on the callback
/// to perform a exact ray-cast in the case were the proxy contains a shape.
/// The callback also performs the any collision filtering. This has performance
/// roughly equal to k * log(n), where k is the number of collisions and n is the
/// number of proxies in the tree.
/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
/// @param callback a callback class that is called for each proxy that is hit by the ray.
template
void RayCast(T* callback, const b2RayCastInput& input) const;
/// Get the height of the embedded tree.
int32 GetTreeHeight() const;
/// Get the balance of the embedded tree.
int32 GetTreeBalance() const;
/// Get the quality metric of the embedded tree.
float32 GetTreeQuality() const;
/// Shift the world origin. Useful for large worlds.
/// The shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
private:
friend class b2DynamicTree;
void BufferMove(int32 proxyId);
void UnBufferMove(int32 proxyId);
bool QueryCallback(int32 proxyId);
b2DynamicTree m_tree;
int32 m_proxyCount;
int32* m_moveBuffer;
int32 m_moveCapacity;
int32 m_moveCount;
b2Pair* m_pairBuffer;
int32 m_pairCapacity;
int32 m_pairCount;
int32 m_queryProxyId;
};
/// This is used to sort pairs.
inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)
{
if (pair1.proxyIdA < pair2.proxyIdA)
{
return true;
}
if (pair1.proxyIdA == pair2.proxyIdA)
{
return pair1.proxyIdB < pair2.proxyIdB;
}
return false;
}
inline void* b2BroadPhase::GetUserData(int32 proxyId) const
{
return m_tree.GetUserData(proxyId);
}
inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const
{
const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA);
const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB);
return b2TestOverlap(aabbA, aabbB);
}
inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const
{
return m_tree.GetFatAABB(proxyId);
}
inline int32 b2BroadPhase::GetProxyCount() const
{
return m_proxyCount;
}
inline int32 b2BroadPhase::GetTreeHeight() const
{
return m_tree.GetHeight();
}
inline int32 b2BroadPhase::GetTreeBalance() const
{
return m_tree.GetMaxBalance();
}
inline float32 b2BroadPhase::GetTreeQuality() const
{
return m_tree.GetAreaRatio();
}
template
void b2BroadPhase::UpdatePairs(T* callback)
{
// Reset pair buffer
m_pairCount = 0;
// Perform tree queries for all moving proxies.
for (int32 i = 0; i < m_moveCount; ++i)
{
m_queryProxyId = m_moveBuffer[i];
if (m_queryProxyId == e_nullProxy)
{
continue;
}
// We have to query the tree with the fat AABB so that
// we don't fail to create a pair that may touch later.
const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId);
// Query tree, create pairs and add them pair buffer.
m_tree.Query(this, fatAABB);
}
// Reset move buffer
m_moveCount = 0;
// Sort the pair buffer to expose duplicates.
std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);
// Send the pairs back to the client.
int32 i = 0;
while (i < m_pairCount)
{
b2Pair* primaryPair = m_pairBuffer + i;
void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);
void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);
callback->AddPair(userDataA, userDataB);
++i;
// Skip any duplicate pairs.
while (i < m_pairCount)
{
b2Pair* pair = m_pairBuffer + i;
if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
{
break;
}
++i;
}
}
// Try to keep the tree balanced.
//m_tree.Rebalance(4);
}
template
inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
{
m_tree.Query(callback, aabb);
}
template
inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const
{
m_tree.RayCast(callback, input);
}
inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin)
{
m_tree.ShiftOrigin(newOrigin);
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/b2Collision.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_COLLISION_H
#define B2_COLLISION_H
#include "../Common/b2Math.h"
#include
/// @file
/// Structures and functions used for computing contact points, distance
/// queries, and TOI queries.
class b2Shape;
class b2CircleShape;
class b2EdgeShape;
class b2PolygonShape;
const uint8 b2_nullFeature = UCHAR_MAX;
/// The features that intersect to form the contact point
/// This must be 4 bytes or less.
struct b2ContactFeature
{
enum Type
{
e_vertex = 0,
e_face = 1
};
uint8 indexA; ///< Feature index on shapeA
uint8 indexB; ///< Feature index on shapeB
uint8 typeA; ///< The feature type on shapeA
uint8 typeB; ///< The feature type on shapeB
};
/// Contact ids to facilitate warm starting.
union b2ContactID
{
b2ContactFeature cf;
uint32 key; ///< Used to quickly compare contact ids.
};
/// A manifold point is a contact point belonging to a contact
/// manifold. It holds details related to the geometry and dynamics
/// of the contact points.
/// The local point usage depends on the manifold type:
/// -e_circles: the local center of circleB
/// -e_faceA: the local center of cirlceB or the clip point of polygonB
/// -e_faceB: the clip point of polygonA
/// This structure is stored across time steps, so we keep it small.
/// Note: the impulses are used for internal caching and may not
/// provide reliable contact forces, especially for high speed collisions.
struct b2ManifoldPoint
{
b2Vec2 localPoint; ///< usage depends on manifold type
float32 normalImpulse; ///< the non-penetration impulse
float32 tangentImpulse; ///< the friction impulse
b2ContactID id; ///< uniquely identifies a contact point between two shapes
};
/// A manifold for two touching convex shapes.
/// Box2D supports multiple types of contact:
/// - clip point versus plane with radius
/// - point versus point with radius (circles)
/// The local point usage depends on the manifold type:
/// -e_circles: the local center of circleA
/// -e_faceA: the center of faceA
/// -e_faceB: the center of faceB
/// Similarly the local normal usage:
/// -e_circles: not used
/// -e_faceA: the normal on polygonA
/// -e_faceB: the normal on polygonB
/// We store contacts in this way so that position correction can
/// account for movement, which is critical for continuous physics.
/// All contact scenarios must be expressed in one of these types.
/// This structure is stored across time steps, so we keep it small.
struct b2Manifold
{
enum Type
{
e_circles,
e_faceA,
e_faceB
};
b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact
b2Vec2 localNormal; ///< not use for Type::e_points
b2Vec2 localPoint; ///< usage depends on manifold type
Type type;
int32 pointCount; ///< the number of manifold points
};
/// This is used to compute the current state of a contact manifold.
struct b2WorldManifold
{
/// Evaluate the manifold with supplied transforms. This assumes
/// modest motion from the original state. This does not change the
/// point count, impulses, etc. The radii must come from the shapes
/// that generated the manifold.
void Initialize(const b2Manifold* manifold,
const b2Transform& xfA, float32 radiusA,
const b2Transform& xfB, float32 radiusB);
b2Vec2 normal; ///< world vector pointing from A to B
b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
float32 separations[b2_maxManifoldPoints]; ///< a negative value indicates overlap, in meters
};
/// This is used for determining the state of contact points.
enum b2PointState
{
b2_nullState, ///< point does not exist
b2_addState, ///< point was added in the update
b2_persistState, ///< point persisted across the update
b2_removeState ///< point was removed in the update
};
/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
const b2Manifold* manifold1, const b2Manifold* manifold2);
/// Used for computing contact manifolds.
struct b2ClipVertex
{
b2Vec2 v;
b2ContactID id;
};
/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
struct b2RayCastInput
{
b2Vec2 p1, p2;
float32 maxFraction;
};
/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
/// come from b2RayCastInput.
struct b2RayCastOutput
{
b2Vec2 normal;
float32 fraction;
};
/// An axis aligned bounding box.
struct b2AABB
{
/// Verify that the bounds are sorted.
bool IsValid() const;
/// Get the center of the AABB.
b2Vec2 GetCenter() const
{
return 0.5f * (lowerBound + upperBound);
}
/// Get the extents of the AABB (half-widths).
b2Vec2 GetExtents() const
{
return 0.5f * (upperBound - lowerBound);
}
/// Get the perimeter length
float32 GetPerimeter() const
{
float32 wx = upperBound.x - lowerBound.x;
float32 wy = upperBound.y - lowerBound.y;
return 2.0f * (wx + wy);
}
/// Combine an AABB into this one.
void Combine(const b2AABB& aabb)
{
lowerBound = b2Min(lowerBound, aabb.lowerBound);
upperBound = b2Max(upperBound, aabb.upperBound);
}
/// Combine two AABBs into this one.
void Combine(const b2AABB& aabb1, const b2AABB& aabb2)
{
lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
}
/// Does this aabb contain the provided AABB.
bool Contains(const b2AABB& aabb) const
{
bool result = true;
result = result && lowerBound.x <= aabb.lowerBound.x;
result = result && lowerBound.y <= aabb.lowerBound.y;
result = result && aabb.upperBound.x <= upperBound.x;
result = result && aabb.upperBound.y <= upperBound.y;
return result;
}
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
b2Vec2 lowerBound; ///< the lower vertex
b2Vec2 upperBound; ///< the upper vertex
};
/// Compute the collision manifold between two circles.
void b2CollideCircles(b2Manifold* manifold,
const b2CircleShape* circleA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between a polygon and a circle.
void b2CollidePolygonAndCircle(b2Manifold* manifold,
const b2PolygonShape* polygonA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between two polygons.
void b2CollidePolygons(b2Manifold* manifold,
const b2PolygonShape* polygonA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB);
/// Compute the collision manifold between an edge and a circle.
void b2CollideEdgeAndCircle(b2Manifold* manifold,
const b2EdgeShape* polygonA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB);
/// Compute the collision manifold between an edge and a circle.
void b2CollideEdgeAndPolygon(b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* circleB, const b2Transform& xfB);
/// Clipping for contact manifolds.
int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
const b2Vec2& normal, float32 offset, int32 vertexIndexA);
/// Determine if two generic shapes overlap.
bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
const b2Shape* shapeB, int32 indexB,
const b2Transform& xfA, const b2Transform& xfB);
// ---------------- Inline Functions ------------------------------------------
inline bool b2AABB::IsValid() const
{
b2Vec2 d = upperBound - lowerBound;
bool valid = d.x >= 0.0f && d.y >= 0.0f;
valid = valid && lowerBound.IsValid() && upperBound.IsValid();
return valid;
}
inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)
{
b2Vec2 d1, d2;
d1 = b.lowerBound - a.upperBound;
d2 = a.lowerBound - b.upperBound;
if (d1.x > 0.0f || d1.y > 0.0f)
return false;
if (d2.x > 0.0f || d2.y > 0.0f)
return false;
return true;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/b2Distance.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_H
#define B2_DISTANCE_H
#include "../Common/b2Math.h"
class b2Shape;
/// A distance proxy is used by the GJK algorithm.
/// It encapsulates any shape.
struct b2DistanceProxy
{
b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
/// Initialize the proxy using the given shape. The shape
/// must remain in scope while the proxy is in use.
void Set(const b2Shape* shape, int32 index);
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const;
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
b2Vec2 m_buffer[2];
const b2Vec2* m_vertices;
int32 m_count;
float32 m_radius;
};
/// Used to warm start b2Distance.
/// Set count to zero on first call.
struct b2SimplexCache
{
float32 metric; ///< length or area
uint16 count;
uint8 indexA[3]; ///< vertices on shape A
uint8 indexB[3]; ///< vertices on shape B
};
/// Input for b2Distance.
/// You have to option to use the shape radii
/// in the computation. Even
struct b2DistanceInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Transform transformA;
b2Transform transformB;
bool useRadii;
};
/// Output for b2Distance.
struct b2DistanceOutput
{
b2Vec2 pointA; ///< closest point on shapeA
b2Vec2 pointB; ///< closest point on shapeB
float32 distance;
int32 iterations; ///< number of GJK iterations used
};
/// Compute the closest points between two shapes. Supports any combination of:
/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
/// On the first call set b2SimplexCache.count to zero.
void b2Distance(b2DistanceOutput* output,
b2SimplexCache* cache,
const b2DistanceInput* input);
//////////////////////////////////////////////////////////////////////////
inline int32 b2DistanceProxy::GetVertexCount() const
{
return m_count;
}
inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/b2DynamicTree.h
================================================
/*
* Copyright (c) 2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DYNAMIC_TREE_H
#define B2_DYNAMIC_TREE_H
#include "b2Collision.h"
#include "../Common/b2GrowableStack.h"
#define b2_nullNode (-1)
/// A node in the dynamic tree. The client does not interact with this directly.
struct b2TreeNode
{
bool IsLeaf() const
{
return child1 == b2_nullNode;
}
/// Enlarged AABB
b2AABB aabb;
void* userData;
union
{
int32 parent;
int32 next;
};
int32 child1;
int32 child2;
// leaf = 0, free node = -1
int32 height;
};
/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
/// A dynamic tree arranges data in a binary tree to accelerate
/// queries such as volume queries and ray casts. Leafs are proxies
/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
/// so that the proxy AABB is bigger than the client object. This allows the client
/// object to move by small amounts without triggering a tree update.
///
/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
class b2DynamicTree
{
public:
/// Constructing the tree initializes the node pool.
b2DynamicTree();
/// Destroy the tree, freeing the node pool.
~b2DynamicTree();
/// Create a proxy. Provide a tight fitting AABB and a userData pointer.
int32 CreateProxy(const b2AABB& aabb, void* userData);
/// Destroy a proxy. This asserts if the id is invalid.
void DestroyProxy(int32 proxyId);
/// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,
/// then the proxy is removed from the tree and re-inserted. Otherwise
/// the function returns immediately.
/// @return true if the proxy was re-inserted.
bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
/// Get proxy user data.
/// @return the proxy user data or 0 if the id is invalid.
void* GetUserData(int32 proxyId) const;
/// Get the fat AABB for a proxy.
const b2AABB& GetFatAABB(int32 proxyId) const;
/// Query an AABB for overlapping proxies. The callback class
/// is called for each proxy that overlaps the supplied AABB.
template
void Query(T* callback, const b2AABB& aabb) const;
/// Ray-cast against the proxies in the tree. This relies on the callback
/// to perform a exact ray-cast in the case were the proxy contains a shape.
/// The callback also performs the any collision filtering. This has performance
/// roughly equal to k * log(n), where k is the number of collisions and n is the
/// number of proxies in the tree.
/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
/// @param callback a callback class that is called for each proxy that is hit by the ray.
template
void RayCast(T* callback, const b2RayCastInput& input) const;
/// Validate this tree. For testing.
void Validate() const;
/// Compute the height of the binary tree in O(N) time. Should not be
/// called often.
int32 GetHeight() const;
/// Get the maximum balance of an node in the tree. The balance is the difference
/// in height of the two children of a node.
int32 GetMaxBalance() const;
/// Get the ratio of the sum of the node areas to the root area.
float32 GetAreaRatio() const;
/// Build an optimal tree. Very expensive. For testing.
void RebuildBottomUp();
/// Shift the world origin. Useful for large worlds.
/// The shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
private:
int32 AllocateNode();
void FreeNode(int32 node);
void InsertLeaf(int32 node);
void RemoveLeaf(int32 node);
int32 Balance(int32 index);
int32 ComputeHeight() const;
int32 ComputeHeight(int32 nodeId) const;
void ValidateStructure(int32 index) const;
void ValidateMetrics(int32 index) const;
int32 m_root;
b2TreeNode* m_nodes;
int32 m_nodeCount;
int32 m_nodeCapacity;
int32 m_freeList;
/// This is used to incrementally traverse the tree for re-balancing.
uint32 m_path;
int32 m_insertionCount;
};
inline void* b2DynamicTree::GetUserData(int32 proxyId) const
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
return m_nodes[proxyId].userData;
}
inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
{
b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
return m_nodes[proxyId].aabb;
}
template
inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
{
b2GrowableStack stack;
stack.Push(m_root);
while (stack.GetCount() > 0)
{
int32 nodeId = stack.Pop();
if (nodeId == b2_nullNode)
{
continue;
}
const b2TreeNode* node = m_nodes + nodeId;
if (b2TestOverlap(node->aabb, aabb))
{
if (node->IsLeaf())
{
bool proceed = callback->QueryCallback(nodeId);
if (proceed == false)
{
return;
}
}
else
{
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}
}
template
inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const
{
b2Vec2 p1 = input.p1;
b2Vec2 p2 = input.p2;
b2Vec2 r = p2 - p1;
b2Assert(r.LengthSquared() > 0.0f);
r.Normalize();
// v is perpendicular to the segment.
b2Vec2 v = b2Cross(1.0f, r);
b2Vec2 abs_v = b2Abs(v);
// Separating axis for segment (Gino, p80).
// |dot(v, p1 - c)| > dot(|v|, h)
float32 maxFraction = input.maxFraction;
// Build a bounding box for the segment.
b2AABB segmentAABB;
{
b2Vec2 t = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b2Min(p1, t);
segmentAABB.upperBound = b2Max(p1, t);
}
b2GrowableStack stack;
stack.Push(m_root);
while (stack.GetCount() > 0)
{
int32 nodeId = stack.Pop();
if (nodeId == b2_nullNode)
{
continue;
}
const b2TreeNode* node = m_nodes + nodeId;
if (b2TestOverlap(node->aabb, segmentAABB) == false)
{
continue;
}
// Separating axis for segment (Gino, p80).
// |dot(v, p1 - c)| > dot(|v|, h)
b2Vec2 c = node->aabb.GetCenter();
b2Vec2 h = node->aabb.GetExtents();
float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
if (separation > 0.0f)
{
continue;
}
if (node->IsLeaf())
{
b2RayCastInput subInput;
subInput.p1 = input.p1;
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
float32 value = callback->RayCastCallback(subInput, nodeId);
if (value == 0.0f)
{
// The client has terminated the ray cast.
return;
}
if (value > 0.0f)
{
// Update segment bounding box.
maxFraction = value;
b2Vec2 t = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b2Min(p1, t);
segmentAABB.upperBound = b2Max(p1, t);
}
}
else
{
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Collision/b2TimeOfImpact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIME_OF_IMPACT_H
#define B2_TIME_OF_IMPACT_H
#include "../Common/b2Math.h"
#include "b2Distance.h"
/// Input parameters for b2TimeOfImpact
struct b2TOIInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Sweep sweepA;
b2Sweep sweepB;
float32 tMax; // defines sweep interval [0, tMax]
};
// Output parameters for b2TimeOfImpact.
struct b2TOIOutput
{
enum State
{
e_unknown,
e_failed,
e_overlapped,
e_touching,
e_separated
};
State state;
float32 t;
};
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
/// non-tunneling collision. If you change the time interval, you should call this function
/// again.
/// Note: use b2Distance to compute the contact point and normal at the time of impact.
void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2BlockAllocator.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_BLOCK_ALLOCATOR_H
#define B2_BLOCK_ALLOCATOR_H
#include "b2Settings.h"
const int32 b2_chunkSize = 16 * 1024;
const int32 b2_maxBlockSize = 640;
const int32 b2_blockSizes = 14;
const int32 b2_chunkArrayIncrement = 128;
struct b2Block;
struct b2Chunk;
/// This is a small object allocator used for allocating small
/// objects that persist for more than one time step.
/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
class b2BlockAllocator
{
public:
b2BlockAllocator();
~b2BlockAllocator();
/// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
void* Allocate(int32 size);
/// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
void Free(void* p, int32 size);
void Clear();
private:
b2Chunk* m_chunks;
int32 m_chunkCount;
int32 m_chunkSpace;
b2Block* m_freeLists[b2_blockSizes];
static int32 s_blockSizes[b2_blockSizes];
static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
static bool s_blockSizeLookupInitialized;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2Draw.h
================================================
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DRAW_H
#define B2_DRAW_H
#include "b2Math.h"
/// Color for debug drawing. Each value has the range [0,1].
struct b2Color
{
b2Color() {}
b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
float32 r, g, b;
};
/// Implement and register this class with a b2World to provide debug drawing of physics
/// entities in your game.
class b2Draw
{
public:
b2Draw();
virtual ~b2Draw() {}
enum
{
e_shapeBit = 0x0001, ///< draw shapes
e_jointBit = 0x0002, ///< draw joint connections
e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes
e_pairBit = 0x0008, ///< draw broad-phase pairs
e_centerOfMassBit = 0x0010 ///< draw center of mass frame
};
/// Set the drawing flags.
void SetFlags(uint32 flags);
/// Get the drawing flags.
uint32 GetFlags() const;
/// Append flags to the current flags.
void AppendFlags(uint32 flags);
/// Clear flags from the current flags.
void ClearFlags(uint32 flags);
/// Draw a closed polygon provided in CCW order.
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a solid closed polygon provided in CCW order.
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a circle.
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
/// Draw a solid circle.
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
/// Draw a line segment.
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
/// Draw a transform. Choose your own length scale.
/// @param xf a transform.
virtual void DrawTransform(const b2Transform& xf) = 0;
protected:
uint32 m_drawFlags;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2GrowableStack.h
================================================
/*
* Copyright (c) 2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_GROWABLE_STACK_H
#define B2_GROWABLE_STACK_H
#include "b2Settings.h"
#include
#include
/// This is a growable LIFO stack with an initial capacity of N.
/// If the stack size exceeds the initial capacity, the heap is used
/// to increase the size of the stack.
template
class b2GrowableStack
{
public:
b2GrowableStack()
{
m_stack = m_array;
m_count = 0;
m_capacity = N;
}
~b2GrowableStack()
{
if (m_stack != m_array)
{
b2Free(m_stack);
m_stack = NULL;
}
}
void Push(const T& element)
{
if (m_count == m_capacity)
{
T* old = m_stack;
m_capacity *= 2;
m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
memcpy(m_stack, old, m_count * sizeof(T));
if (old != m_array)
{
b2Free(old);
}
}
m_stack[m_count] = element;
++m_count;
}
T Pop()
{
b2Assert(m_count > 0);
--m_count;
return m_stack[m_count];
}
int32 GetCount()
{
return m_count;
}
private:
T* m_stack;
T m_array[N];
int32 m_count;
int32 m_capacity;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2Math.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MATH_H
#define B2_MATH_H
#include "b2Settings.h"
#include
/// This function is used to ensure that a floating point number is not a NaN or infinity.
inline bool b2IsValid(float32 x)
{
int32 ix = *reinterpret_cast(&x);
return (ix & 0x7f800000) != 0x7f800000;
}
/// This is a approximate yet fast inverse square-root.
inline float32 b2InvSqrt(float32 x)
{
union
{
float32 x;
int32 i;
} convert;
convert.x = x;
float32 xhalf = 0.5f * x;
convert.i = 0x5f3759df - (convert.i >> 1);
x = convert.x;
x = x * (1.5f - xhalf * x * x);
return x;
}
#define b2Sqrt(x) sqrtf(x)
#define b2Atan2(y, x) atan2f(y, x)
/// A 2D column vector.
struct b2Vec2
{
/// Default constructor does nothing (for performance).
b2Vec2() {}
/// Construct using coordinates.
b2Vec2(float32 x, float32 y) : x(x), y(y) {}
/// Set this vector to all zeros.
void SetZero() { x = 0.0f; y = 0.0f; }
/// Set this vector to some specified coordinates.
void Set(float32 x_, float32 y_) { x = x_; y = y_; }
/// Negate this vector.
b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
/// Read from and indexed element.
float32 operator () (int32 i) const
{
return (&x)[i];
}
/// Write to an indexed element.
float32& operator () (int32 i)
{
return (&x)[i];
}
/// Add a vector to this vector.
void operator += (const b2Vec2& v)
{
x += v.x; y += v.y;
}
/// Subtract a vector from this vector.
void operator -= (const b2Vec2& v)
{
x -= v.x; y -= v.y;
}
/// Multiply this vector by a scalar.
void operator *= (float32 a)
{
x *= a; y *= a;
}
/// Get the length of this vector (the norm).
float32 Length() const
{
return b2Sqrt(x * x + y * y);
}
/// Get the length squared. For performance, use this instead of
/// b2Vec2::Length (if possible).
float32 LengthSquared() const
{
return x * x + y * y;
}
/// Convert this vector into a unit vector. Returns the length.
float32 Normalize()
{
float32 length = Length();
if (length < b2_epsilon)
{
return 0.0f;
}
float32 invLength = 1.0f / length;
x *= invLength;
y *= invLength;
return length;
}
/// Does this vector contain finite coordinates?
bool IsValid() const
{
return b2IsValid(x) && b2IsValid(y);
}
/// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
b2Vec2 Skew() const
{
return b2Vec2(-y, x);
}
float32 x, y;
};
/// A 2D column vector with 3 elements.
struct b2Vec3
{
/// Default constructor does nothing (for performance).
b2Vec3() {}
/// Construct using coordinates.
b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
/// Set this vector to all zeros.
void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
/// Set this vector to some specified coordinates.
void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
/// Negate this vector.
b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
/// Add a vector to this vector.
void operator += (const b2Vec3& v)
{
x += v.x; y += v.y; z += v.z;
}
/// Subtract a vector from this vector.
void operator -= (const b2Vec3& v)
{
x -= v.x; y -= v.y; z -= v.z;
}
/// Multiply this vector by a scalar.
void operator *= (float32 s)
{
x *= s; y *= s; z *= s;
}
float32 x, y, z;
};
/// A 2-by-2 matrix. Stored in column-major order.
struct b2Mat22
{
/// The default constructor does nothing (for performance).
b2Mat22() {}
/// Construct this matrix using columns.
b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
{
ex = c1;
ey = c2;
}
/// Construct this matrix using scalars.
b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
{
ex.x = a11; ex.y = a21;
ey.x = a12; ey.y = a22;
}
/// Initialize this matrix using columns.
void Set(const b2Vec2& c1, const b2Vec2& c2)
{
ex = c1;
ey = c2;
}
/// Set this to the identity matrix.
void SetIdentity()
{
ex.x = 1.0f; ey.x = 0.0f;
ex.y = 0.0f; ey.y = 1.0f;
}
/// Set this matrix to all zeros.
void SetZero()
{
ex.x = 0.0f; ey.x = 0.0f;
ex.y = 0.0f; ey.y = 0.0f;
}
b2Mat22 GetInverse() const
{
float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
b2Mat22 B;
float32 det = a * d - b * c;
if (det != 0.0f)
{
det = 1.0f / det;
}
B.ex.x = det * d; B.ey.x = -det * b;
B.ex.y = -det * c; B.ey.y = det * a;
return B;
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec2 Solve(const b2Vec2& b) const
{
float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
float32 det = a11 * a22 - a12 * a21;
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec2 x;
x.x = det * (a22 * b.x - a12 * b.y);
x.y = det * (a11 * b.y - a21 * b.x);
return x;
}
b2Vec2 ex, ey;
};
/// A 3-by-3 matrix. Stored in column-major order.
struct b2Mat33
{
/// The default constructor does nothing (for performance).
b2Mat33() {}
/// Construct this matrix using columns.
b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
{
ex = c1;
ey = c2;
ez = c3;
}
/// Set this matrix to all zeros.
void SetZero()
{
ex.SetZero();
ey.SetZero();
ez.SetZero();
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec3 Solve33(const b2Vec3& b) const;
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases. Solve only the upper
/// 2-by-2 matrix equation.
b2Vec2 Solve22(const b2Vec2& b) const;
/// Get the inverse of this matrix as a 2-by-2.
/// Returns the zero matrix if singular.
void GetInverse22(b2Mat33* M) const;
/// Get the symmetric inverse of this matrix as a 3-by-3.
/// Returns the zero matrix if singular.
void GetSymInverse33(b2Mat33* M) const;
b2Vec3 ex, ey, ez;
};
/// Rotation
struct b2Rot
{
b2Rot() {}
/// Initialize from an angle in radians
explicit b2Rot(float32 angle)
{
/// TODO_ERIN optimize
s = sinf(angle);
c = cosf(angle);
}
/// Set using an angle in radians.
void Set(float32 angle)
{
/// TODO_ERIN optimize
s = sinf(angle);
c = cosf(angle);
}
/// Set to the identity rotation
void SetIdentity()
{
s = 0.0f;
c = 1.0f;
}
/// Get the angle in radians
float32 GetAngle() const
{
return b2Atan2(s, c);
}
/// Get the x-axis
b2Vec2 GetXAxis() const
{
return b2Vec2(c, s);
}
/// Get the u-axis
b2Vec2 GetYAxis() const
{
return b2Vec2(-s, c);
}
/// Sine and cosine
float32 s, c;
};
/// A transform contains translation and rotation. It is used to represent
/// the position and orientation of rigid frames.
struct b2Transform
{
/// The default constructor does nothing.
b2Transform() {}
/// Initialize using a position vector and a rotation.
b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {}
/// Set this to the identity transform.
void SetIdentity()
{
p.SetZero();
q.SetIdentity();
}
/// Set this based on the position and angle.
void Set(const b2Vec2& position, float32 angle)
{
p = position;
q.Set(angle);
}
b2Vec2 p;
b2Rot q;
};
/// This describes the motion of a body/shape for TOI computation.
/// Shapes are defined with respect to the body origin, which may
/// no coincide with the center of mass. However, to support dynamics
/// we must interpolate the center of mass position.
struct b2Sweep
{
/// Get the interpolated transform at a specific time.
/// @param beta is a factor in [0,1], where 0 indicates alpha0.
void GetTransform(b2Transform* xfb, float32 beta) const;
/// Advance the sweep forward, yielding a new initial state.
/// @param alpha the new initial time.
void Advance(float32 alpha);
/// Normalize the angles.
void Normalize();
b2Vec2 localCenter; ///< local center of mass position
b2Vec2 c0, c; ///< center world positions
float32 a0, a; ///< world angles
/// Fraction of the current time step in the range [0,1]
/// c0 and a0 are the positions at alpha0.
float32 alpha0;
};
/// Useful constant
extern const b2Vec2 b2Vec2_zero;
/// Perform the dot product on two vectors.
inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
{
return a.x * b.x + a.y * b.y;
}
/// Perform the cross product on two vectors. In 2D this produces a scalar.
inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
{
return a.x * b.y - a.y * b.x;
}
/// Perform the cross product on a vector and a scalar. In 2D this produces
/// a vector.
inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
{
return b2Vec2(s * a.y, -s * a.x);
}
/// Perform the cross product on a scalar and a vector. In 2D this produces
/// a vector.
inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
{
return b2Vec2(-s * a.y, s * a.x);
}
/// Multiply a matrix times a vector. If a rotation matrix is provided,
/// then this transforms the vector from one frame to another.
inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
{
return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
}
/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
/// then this transforms the vector from one frame to another (inverse transform).
inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
{
return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey));
}
/// Add two vectors component-wise.
inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)
{
return b2Vec2(a.x + b.x, a.y + b.y);
}
/// Subtract two vectors component-wise.
inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
{
return b2Vec2(a.x - b.x, a.y - b.y);
}
inline b2Vec2 operator * (float32 s, const b2Vec2& a)
{
return b2Vec2(s * a.x, s * a.y);
}
inline bool operator == (const b2Vec2& a, const b2Vec2& b)
{
return a.x == b.x && a.y == b.y;
}
inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
{
b2Vec2 c = a - b;
return c.Length();
}
inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
{
b2Vec2 c = a - b;
return b2Dot(c, c);
}
inline b2Vec3 operator * (float32 s, const b2Vec3& a)
{
return b2Vec3(s * a.x, s * a.y, s * a.z);
}
/// Add two vectors component-wise.
inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)
{
return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
}
/// Subtract two vectors component-wise.
inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
{
return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);
}
/// Perform the dot product on two vectors.
inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
/// Perform the cross product on two vectors.
inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)
{
return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
}
inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
{
return b2Mat22(A.ex + B.ex, A.ey + B.ey);
}
// A * B
inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
{
return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey));
}
// A^T * B
inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
{
b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex));
b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey));
return b2Mat22(c1, c2);
}
/// Multiply a matrix times a vector.
inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)
{
return v.x * A.ex + v.y * A.ey + v.z * A.ez;
}
/// Multiply a matrix times a vector.
inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
{
return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
}
/// Multiply two rotations: q * r
inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r)
{
// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
// [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
// s = qs * rc + qc * rs
// c = qc * rc - qs * rs
b2Rot qr;
qr.s = q.s * r.c + q.c * r.s;
qr.c = q.c * r.c - q.s * r.s;
return qr;
}
/// Transpose multiply two rotations: qT * r
inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r)
{
// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
// [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc]
// s = qc * rs - qs * rc
// c = qc * rc + qs * rs
b2Rot qr;
qr.s = q.c * r.s - q.s * r.c;
qr.c = q.c * r.c + q.s * r.s;
return qr;
}
/// Rotate a vector
inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v)
{
return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y);
}
/// Inverse rotate a vector
inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v)
{
return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y);
}
inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)
{
float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
return b2Vec2(x, y);
}
inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)
{
float32 px = v.x - T.p.x;
float32 py = v.y - T.p.y;
float32 x = (T.q.c * px + T.q.s * py);
float32 y = (-T.q.s * px + T.q.c * py);
return b2Vec2(x, y);
}
// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B)
{
b2Transform C;
C.q = b2Mul(A.q, B.q);
C.p = b2Mul(A.q, B.p) + A.p;
return C;
}
// v2 = A.q' * (B.q * v1 + B.p - A.p)
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B)
{
b2Transform C;
C.q = b2MulT(A.q, B.q);
C.p = b2MulT(A.q, B.p - A.p);
return C;
}
template
inline T b2Abs(T a)
{
return a > T(0) ? a : -a;
}
inline b2Vec2 b2Abs(const b2Vec2& a)
{
return b2Vec2(b2Abs(a.x), b2Abs(a.y));
}
inline b2Mat22 b2Abs(const b2Mat22& A)
{
return b2Mat22(b2Abs(A.ex), b2Abs(A.ey));
}
template
inline T b2Min(T a, T b)
{
return a < b ? a : b;
}
inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)
{
return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y));
}
template
inline T b2Max(T a, T b)
{
return a > b ? a : b;
}
inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)
{
return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y));
}
template
inline T b2Clamp(T a, T low, T high)
{
return b2Max(low, b2Min(a, high));
}
inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)
{
return b2Max(low, b2Min(a, high));
}
template inline void b2Swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
/// "Next Largest Power of 2
/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
/// largest power of 2. For a 32-bit value:"
inline uint32 b2NextPowerOfTwo(uint32 x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x + 1;
}
inline bool b2IsPowerOfTwo(uint32 x)
{
bool result = x > 0 && (x & (x - 1)) == 0;
return result;
}
inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const
{
xf->p = (1.0f - beta) * c0 + beta * c;
float32 angle = (1.0f - beta) * a0 + beta * a;
xf->q.Set(angle);
// Shift to origin
xf->p -= b2Mul(xf->q, localCenter);
}
inline void b2Sweep::Advance(float32 alpha)
{
b2Assert(alpha0 < 1.0f);
float32 beta = (alpha - alpha0) / (1.0f - alpha0);
c0 += beta * (c - c0);
a0 += beta * (a - a0);
alpha0 = alpha;
}
/// Normalize an angle in radians to be between -pi and pi
inline void b2Sweep::Normalize()
{
float32 twoPi = 2.0f * b2_pi;
float32 d = twoPi * floorf(a0 / twoPi);
a0 -= d;
a -= d;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2Settings.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_SETTINGS_H
#define B2_SETTINGS_H
#include
#include
#include
#define B2_NOT_USED(x) ((void)(x))
#define b2Assert(A) assert(A)
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef float float32;
typedef double float64;
#define b2_maxFloat FLT_MAX
#define b2_epsilon FLT_EPSILON
#define b2_pi 3.14159265359f
/// @file
/// Global tuning constants based on meters-kilograms-seconds (MKS) units.
///
// Collision
/// The maximum number of contact points between two convex shapes. Do
/// not change this value.
#define b2_maxManifoldPoints 2
/// The maximum number of vertices on a convex polygon. You cannot increase
/// this too much because b2BlockAllocator has a maximum object size.
#define b2_maxPolygonVertices 8
/// This is used to fatten AABBs in the dynamic tree. This allows proxies
/// to move by a small amount without triggering a tree adjustment.
/// This is in meters.
#define b2_aabbExtension 0.1f
/// This is used to fatten AABBs in the dynamic tree. This is used to predict
/// the future position based on the current displacement.
/// This is a dimensionless multiplier.
#define b2_aabbMultiplier 2.0f
/// A small length used as a collision and constraint tolerance. Usually it is
/// chosen to be numerically significant, but visually insignificant.
#define b2_linearSlop 0.005f
/// A small angle used as a collision and constraint tolerance. Usually it is
/// chosen to be numerically significant, but visually insignificant.
#define b2_angularSlop (2.0f / 180.0f * b2_pi)
/// The radius of the polygon/edge shape skin. This should not be modified. Making
/// this smaller means polygons will have an insufficient buffer for continuous collision.
/// Making it larger may create artifacts for vertex collision.
#define b2_polygonRadius (2.0f * b2_linearSlop)
/// Maximum number of sub-steps per contact in continuous physics simulation.
#define b2_maxSubSteps 8
// Dynamics
/// Maximum number of contacts to be handled to solve a TOI impact.
#define b2_maxTOIContacts 32
/// A velocity threshold for elastic collisions. Any collision with a relative linear
/// velocity below this threshold will be treated as inelastic.
#define b2_velocityThreshold 1.0f
/// The maximum linear position correction used when solving constraints. This helps to
/// prevent overshoot.
#define b2_maxLinearCorrection 0.2f
/// The maximum angular position correction used when solving constraints. This helps to
/// prevent overshoot.
#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi)
/// The maximum linear velocity of a body. This limit is very large and is used
/// to prevent numerical problems. You shouldn't need to adjust this.
#define b2_maxTranslation 2.0f
#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation)
/// The maximum angular velocity of a body. This limit is very large and is used
/// to prevent numerical problems. You shouldn't need to adjust this.
#define b2_maxRotation (0.5f * b2_pi)
#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation)
/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
/// that overlap is removed in one time step. However using values close to 1 often lead
/// to overshoot.
#define b2_baumgarte 0.2f
#define b2_toiBaugarte 0.75f
// Sleep
/// The time that a body must be still before it will go to sleep.
#define b2_timeToSleep 0.5f
/// A body cannot sleep if its linear velocity is above this tolerance.
#define b2_linearSleepTolerance 0.01f
/// A body cannot sleep if its angular velocity is above this tolerance.
#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)
// Memory Allocation
/// Implement this function to use your own memory allocator.
void* b2Alloc(int32 size);
/// If you implement b2Alloc, you should also implement this function.
void b2Free(void* mem);
/// Logging function.
void b2Log(const char* string, ...);
/// Version numbering scheme.
/// See http://en.wikipedia.org/wiki/Software_versioning
struct b2Version
{
int32 major; ///< significant changes
int32 minor; ///< incremental changes
int32 revision; ///< bug fixes
};
/// Current version.
extern b2Version b2_version;
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2StackAllocator.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_STACK_ALLOCATOR_H
#define B2_STACK_ALLOCATOR_H
#include "b2Settings.h"
const int32 b2_stackSize = 100 * 1024; // 100k
const int32 b2_maxStackEntries = 32;
struct b2StackEntry
{
char* data;
int32 size;
bool usedMalloc;
};
// This is a stack allocator used for fast per step allocations.
// You must nest allocate/free pairs. The code will assert
// if you try to interleave multiple allocate/free pairs.
class b2StackAllocator
{
public:
b2StackAllocator();
~b2StackAllocator();
void* Allocate(int32 size);
void Free(void* p);
int32 GetMaxAllocation() const;
private:
char m_data[b2_stackSize];
int32 m_index;
int32 m_allocation;
int32 m_maxAllocation;
b2StackEntry m_entries[b2_maxStackEntries];
int32 m_entryCount;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Common/b2Timer.h
================================================
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIMER_H
#define B2_TIMER_H
#include "b2Settings.h"
/// Timer for profiling. This has platform specific code and may
/// not work on every platform.
class b2Timer
{
public:
/// Constructor
b2Timer();
/// Reset the timer.
void Reset();
/// Get the time since construction or the last reset.
float32 GetMilliseconds() const;
private:
#if defined(_WIN32)
float64 m_start;
static float64 s_invFrequency;
#elif defined(__linux__) || defined (__APPLE__)
unsigned long m_start_sec;
unsigned long m_start_usec;
#endif
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H
#define B2_CHAIN_AND_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2ChainAndCircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
~b2ChainAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H
#define B2_CHAIN_AND_POLYGON_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2ChainAndPolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
~b2ChainAndPolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2CircleContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_CONTACT_H
#define B2_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2CircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2CircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2Contact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_H
#define B2_CONTACT_H
#include "../../Common/b2Math.h"
#include "../../Collision/b2Collision.h"
#include "../../Collision/Shapes/b2Shape.h"
#include "../b2Fixture.h"
class b2Body;
class b2Contact;
class b2Fixture;
class b2World;
class b2BlockAllocator;
class b2StackAllocator;
class b2ContactListener;
/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero.
/// For example, anything slides on ice.
inline float32 b2MixFriction(float32 friction1, float32 friction2)
{
return b2Sqrt(friction1 * friction2);
}
/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
/// For example, a superball bounces on anything.
inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)
{
return restitution1 > restitution2 ? restitution1 : restitution2;
}
typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB,
b2BlockAllocator* allocator);
typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);
struct b2ContactRegister
{
b2ContactCreateFcn* createFcn;
b2ContactDestroyFcn* destroyFcn;
bool primary;
};
/// A contact edge is used to connect bodies and contacts together
/// in a contact graph where each body is a node and each contact
/// is an edge. A contact edge belongs to a doubly linked list
/// maintained in each attached body. Each contact has two contact
/// nodes, one for each attached body.
struct b2ContactEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Contact* contact; ///< the contact
b2ContactEdge* prev; ///< the previous contact edge in the body's contact list
b2ContactEdge* next; ///< the next contact edge in the body's contact list
};
/// The class manages contact between two shapes. A contact exists for each overlapping
/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
/// that has no contact points.
class b2Contact
{
public:
/// Get the contact manifold. Do not modify the manifold unless you understand the
/// internals of Box2D.
b2Manifold* GetManifold();
const b2Manifold* GetManifold() const;
/// Get the world manifold.
void GetWorldManifold(b2WorldManifold* worldManifold) const;
/// Is this contact touching?
bool IsTouching() const;
/// Enable/disable this contact. This can be used inside the pre-solve
/// contact listener. The contact is only disabled for the current
/// time step (or sub-step in continuous collisions).
void SetEnabled(bool flag);
/// Has this contact been disabled?
bool IsEnabled() const;
/// Get the next contact in the world's contact list.
b2Contact* GetNext();
const b2Contact* GetNext() const;
/// Get fixture A in this contact.
b2Fixture* GetFixtureA();
const b2Fixture* GetFixtureA() const;
/// Get the child primitive index for fixture A.
int32 GetChildIndexA() const;
/// Get fixture B in this contact.
b2Fixture* GetFixtureB();
const b2Fixture* GetFixtureB() const;
/// Get the child primitive index for fixture B.
int32 GetChildIndexB() const;
/// Override the default friction mixture. You can call this in b2ContactListener::PreSolve.
/// This value persists until set or reset.
void SetFriction(float32 friction);
/// Get the friction.
float32 GetFriction() const;
/// Reset the friction mixture to the default value.
void ResetFriction();
/// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve.
/// The value persists until you set or reset.
void SetRestitution(float32 restitution);
/// Get the restitution.
float32 GetRestitution() const;
/// Reset the restitution to the default value.
void ResetRestitution();
/// Set the desired tangent speed for a conveyor belt behavior. In meters per second.
void SetTangentSpeed(float32 speed);
/// Get the desired tangent speed. In meters per second.
float32 GetTangentSpeed() const;
/// Evaluate this contact with your own manifold and transforms.
virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;
protected:
friend class b2ContactManager;
friend class b2World;
friend class b2ContactSolver;
friend class b2Body;
friend class b2Fixture;
// Flags stored in m_flags
enum
{
// Used when crawling contact graph when forming islands.
e_islandFlag = 0x0001,
// Set when the shapes are touching.
e_touchingFlag = 0x0002,
// This contact can be disabled (by user)
e_enabledFlag = 0x0004,
// This contact needs filtering because a fixture filter was changed.
e_filterFlag = 0x0008,
// This bullet contact had a TOI event
e_bulletHitFlag = 0x0010,
// This contact has a valid TOI in m_toi
e_toiFlag = 0x0020
};
/// Flag this contact for filtering. Filtering will occur the next time step.
void FlagForFiltering();
static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,
b2Shape::Type typeA, b2Shape::Type typeB);
static void InitializeRegisters();
static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {}
b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
virtual ~b2Contact() {}
void Update(b2ContactListener* listener);
static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
static bool s_initialized;
uint32 m_flags;
// World pool and list pointers.
b2Contact* m_prev;
b2Contact* m_next;
// Nodes for connecting bodies.
b2ContactEdge m_nodeA;
b2ContactEdge m_nodeB;
b2Fixture* m_fixtureA;
b2Fixture* m_fixtureB;
int32 m_indexA;
int32 m_indexB;
b2Manifold m_manifold;
int32 m_toiCount;
float32 m_toi;
float32 m_friction;
float32 m_restitution;
float32 m_tangentSpeed;
};
inline b2Manifold* b2Contact::GetManifold()
{
return &m_manifold;
}
inline const b2Manifold* b2Contact::GetManifold() const
{
return &m_manifold;
}
inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const
{
const b2Body* bodyA = m_fixtureA->GetBody();
const b2Body* bodyB = m_fixtureB->GetBody();
const b2Shape* shapeA = m_fixtureA->GetShape();
const b2Shape* shapeB = m_fixtureB->GetShape();
worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);
}
inline void b2Contact::SetEnabled(bool flag)
{
if (flag)
{
m_flags |= e_enabledFlag;
}
else
{
m_flags &= ~e_enabledFlag;
}
}
inline bool b2Contact::IsEnabled() const
{
return (m_flags & e_enabledFlag) == e_enabledFlag;
}
inline bool b2Contact::IsTouching() const
{
return (m_flags & e_touchingFlag) == e_touchingFlag;
}
inline b2Contact* b2Contact::GetNext()
{
return m_next;
}
inline const b2Contact* b2Contact::GetNext() const
{
return m_next;
}
inline b2Fixture* b2Contact::GetFixtureA()
{
return m_fixtureA;
}
inline const b2Fixture* b2Contact::GetFixtureA() const
{
return m_fixtureA;
}
inline b2Fixture* b2Contact::GetFixtureB()
{
return m_fixtureB;
}
inline int32 b2Contact::GetChildIndexA() const
{
return m_indexA;
}
inline const b2Fixture* b2Contact::GetFixtureB() const
{
return m_fixtureB;
}
inline int32 b2Contact::GetChildIndexB() const
{
return m_indexB;
}
inline void b2Contact::FlagForFiltering()
{
m_flags |= e_filterFlag;
}
inline void b2Contact::SetFriction(float32 friction)
{
m_friction = friction;
}
inline float32 b2Contact::GetFriction() const
{
return m_friction;
}
inline void b2Contact::ResetFriction()
{
m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
}
inline void b2Contact::SetRestitution(float32 restitution)
{
m_restitution = restitution;
}
inline float32 b2Contact::GetRestitution() const
{
return m_restitution;
}
inline void b2Contact::ResetRestitution()
{
m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
}
inline void b2Contact::SetTangentSpeed(float32 speed)
{
m_tangentSpeed = speed;
}
inline float32 b2Contact::GetTangentSpeed() const
{
return m_tangentSpeed;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2ContactSolver.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_SOLVER_H
#define B2_CONTACT_SOLVER_H
#include "../../Common/b2Math.h"
#include "../../Collision/b2Collision.h"
#include "../b2TimeStep.h"
class b2Contact;
class b2Body;
class b2StackAllocator;
struct b2ContactPositionConstraint;
struct b2VelocityConstraintPoint
{
b2Vec2 rA;
b2Vec2 rB;
float32 normalImpulse;
float32 tangentImpulse;
float32 normalMass;
float32 tangentMass;
float32 velocityBias;
};
struct b2ContactVelocityConstraint
{
b2VelocityConstraintPoint points[b2_maxManifoldPoints];
b2Vec2 normal;
b2Mat22 normalMass;
b2Mat22 K;
int32 indexA;
int32 indexB;
float32 invMassA, invMassB;
float32 invIA, invIB;
float32 friction;
float32 restitution;
float32 tangentSpeed;
int32 pointCount;
int32 contactIndex;
};
struct b2ContactSolverDef
{
b2TimeStep step;
b2Contact** contacts;
int32 count;
b2Position* positions;
b2Velocity* velocities;
b2StackAllocator* allocator;
};
class b2ContactSolver
{
public:
b2ContactSolver(b2ContactSolverDef* def);
~b2ContactSolver();
void InitializeVelocityConstraints();
void WarmStart();
void SolveVelocityConstraints();
void StoreImpulses();
bool SolvePositionConstraints();
bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB);
b2TimeStep m_step;
b2Position* m_positions;
b2Velocity* m_velocities;
b2StackAllocator* m_allocator;
b2ContactPositionConstraint* m_positionConstraints;
b2ContactVelocityConstraint* m_velocityConstraints;
b2Contact** m_contacts;
int m_count;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H
#define B2_EDGE_AND_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2EdgeAndCircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2EdgeAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_AND_POLYGON_CONTACT_H
#define B2_EDGE_AND_POLYGON_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2EdgeAndPolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2EdgeAndPolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H
#define B2_POLYGON_AND_CIRCLE_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2PolygonAndCircleContact : public b2Contact
{
public:
static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Contacts/b2PolygonContact.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_CONTACT_H
#define B2_POLYGON_CONTACT_H
#include "b2Contact.h"
class b2BlockAllocator;
class b2PolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2DistanceJoint.h
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_JOINT_H
#define B2_DISTANCE_JOINT_H
#include "b2Joint.h"
/// Distance joint definition. This requires defining an
/// anchor point on both bodies and the non-zero length of the
/// distance joint. The definition uses local anchor points
/// so that the initial configuration can violate the constraint
/// slightly. This helps when saving and loading a game.
/// @warning Do not use a zero or short length.
struct b2DistanceJointDef : public b2JointDef
{
b2DistanceJointDef()
{
type = e_distanceJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
length = 1.0f;
frequencyHz = 0.0f;
dampingRatio = 0.0f;
}
/// Initialize the bodies, anchors, and length using the world
/// anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& anchorA, const b2Vec2& anchorB);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The natural length between the anchor points.
float32 length;
/// The mass-spring-damper frequency in Hertz. A value of 0
/// disables softness.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A distance joint constrains two points on two bodies
/// to remain at a fixed distance from each other. You can view
/// this as a massless, rigid rod.
class b2DistanceJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
/// Get the reaction force given the inverse time step.
/// Unit is N.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Get the reaction torque given the inverse time step.
/// Unit is N*m. This is always zero for a distance joint.
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set/get the natural length.
/// Manipulating the length can lead to non-physical behavior when the frequency is zero.
void SetLength(float32 length);
float32 GetLength() const;
/// Set/get frequency in Hz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
/// Set/get damping ratio.
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2DistanceJoint(const b2DistanceJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_bias;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_gamma;
float32 m_impulse;
float32 m_length;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_u;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
float32 m_mass;
};
inline void b2DistanceJoint::SetLength(float32 length)
{
m_length = length;
}
inline float32 b2DistanceJoint::GetLength() const
{
return m_length;
}
inline void b2DistanceJoint::SetFrequency(float32 hz)
{
m_frequencyHz = hz;
}
inline float32 b2DistanceJoint::GetFrequency() const
{
return m_frequencyHz;
}
inline void b2DistanceJoint::SetDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
inline float32 b2DistanceJoint::GetDampingRatio() const
{
return m_dampingRatio;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2FrictionJoint.h
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_FRICTION_JOINT_H
#define B2_FRICTION_JOINT_H
#include "b2Joint.h"
/// Friction joint definition.
struct b2FrictionJointDef : public b2JointDef
{
b2FrictionJointDef()
{
type = e_frictionJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
maxForce = 0.0f;
maxTorque = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum friction force in N.
float32 maxForce;
/// The maximum friction torque in N-m.
float32 maxTorque;
};
/// Friction joint. This is used for top-down friction.
/// It provides 2D translational friction and angular friction.
class b2FrictionJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set the maximum friction force in N.
void SetMaxForce(float32 force);
/// Get the maximum friction force in N.
float32 GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float32 torque);
/// Get the maximum friction torque in N*m.
float32 GetMaxTorque() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2FrictionJoint(const b2FrictionJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
// Solver shared
b2Vec2 m_linearImpulse;
float32 m_angularImpulse;
float32 m_maxForce;
float32 m_maxTorque;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat22 m_linearMass;
float32 m_angularMass;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2GearJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_GEAR_JOINT_H
#define B2_GEAR_JOINT_H
#include "b2Joint.h"
/// Gear joint definition. This definition requires two existing
/// revolute or prismatic joints (any combination will work).
struct b2GearJointDef : public b2JointDef
{
b2GearJointDef()
{
type = e_gearJoint;
joint1 = NULL;
joint2 = NULL;
ratio = 1.0f;
}
/// The first revolute/prismatic joint attached to the gear joint.
b2Joint* joint1;
/// The second revolute/prismatic joint attached to the gear joint.
b2Joint* joint2;
/// The gear ratio.
/// @see b2GearJoint for explanation.
float32 ratio;
};
/// A gear joint is used to connect two joints together. Either joint
/// can be a revolute or prismatic joint. You specify a gear ratio
/// to bind the motions together:
/// coordinate1 + ratio * coordinate2 = constant
/// The ratio can be negative or positive. If one joint is a revolute joint
/// and the other joint is a prismatic joint, then the ratio will have units
/// of length or units of 1/length.
/// @warning You have to manually destroy the gear joint if joint1 or joint2
/// is destroyed.
class b2GearJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the first joint.
b2Joint* GetJoint1() { return m_joint1; }
/// Get the second joint.
b2Joint* GetJoint2() { return m_joint2; }
/// Set/Get the gear ratio.
void SetRatio(float32 ratio);
float32 GetRatio() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2GearJoint(const b2GearJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Joint* m_joint1;
b2Joint* m_joint2;
b2JointType m_typeA;
b2JointType m_typeB;
// Body A is connected to body C
// Body B is connected to body D
b2Body* m_bodyC;
b2Body* m_bodyD;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localAnchorC;
b2Vec2 m_localAnchorD;
b2Vec2 m_localAxisC;
b2Vec2 m_localAxisD;
float32 m_referenceAngleA;
float32 m_referenceAngleB;
float32 m_constant;
float32 m_ratio;
float32 m_impulse;
// Solver temp
int32 m_indexA, m_indexB, m_indexC, m_indexD;
b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD;
float32 m_mA, m_mB, m_mC, m_mD;
float32 m_iA, m_iB, m_iC, m_iD;
b2Vec2 m_JvAC, m_JvBD;
float32 m_JwA, m_JwB, m_JwC, m_JwD;
float32 m_mass;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2Joint.h
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_JOINT_H
#define B2_JOINT_H
#include "../../Common/b2Math.h"
class b2Body;
class b2Joint;
struct b2SolverData;
class b2BlockAllocator;
enum b2JointType
{
e_unknownJoint,
e_revoluteJoint,
e_prismaticJoint,
e_distanceJoint,
e_pulleyJoint,
e_mouseJoint,
e_gearJoint,
e_wheelJoint,
e_weldJoint,
e_frictionJoint,
e_ropeJoint,
e_motorJoint
};
enum b2LimitState
{
e_inactiveLimit,
e_atLowerLimit,
e_atUpperLimit,
e_equalLimits
};
struct b2Jacobian
{
b2Vec2 linear;
float32 angularA;
float32 angularB;
};
/// A joint edge is used to connect bodies and joints together
/// in a joint graph where each body is a node and each joint
/// is an edge. A joint edge belongs to a doubly linked list
/// maintained in each attached body. Each joint has two joint
/// nodes, one for each attached body.
struct b2JointEdge
{
b2Body* other; ///< provides quick access to the other body attached.
b2Joint* joint; ///< the joint
b2JointEdge* prev; ///< the previous joint edge in the body's joint list
b2JointEdge* next; ///< the next joint edge in the body's joint list
};
/// Joint definitions are used to construct joints.
struct b2JointDef
{
b2JointDef()
{
type = e_unknownJoint;
userData = NULL;
bodyA = NULL;
bodyB = NULL;
collideConnected = false;
}
/// The joint type is set automatically for concrete joint types.
b2JointType type;
/// Use this to attach application specific data to your joints.
void* userData;
/// The first attached body.
b2Body* bodyA;
/// The second attached body.
b2Body* bodyB;
/// Set this flag to true if the attached bodies should collide.
bool collideConnected;
};
/// The base joint class. Joints are used to constraint two bodies together in
/// various fashions. Some joints also feature limits and motors.
class b2Joint
{
public:
/// Get the type of the concrete joint.
b2JointType GetType() const;
/// Get the first body attached to this joint.
b2Body* GetBodyA();
/// Get the second body attached to this joint.
b2Body* GetBodyB();
/// Get the anchor point on bodyA in world coordinates.
virtual b2Vec2 GetAnchorA() const = 0;
/// Get the anchor point on bodyB in world coordinates.
virtual b2Vec2 GetAnchorB() const = 0;
/// Get the reaction force on bodyB at the joint anchor in Newtons.
virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0;
/// Get the reaction torque on bodyB in N*m.
virtual float32 GetReactionTorque(float32 inv_dt) const = 0;
/// Get the next joint the world joint list.
b2Joint* GetNext();
const b2Joint* GetNext() const;
/// Get the user data pointer.
void* GetUserData() const;
/// Set the user data pointer.
void SetUserData(void* data);
/// Short-cut function to determine if either body is inactive.
bool IsActive() const;
/// Get collide connected.
/// Note: modifying the collide connect flag won't work correctly because
/// the flag is only checked when fixture AABBs begin to overlap.
bool GetCollideConnected() const;
/// Dump this joint to the log file.
virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); }
/// Shift the origin for any points stored in world coordinates.
virtual void ShiftOrigin(const b2Vec2& newOrigin) { B2_NOT_USED(newOrigin); }
protected:
friend class b2World;
friend class b2Body;
friend class b2Island;
friend class b2GearJoint;
static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
b2Joint(const b2JointDef* def);
virtual ~b2Joint() {}
virtual void InitVelocityConstraints(const b2SolverData& data) = 0;
virtual void SolveVelocityConstraints(const b2SolverData& data) = 0;
// This returns true if the position errors are within tolerance.
virtual bool SolvePositionConstraints(const b2SolverData& data) = 0;
b2JointType m_type;
b2Joint* m_prev;
b2Joint* m_next;
b2JointEdge m_edgeA;
b2JointEdge m_edgeB;
b2Body* m_bodyA;
b2Body* m_bodyB;
int32 m_index;
bool m_islandFlag;
bool m_collideConnected;
void* m_userData;
};
inline b2JointType b2Joint::GetType() const
{
return m_type;
}
inline b2Body* b2Joint::GetBodyA()
{
return m_bodyA;
}
inline b2Body* b2Joint::GetBodyB()
{
return m_bodyB;
}
inline b2Joint* b2Joint::GetNext()
{
return m_next;
}
inline const b2Joint* b2Joint::GetNext() const
{
return m_next;
}
inline void* b2Joint::GetUserData() const
{
return m_userData;
}
inline void b2Joint::SetUserData(void* data)
{
m_userData = data;
}
inline bool b2Joint::GetCollideConnected() const
{
return m_collideConnected;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2MotorJoint.h
================================================
/*
* Copyright (c) 2006-2012 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MOTOR_JOINT_H
#define B2_MOTOR_JOINT_H
#include "b2Joint.h"
/// Motor joint definition.
struct b2MotorJointDef : public b2JointDef
{
b2MotorJointDef()
{
type = e_motorJoint;
linearOffset.SetZero();
angularOffset = 0.0f;
maxForce = 1.0f;
maxTorque = 1.0f;
correctionFactor = 0.3f;
}
/// Initialize the bodies and offsets using the current transforms.
void Initialize(b2Body* bodyA, b2Body* bodyB);
/// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters.
b2Vec2 linearOffset;
/// The bodyB angle minus bodyA angle in radians.
float32 angularOffset;
/// The maximum motor force in N.
float32 maxForce;
/// The maximum motor torque in N-m.
float32 maxTorque;
/// Position correction factor in the range [0,1].
float32 correctionFactor;
};
/// A motor joint is used to control the relative motion
/// between two bodies. A typical usage is to control the movement
/// of a dynamic body with respect to the ground.
class b2MotorJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Set/get the target linear offset, in frame A, in meters.
void SetLinearOffset(const b2Vec2& linearOffset);
const b2Vec2& GetLinearOffset() const;
/// Set/get the target angular offset, in radians.
void SetAngularOffset(float32 angularOffset);
float32 GetAngularOffset() const;
/// Set the maximum friction force in N.
void SetMaxForce(float32 force);
/// Get the maximum friction force in N.
float32 GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float32 torque);
/// Get the maximum friction torque in N*m.
float32 GetMaxTorque() const;
/// Set the position correction factor in the range [0,1].
void SetCorrectionFactor(float32 factor);
/// Get the position correction factor in the range [0,1].
float32 GetCorrectionFactor() const;
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2MotorJoint(const b2MotorJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_linearOffset;
float32 m_angularOffset;
b2Vec2 m_linearImpulse;
float32 m_angularImpulse;
float32 m_maxForce;
float32 m_maxTorque;
float32 m_correctionFactor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
b2Vec2 m_linearError;
float32 m_angularError;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat22 m_linearMass;
float32 m_angularMass;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2MouseJoint.h
================================================
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MOUSE_JOINT_H
#define B2_MOUSE_JOINT_H
#include "b2Joint.h"
/// Mouse joint definition. This requires a world target point,
/// tuning parameters, and the time step.
struct b2MouseJointDef : public b2JointDef
{
b2MouseJointDef()
{
type = e_mouseJoint;
target.Set(0.0f, 0.0f);
maxForce = 0.0f;
frequencyHz = 5.0f;
dampingRatio = 0.7f;
}
/// The initial world target point. This is assumed
/// to coincide with the body anchor initially.
b2Vec2 target;
/// The maximum constraint force that can be exerted
/// to move the candidate body. Usually you will express
/// as some multiple of the weight (multiplier * mass * gravity).
float32 maxForce;
/// The response speed.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A mouse joint is used to make a point on a body track a
/// specified world point. This a soft constraint with a maximum
/// force. This allows the constraint to stretch and without
/// applying huge forces.
/// NOTE: this joint is not documented in the manual because it was
/// developed to be used in the testbed. If you want to learn how to
/// use the mouse joint, look at the testbed.
class b2MouseJoint : public b2Joint
{
public:
/// Implements b2Joint.
b2Vec2 GetAnchorA() const;
/// Implements b2Joint.
b2Vec2 GetAnchorB() const;
/// Implements b2Joint.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Implements b2Joint.
float32 GetReactionTorque(float32 inv_dt) const;
/// Use this to update the target point.
void SetTarget(const b2Vec2& target);
const b2Vec2& GetTarget() const;
/// Set/get the maximum force in Newtons.
void SetMaxForce(float32 force);
float32 GetMaxForce() const;
/// Set/get the frequency in Hertz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
/// Set/get the damping ratio (dimensionless).
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
/// The mouse joint does not support dumping.
void Dump() { b2Log("Mouse joint dumping is not supported.\n"); }
/// Implement b2Joint::ShiftOrigin
void ShiftOrigin(const b2Vec2& newOrigin);
protected:
friend class b2Joint;
b2MouseJoint(const b2MouseJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Vec2 m_localAnchorB;
b2Vec2 m_targetA;
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_beta;
// Solver shared
b2Vec2 m_impulse;
float32 m_maxForce;
float32 m_gamma;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rB;
b2Vec2 m_localCenterB;
float32 m_invMassB;
float32 m_invIB;
b2Mat22 m_mass;
b2Vec2 m_C;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2PrismaticJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_PRISMATIC_JOINT_H
#define B2_PRISMATIC_JOINT_H
#include "b2Joint.h"
/// Prismatic joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct b2PrismaticJointDef : public b2JointDef
{
b2PrismaticJointDef()
{
type = e_prismaticJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
referenceAngle = 0.0f;
enableLimit = false;
lowerTranslation = 0.0f;
upperTranslation = 0.0f;
enableMotor = false;
maxMotorForce = 0.0f;
motorSpeed = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and unit world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The local translation unit axis in bodyA.
b2Vec2 localAxisA;
/// The constrained angle between the bodies: bodyB_angle - bodyA_angle.
float32 referenceAngle;
/// Enable/disable the joint limit.
bool enableLimit;
/// The lower translation limit, usually in meters.
float32 lowerTranslation;
/// The upper translation limit, usually in meters.
float32 upperTranslation;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float32 maxMotorForce;
/// The desired motor speed in radians per second.
float32 motorSpeed;
};
/// A prismatic joint. This joint provides one degree of freedom: translation
/// along an axis fixed in bodyA. Relative rotation is prevented. You can
/// use a joint limit to restrict the range of motion and a joint motor to
/// drive the motion or to model joint friction.
class b2PrismaticJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// The local joint axis relative to bodyA.
const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
/// Get the reference angle.
float32 GetReferenceAngle() const { return m_referenceAngle; }
/// Get the current joint translation, usually in meters.
float32 GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float32 GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit, usually in meters.
float32 GetLowerLimit() const;
/// Get the upper joint limit, usually in meters.
float32 GetUpperLimit() const;
/// Set the joint limits, usually in meters.
void SetLimits(float32 lower, float32 upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in meters per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed, usually in meters per second.
float32 GetMotorSpeed() const;
/// Set the maximum motor force, usually in N.
void SetMaxMotorForce(float32 force);
float32 GetMaxMotorForce() const { return m_maxMotorForce; }
/// Get the current motor force given the inverse time step, usually in N.
float32 GetMotorForce(float32 inv_dt) const;
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
friend class b2GearJoint;
b2PrismaticJoint(const b2PrismaticJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localXAxisA;
b2Vec2 m_localYAxisA;
float32 m_referenceAngle;
b2Vec3 m_impulse;
float32 m_motorImpulse;
float32 m_lowerTranslation;
float32 m_upperTranslation;
float32 m_maxMotorForce;
float32 m_motorSpeed;
bool m_enableLimit;
bool m_enableMotor;
b2LimitState m_limitState;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Vec2 m_axis, m_perp;
float32 m_s1, m_s2;
float32 m_a1, m_a2;
b2Mat33 m_K;
float32 m_motorMass;
};
inline float32 b2PrismaticJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2PulleyJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_PULLEY_JOINT_H
#define B2_PULLEY_JOINT_H
#include "b2Joint.h"
const float32 b2_minPulleyLength = 2.0f;
/// Pulley joint definition. This requires two ground anchors,
/// two dynamic body anchor points, and a pulley ratio.
struct b2PulleyJointDef : public b2JointDef
{
b2PulleyJointDef()
{
type = e_pulleyJoint;
groundAnchorA.Set(-1.0f, 1.0f);
groundAnchorB.Set(1.0f, 1.0f);
localAnchorA.Set(-1.0f, 0.0f);
localAnchorB.Set(1.0f, 0.0f);
lengthA = 0.0f;
lengthB = 0.0f;
ratio = 1.0f;
collideConnected = true;
}
/// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,
const b2Vec2& anchorA, const b2Vec2& anchorB,
float32 ratio);
/// The first ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorA;
/// The second ground anchor in world coordinates. This point never moves.
b2Vec2 groundAnchorB;
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The a reference length for the segment attached to bodyA.
float32 lengthA;
/// The a reference length for the segment attached to bodyB.
float32 lengthB;
/// The pulley ratio, used to simulate a block-and-tackle.
float32 ratio;
};
/// The pulley joint is connected to two bodies and two fixed ground points.
/// The pulley supports a ratio such that:
/// length1 + ratio * length2 <= constant
/// Yes, the force transmitted is scaled by the ratio.
/// Warning: the pulley joint can get a bit squirrelly by itself. They often
/// work better when combined with prismatic joints. You should also cover the
/// the anchor points with static shapes to prevent one side from going to
/// zero length.
class b2PulleyJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the first ground anchor.
b2Vec2 GetGroundAnchorA() const;
/// Get the second ground anchor.
b2Vec2 GetGroundAnchorB() const;
/// Get the current length of the segment attached to bodyA.
float32 GetLengthA() const;
/// Get the current length of the segment attached to bodyB.
float32 GetLengthB() const;
/// Get the pulley ratio.
float32 GetRatio() const;
/// Get the current length of the segment attached to bodyA.
float32 GetCurrentLengthA() const;
/// Get the current length of the segment attached to bodyB.
float32 GetCurrentLengthB() const;
/// Dump joint to dmLog
void Dump();
/// Implement b2Joint::ShiftOrigin
void ShiftOrigin(const b2Vec2& newOrigin);
protected:
friend class b2Joint;
b2PulleyJoint(const b2PulleyJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Vec2 m_groundAnchorA;
b2Vec2 m_groundAnchorB;
float32 m_lengthA;
float32 m_lengthB;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_constant;
float32 m_ratio;
float32 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_uA;
b2Vec2 m_uB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
float32 m_mass;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2RevoluteJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_REVOLUTE_JOINT_H
#define B2_REVOLUTE_JOINT_H
#include "b2Joint.h"
/// Revolute joint definition. This requires defining an
/// anchor point where the bodies are joined. The definition
/// uses local anchor points so that the initial configuration
/// can violate the constraint slightly. You also need to
/// specify the initial relative angle for joint limits. This
/// helps when saving and loading a game.
/// The local anchor points are measured from the body's origin
/// rather than the center of mass because:
/// 1. you might not know where the center of mass will be.
/// 2. if you add/remove shapes from a body and recompute the mass,
/// the joints will be broken.
struct b2RevoluteJointDef : public b2JointDef
{
b2RevoluteJointDef()
{
type = e_revoluteJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
lowerAngle = 0.0f;
upperAngle = 0.0f;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
enableLimit = false;
enableMotor = false;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The bodyB angle minus bodyA angle in the reference state (radians).
float32 referenceAngle;
/// A flag to enable joint limits.
bool enableLimit;
/// The lower angle for the joint limit (radians).
float32 lowerAngle;
/// The upper angle for the joint limit (radians).
float32 upperAngle;
/// A flag to enable the joint motor.
bool enableMotor;
/// The desired motor speed. Usually in radians per second.
float32 motorSpeed;
/// The maximum motor torque used to achieve the desired motor speed.
/// Usually in N-m.
float32 maxMotorTorque;
};
/// A revolute joint constrains two bodies to share a common point while they
/// are free to rotate about the point. The relative rotation about the shared
/// point is the joint angle. You can limit the relative rotation with
/// a joint limit that specifies a lower and upper angle. You can use a motor
/// to drive the relative rotation about the shared point. A maximum motor torque
/// is provided so that infinite forces are not generated.
class b2RevoluteJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the reference angle.
float32 GetReferenceAngle() const { return m_referenceAngle; }
/// Get the current joint angle in radians.
float32 GetJointAngle() const;
/// Get the current joint angle speed in radians per second.
float32 GetJointSpeed() const;
/// Is the joint limit enabled?
bool IsLimitEnabled() const;
/// Enable/disable the joint limit.
void EnableLimit(bool flag);
/// Get the lower joint limit in radians.
float32 GetLowerLimit() const;
/// Get the upper joint limit in radians.
float32 GetUpperLimit() const;
/// Set the joint limits in radians.
void SetLimits(float32 lower, float32 upper);
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed in radians per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed in radians per second.
float32 GetMotorSpeed() const;
/// Set the maximum motor torque, usually in N-m.
void SetMaxMotorTorque(float32 torque);
float32 GetMaxMotorTorque() const { return m_maxMotorTorque; }
/// Get the reaction force given the inverse time step.
/// Unit is N.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Get the reaction torque due to the joint limit given the inverse time step.
/// Unit is N*m.
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the current motor torque given the inverse time step.
/// Unit is N*m.
float32 GetMotorTorque(float32 inv_dt) const;
/// Dump to b2Log.
void Dump();
protected:
friend class b2Joint;
friend class b2GearJoint;
b2RevoluteJoint(const b2RevoluteJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec3 m_impulse;
float32 m_motorImpulse;
bool m_enableMotor;
float32 m_maxMotorTorque;
float32 m_motorSpeed;
bool m_enableLimit;
float32 m_referenceAngle;
float32 m_lowerAngle;
float32 m_upperAngle;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat33 m_mass; // effective mass for point-to-point constraint.
float32 m_motorMass; // effective mass for motor/limit angular constraint.
b2LimitState m_limitState;
};
inline float32 b2RevoluteJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2RopeJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_ROPE_JOINT_H
#define B2_ROPE_JOINT_H
#include "b2Joint.h"
/// Rope joint definition. This requires two body anchor points and
/// a maximum lengths.
/// Note: by default the connected objects will not collide.
/// see collideConnected in b2JointDef.
struct b2RopeJointDef : public b2JointDef
{
b2RopeJointDef()
{
type = e_ropeJoint;
localAnchorA.Set(-1.0f, 0.0f);
localAnchorB.Set(1.0f, 0.0f);
maxLength = 0.0f;
}
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum length of the rope.
/// Warning: this must be larger than b2_linearSlop or
/// the joint will have no effect.
float32 maxLength;
};
/// A rope joint enforces a maximum distance between two points
/// on two bodies. It has no other effect.
/// Warning: if you attempt to change the maximum length during
/// the simulation you will get some non-physical behavior.
/// A model that would allow you to dynamically modify the length
/// would have some sponginess, so I chose not to implement it
/// that way. See b2DistanceJoint if you want to dynamically
/// control length.
class b2RopeJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set/Get the maximum length of the rope.
void SetMaxLength(float32 length) { m_maxLength = length; }
float32 GetMaxLength() const;
b2LimitState GetLimitState() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2RopeJoint(const b2RopeJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_maxLength;
float32 m_length;
float32 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_u;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
float32 m_mass;
b2LimitState m_state;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2WeldJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WELD_JOINT_H
#define B2_WELD_JOINT_H
#include "b2Joint.h"
/// Weld joint definition. You need to specify local anchor points
/// where they are attached and the relative body angle. The position
/// of the anchor points is important for computing the reaction torque.
struct b2WeldJointDef : public b2JointDef
{
b2WeldJointDef()
{
type = e_weldJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
frequencyHz = 0.0f;
dampingRatio = 0.0f;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The bodyB angle minus bodyA angle in the reference state (radians).
float32 referenceAngle;
/// The mass-spring-damper frequency in Hertz. Rotation only.
/// Disable softness with a value of 0.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A weld joint essentially glues two bodies together. A weld joint may
/// distort somewhat because the island constraint solver is approximate.
class b2WeldJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the reference angle.
float32 GetReferenceAngle() const { return m_referenceAngle; }
/// Set/get frequency in Hz.
void SetFrequency(float32 hz) { m_frequencyHz = hz; }
float32 GetFrequency() const { return m_frequencyHz; }
/// Set/get damping ratio.
void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; }
float32 GetDampingRatio() const { return m_dampingRatio; }
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2WeldJoint(const b2WeldJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_bias;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_referenceAngle;
float32 m_gamma;
b2Vec3 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat33 m_mass;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/Joints/b2WheelJoint.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WHEEL_JOINT_H
#define B2_WHEEL_JOINT_H
#include "b2Joint.h"
/// Wheel joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct b2WheelJointDef : public b2JointDef
{
b2WheelJointDef()
{
type = e_wheelJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
enableMotor = false;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
frequencyHz = 2.0f;
dampingRatio = 0.7f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The local translation axis in bodyA.
b2Vec2 localAxisA;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float32 maxMotorTorque;
/// The desired motor speed in radians per second.
float32 motorSpeed;
/// Suspension frequency, zero indicates no suspension
float32 frequencyHz;
/// Suspension damping ratio, one indicates critical damping
float32 dampingRatio;
};
/// A wheel joint. This joint provides two degrees of freedom: translation
/// along an axis fixed in bodyA and rotation in the plane. You can use a
/// joint limit to restrict the range of motion and a joint motor to drive
/// the rotation or to model rotational friction.
/// This joint is designed for vehicle suspensions.
class b2WheelJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// The local joint axis relative to bodyA.
const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
/// Get the current joint translation, usually in meters.
float32 GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float32 GetJointSpeed() const;
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in radians per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed, usually in radians per second.
float32 GetMotorSpeed() const;
/// Set/Get the maximum motor force, usually in N-m.
void SetMaxMotorTorque(float32 torque);
float32 GetMaxMotorTorque() const;
/// Get the current motor torque given the inverse time step, usually in N-m.
float32 GetMotorTorque(float32 inv_dt) const;
/// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring.
void SetSpringFrequencyHz(float32 hz);
float32 GetSpringFrequencyHz() const;
/// Set/Get the spring damping ratio
void SetSpringDampingRatio(float32 ratio);
float32 GetSpringDampingRatio() const;
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2WheelJoint(const b2WheelJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localXAxisA;
b2Vec2 m_localYAxisA;
float32 m_impulse;
float32 m_motorImpulse;
float32 m_springImpulse;
float32 m_maxMotorTorque;
float32 m_motorSpeed;
bool m_enableMotor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Vec2 m_ax, m_ay;
float32 m_sAx, m_sBx;
float32 m_sAy, m_sBy;
float32 m_mass;
float32 m_motorMass;
float32 m_springMass;
float32 m_bias;
float32 m_gamma;
};
inline float32 b2WheelJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
inline float32 b2WheelJoint::GetMaxMotorTorque() const
{
return m_maxMotorTorque;
}
inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz)
{
m_frequencyHz = hz;
}
inline float32 b2WheelJoint::GetSpringFrequencyHz() const
{
return m_frequencyHz;
}
inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
inline float32 b2WheelJoint::GetSpringDampingRatio() const
{
return m_dampingRatio;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2Body.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_BODY_H
#define B2_BODY_H
#include "../Common/b2Math.h"
#include "../Collision/Shapes/b2Shape.h"
#include
class b2Fixture;
class b2Joint;
class b2Contact;
class b2Controller;
class b2World;
struct b2FixtureDef;
struct b2JointEdge;
struct b2ContactEdge;
/// The body type.
/// static: zero mass, zero velocity, may be manually moved
/// kinematic: zero mass, non-zero velocity set by user, moved by solver
/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver
enum b2BodyType
{
b2_staticBody = 0,
b2_kinematicBody,
b2_dynamicBody
// TODO_ERIN
//b2_bulletBody,
};
/// A body definition holds all the data needed to construct a rigid body.
/// You can safely re-use body definitions. Shapes are added to a body after construction.
struct b2BodyDef
{
/// This constructor sets the body definition default values.
b2BodyDef()
{
userData = NULL;
position.Set(0.0f, 0.0f);
angle = 0.0f;
linearVelocity.Set(0.0f, 0.0f);
angularVelocity = 0.0f;
linearDamping = 0.0f;
angularDamping = 0.0f;
allowSleep = true;
awake = true;
fixedRotation = false;
bullet = false;
type = b2_staticBody;
active = true;
gravityScale = 1.0f;
}
/// The body type: static, kinematic, or dynamic.
/// Note: if a dynamic body would have zero mass, the mass is set to one.
b2BodyType type;
/// The world position of the body. Avoid creating bodies at the origin
/// since this can lead to many overlapping shapes.
b2Vec2 position;
/// The world angle of the body in radians.
float32 angle;
/// The linear velocity of the body's origin in world co-ordinates.
b2Vec2 linearVelocity;
/// The angular velocity of the body.
float32 angularVelocity;
/// Linear damping is use to reduce the linear velocity. The damping parameter
/// can be larger than 1.0f but the damping effect becomes sensitive to the
/// time step when the damping parameter is large.
float32 linearDamping;
/// Angular damping is use to reduce the angular velocity. The damping parameter
/// can be larger than 1.0f but the damping effect becomes sensitive to the
/// time step when the damping parameter is large.
float32 angularDamping;
/// Set this flag to false if this body should never fall asleep. Note that
/// this increases CPU usage.
bool allowSleep;
/// Is this body initially awake or sleeping?
bool awake;
/// Should this body be prevented from rotating? Useful for characters.
bool fixedRotation;
/// Is this a fast moving body that should be prevented from tunneling through
/// other moving bodies? Note that all bodies are prevented from tunneling through
/// kinematic and static bodies. This setting is only considered on dynamic bodies.
/// @warning You should use this flag sparingly since it increases processing time.
bool bullet;
/// Does this body start out active?
bool active;
/// Use this to store application specific body data.
void* userData;
/// Scale the gravity applied to this body.
float32 gravityScale;
};
/// A rigid body. These are created via b2World::CreateBody.
class b2Body
{
public:
/// Creates a fixture and attach it to this body. Use this function if you need
/// to set some fixture parameters, like friction. Otherwise you can create the
/// fixture directly from a shape.
/// If the density is non-zero, this function automatically updates the mass of the body.
/// Contacts are not created until the next time step.
/// @param def the fixture definition.
/// @warning This function is locked during callbacks.
b2Fixture* CreateFixture(const b2FixtureDef* def);
/// Creates a fixture from a shape and attach it to this body.
/// This is a convenience function. Use b2FixtureDef if you need to set parameters
/// like friction, restitution, user data, or filtering.
/// If the density is non-zero, this function automatically updates the mass of the body.
/// @param shape the shape to be cloned.
/// @param density the shape density (set to zero for static bodies).
/// @warning This function is locked during callbacks.
b2Fixture* CreateFixture(const b2Shape* shape, float32 density);
/// Destroy a fixture. This removes the fixture from the broad-phase and
/// destroys all contacts associated with this fixture. This will
/// automatically adjust the mass of the body if the body is dynamic and the
/// fixture has positive density.
/// All fixtures attached to a body are implicitly destroyed when the body is destroyed.
/// @param fixture the fixture to be removed.
/// @warning This function is locked during callbacks.
void DestroyFixture(b2Fixture* fixture);
/// Set the position of the body's origin and rotation.
/// Manipulating a body's transform may cause non-physical behavior.
/// Note: contacts are updated on the next call to b2World::Step.
/// @param position the world position of the body's local origin.
/// @param angle the world rotation in radians.
void SetTransform(const b2Vec2& position, float32 angle);
/// Get the body transform for the body's origin.
/// @return the world transform of the body's origin.
const b2Transform& GetTransform() const;
/// Get the world body origin position.
/// @return the world position of the body's origin.
const b2Vec2& GetPosition() const;
/// Get the angle in radians.
/// @return the current world rotation angle in radians.
float32 GetAngle() const;
/// Get the world position of the center of mass.
const b2Vec2& GetWorldCenter() const;
/// Get the local position of the center of mass.
const b2Vec2& GetLocalCenter() const;
/// Set the linear velocity of the center of mass.
/// @param v the new linear velocity of the center of mass.
void SetLinearVelocity(const b2Vec2& v);
/// Get the linear velocity of the center of mass.
/// @return the linear velocity of the center of mass.
const b2Vec2& GetLinearVelocity() const;
/// Set the angular velocity.
/// @param omega the new angular velocity in radians/second.
void SetAngularVelocity(float32 omega);
/// Get the angular velocity.
/// @return the angular velocity in radians/second.
float32 GetAngularVelocity() const;
/// Apply a force at a world point. If the force is not
/// applied at the center of mass, it will generate a torque and
/// affect the angular velocity. This wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param point the world position of the point of application.
/// @param wake also wake up the body
void ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake);
/// Apply a force to the center of mass. This wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param wake also wake up the body
void ApplyForceToCenter(const b2Vec2& force, bool wake);
/// Apply a torque. This affects the angular velocity
/// without affecting the linear velocity of the center of mass.
/// This wakes up the body.
/// @param torque about the z-axis (out of the screen), usually in N-m.
/// @param wake also wake up the body
void ApplyTorque(float32 torque, bool wake);
/// Apply an impulse at a point. This immediately modifies the velocity.
/// It also modifies the angular velocity if the point of application
/// is not at the center of mass. This wakes up the body.
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
/// @param point the world position of the point of application.
/// @param wake also wake up the body
void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake);
/// Apply an angular impulse.
/// @param impulse the angular impulse in units of kg*m*m/s
/// @param wake also wake up the body
void ApplyAngularImpulse(float32 impulse, bool wake);
/// Get the total mass of the body.
/// @return the mass, usually in kilograms (kg).
float32 GetMass() const;
/// Get the rotational inertia of the body about the local origin.
/// @return the rotational inertia, usually in kg-m^2.
float32 GetInertia() const;
/// Get the mass data of the body.
/// @return a struct containing the mass, inertia and center of the body.
void GetMassData(b2MassData* data) const;
/// Set the mass properties to override the mass properties of the fixtures.
/// Note that this changes the center of mass position.
/// Note that creating or destroying fixtures can also alter the mass.
/// This function has no effect if the body isn't dynamic.
/// @param massData the mass properties.
void SetMassData(const b2MassData* data);
/// This resets the mass properties to the sum of the mass properties of the fixtures.
/// This normally does not need to be called unless you called SetMassData to override
/// the mass and you later want to reset the mass.
void ResetMassData();
/// Get the world coordinates of a point given the local coordinates.
/// @param localPoint a point on the body measured relative the the body's origin.
/// @return the same point expressed in world coordinates.
b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const;
/// Get the world coordinates of a vector given the local coordinates.
/// @param localVector a vector fixed in the body.
/// @return the same vector expressed in world coordinates.
b2Vec2 GetWorldVector(const b2Vec2& localVector) const;
/// Gets a local point relative to the body's origin given a world point.
/// @param a point in world coordinates.
/// @return the corresponding local point relative to the body's origin.
b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;
/// Gets a local vector given a world vector.
/// @param a vector in world coordinates.
/// @return the corresponding local vector.
b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;
/// Get the world linear velocity of a world point attached to this body.
/// @param a point in world coordinates.
/// @return the world velocity of a point.
b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;
/// Get the world velocity of a local point.
/// @param a point in local coordinates.
/// @return the world velocity of a point.
b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;
/// Get the linear damping of the body.
float32 GetLinearDamping() const;
/// Set the linear damping of the body.
void SetLinearDamping(float32 linearDamping);
/// Get the angular damping of the body.
float32 GetAngularDamping() const;
/// Set the angular damping of the body.
void SetAngularDamping(float32 angularDamping);
/// Get the gravity scale of the body.
float32 GetGravityScale() const;
/// Set the gravity scale of the body.
void SetGravityScale(float32 scale);
/// Set the type of this body. This may alter the mass and velocity.
void SetType(b2BodyType type);
/// Get the type of this body.
b2BodyType GetType() const;
/// Should this body be treated like a bullet for continuous collision detection?
void SetBullet(bool flag);
/// Is this body treated like a bullet for continuous collision detection?
bool IsBullet() const;
/// You can disable sleeping on this body. If you disable sleeping, the
/// body will be woken.
void SetSleepingAllowed(bool flag);
/// Is this body allowed to sleep
bool IsSleepingAllowed() const;
/// Set the sleep state of the body. A sleeping body has very
/// low CPU cost.
/// @param flag set to true to wake the body, false to put it to sleep.
void SetAwake(bool flag);
/// Get the sleeping state of this body.
/// @return true if the body is awake.
bool IsAwake() const;
/// Set the active state of the body. An inactive body is not
/// simulated and cannot be collided with or woken up.
/// If you pass a flag of true, all fixtures will be added to the
/// broad-phase.
/// If you pass a flag of false, all fixtures will be removed from
/// the broad-phase and all contacts will be destroyed.
/// Fixtures and joints are otherwise unaffected. You may continue
/// to create/destroy fixtures and joints on inactive bodies.
/// Fixtures on an inactive body are implicitly inactive and will
/// not participate in collisions, ray-casts, or queries.
/// Joints connected to an inactive body are implicitly inactive.
/// An inactive body is still owned by a b2World object and remains
/// in the body list.
void SetActive(bool flag);
/// Get the active state of the body.
bool IsActive() const;
/// Set this body to have fixed rotation. This causes the mass
/// to be reset.
void SetFixedRotation(bool flag);
/// Does this body have fixed rotation?
bool IsFixedRotation() const;
/// Get the list of all fixtures attached to this body.
b2Fixture* GetFixtureList();
const b2Fixture* GetFixtureList() const;
/// Get the list of all joints attached to this body.
b2JointEdge* GetJointList();
const b2JointEdge* GetJointList() const;
/// Get the list of all contacts attached to this body.
/// @warning this list changes during the time step and you may
/// miss some collisions if you don't use b2ContactListener.
b2ContactEdge* GetContactList();
const b2ContactEdge* GetContactList() const;
/// Get the next body in the world's body list.
b2Body* GetNext();
const b2Body* GetNext() const;
/// Get the user data pointer that was provided in the body definition.
void* GetUserData() const;
/// Set the user data. Use this to store your application specific data.
void SetUserData(void* data);
/// Get the parent world of this body.
b2World* GetWorld();
const b2World* GetWorld() const;
/// Dump this body to a log file
void Dump();
private:
friend class b2World;
friend class b2Island;
friend class b2ContactManager;
friend class b2ContactSolver;
friend class b2Contact;
friend class b2DistanceJoint;
friend class b2FrictionJoint;
friend class b2GearJoint;
friend class b2MotorJoint;
friend class b2MouseJoint;
friend class b2PrismaticJoint;
friend class b2PulleyJoint;
friend class b2RevoluteJoint;
friend class b2RopeJoint;
friend class b2WeldJoint;
friend class b2WheelJoint;
// m_flags
enum
{
e_islandFlag = 0x0001,
e_awakeFlag = 0x0002,
e_autoSleepFlag = 0x0004,
e_bulletFlag = 0x0008,
e_fixedRotationFlag = 0x0010,
e_activeFlag = 0x0020,
e_toiFlag = 0x0040
};
b2Body(const b2BodyDef* bd, b2World* world);
~b2Body();
void SynchronizeFixtures();
void SynchronizeTransform();
// This is used to prevent connected bodies from colliding.
// It may lie, depending on the collideConnected flag.
bool ShouldCollide(const b2Body* other) const;
void Advance(float32 t);
b2BodyType m_type;
uint16 m_flags;
int32 m_islandIndex;
b2Transform m_xf; // the body origin transform
b2Sweep m_sweep; // the swept motion for CCD
b2Vec2 m_linearVelocity;
float32 m_angularVelocity;
b2Vec2 m_force;
float32 m_torque;
b2World* m_world;
b2Body* m_prev;
b2Body* m_next;
b2Fixture* m_fixtureList;
int32 m_fixtureCount;
b2JointEdge* m_jointList;
b2ContactEdge* m_contactList;
float32 m_mass, m_invMass;
// Rotational inertia about the center of mass.
float32 m_I, m_invI;
float32 m_linearDamping;
float32 m_angularDamping;
float32 m_gravityScale;
float32 m_sleepTime;
void* m_userData;
};
inline b2BodyType b2Body::GetType() const
{
return m_type;
}
inline const b2Transform& b2Body::GetTransform() const
{
return m_xf;
}
inline const b2Vec2& b2Body::GetPosition() const
{
return m_xf.p;
}
inline float32 b2Body::GetAngle() const
{
return m_sweep.a;
}
inline const b2Vec2& b2Body::GetWorldCenter() const
{
return m_sweep.c;
}
inline const b2Vec2& b2Body::GetLocalCenter() const
{
return m_sweep.localCenter;
}
inline void b2Body::SetLinearVelocity(const b2Vec2& v)
{
if (m_type == b2_staticBody)
{
return;
}
if (b2Dot(v,v) > 0.0f)
{
SetAwake(true);
}
m_linearVelocity = v;
}
inline const b2Vec2& b2Body::GetLinearVelocity() const
{
return m_linearVelocity;
}
inline void b2Body::SetAngularVelocity(float32 w)
{
if (m_type == b2_staticBody)
{
return;
}
if (w * w > 0.0f)
{
SetAwake(true);
}
m_angularVelocity = w;
}
inline float32 b2Body::GetAngularVelocity() const
{
return m_angularVelocity;
}
inline float32 b2Body::GetMass() const
{
return m_mass;
}
inline float32 b2Body::GetInertia() const
{
return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
}
inline void b2Body::GetMassData(b2MassData* data) const
{
data->mass = m_mass;
data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
data->center = m_sweep.localCenter;
}
inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const
{
return b2Mul(m_xf, localPoint);
}
inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const
{
return b2Mul(m_xf.q, localVector);
}
inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
{
return b2MulT(m_xf, worldPoint);
}
inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const
{
return b2MulT(m_xf.q, worldVector);
}
inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const
{
return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c);
}
inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const
{
return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
}
inline float32 b2Body::GetLinearDamping() const
{
return m_linearDamping;
}
inline void b2Body::SetLinearDamping(float32 linearDamping)
{
m_linearDamping = linearDamping;
}
inline float32 b2Body::GetAngularDamping() const
{
return m_angularDamping;
}
inline void b2Body::SetAngularDamping(float32 angularDamping)
{
m_angularDamping = angularDamping;
}
inline float32 b2Body::GetGravityScale() const
{
return m_gravityScale;
}
inline void b2Body::SetGravityScale(float32 scale)
{
m_gravityScale = scale;
}
inline void b2Body::SetBullet(bool flag)
{
if (flag)
{
m_flags |= e_bulletFlag;
}
else
{
m_flags &= ~e_bulletFlag;
}
}
inline bool b2Body::IsBullet() const
{
return (m_flags & e_bulletFlag) == e_bulletFlag;
}
inline void b2Body::SetAwake(bool flag)
{
if (flag)
{
if ((m_flags & e_awakeFlag) == 0)
{
m_flags |= e_awakeFlag;
m_sleepTime = 0.0f;
}
}
else
{
m_flags &= ~e_awakeFlag;
m_sleepTime = 0.0f;
m_linearVelocity.SetZero();
m_angularVelocity = 0.0f;
m_force.SetZero();
m_torque = 0.0f;
}
}
inline bool b2Body::IsAwake() const
{
return (m_flags & e_awakeFlag) == e_awakeFlag;
}
inline bool b2Body::IsActive() const
{
return (m_flags & e_activeFlag) == e_activeFlag;
}
inline bool b2Body::IsFixedRotation() const
{
return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
}
inline void b2Body::SetSleepingAllowed(bool flag)
{
if (flag)
{
m_flags |= e_autoSleepFlag;
}
else
{
m_flags &= ~e_autoSleepFlag;
SetAwake(true);
}
}
inline bool b2Body::IsSleepingAllowed() const
{
return (m_flags & e_autoSleepFlag) == e_autoSleepFlag;
}
inline b2Fixture* b2Body::GetFixtureList()
{
return m_fixtureList;
}
inline const b2Fixture* b2Body::GetFixtureList() const
{
return m_fixtureList;
}
inline b2JointEdge* b2Body::GetJointList()
{
return m_jointList;
}
inline const b2JointEdge* b2Body::GetJointList() const
{
return m_jointList;
}
inline b2ContactEdge* b2Body::GetContactList()
{
return m_contactList;
}
inline const b2ContactEdge* b2Body::GetContactList() const
{
return m_contactList;
}
inline b2Body* b2Body::GetNext()
{
return m_next;
}
inline const b2Body* b2Body::GetNext() const
{
return m_next;
}
inline void b2Body::SetUserData(void* data)
{
m_userData = data;
}
inline void* b2Body::GetUserData() const
{
return m_userData;
}
inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate a force if the body is sleeping.
if (m_flags & e_awakeFlag)
{
m_force += force;
m_torque += b2Cross(point - m_sweep.c, force);
}
}
inline void b2Body::ApplyForceToCenter(const b2Vec2& force, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate a force if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_force += force;
}
}
inline void b2Body::ApplyTorque(float32 torque, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate a force if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_torque += torque;
}
}
inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_linearVelocity += m_invMass * impulse;
m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
}
}
inline void b2Body::ApplyAngularImpulse(float32 impulse, bool wake)
{
if (m_type != b2_dynamicBody)
{
return;
}
if (wake && (m_flags & e_awakeFlag) == 0)
{
SetAwake(true);
}
// Don't accumulate velocity if the body is sleeping
if (m_flags & e_awakeFlag)
{
m_angularVelocity += m_invI * impulse;
}
}
inline void b2Body::SynchronizeTransform()
{
m_xf.q.Set(m_sweep.a);
m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}
inline void b2Body::Advance(float32 alpha)
{
// Advance to the new safe time. This doesn't sync the broad-phase.
m_sweep.Advance(alpha);
m_sweep.c = m_sweep.c0;
m_sweep.a = m_sweep.a0;
m_xf.q.Set(m_sweep.a);
m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
}
inline b2World* b2Body::GetWorld()
{
return m_world;
}
inline const b2World* b2Body::GetWorld() const
{
return m_world;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2ContactManager.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_MANAGER_H
#define B2_CONTACT_MANAGER_H
#include "../Collision/b2BroadPhase.h"
class b2Contact;
class b2ContactFilter;
class b2ContactListener;
class b2BlockAllocator;
// Delegate of b2World.
class b2ContactManager
{
public:
b2ContactManager();
// Broad-phase callback.
void AddPair(void* proxyUserDataA, void* proxyUserDataB);
void FindNewContacts();
void Destroy(b2Contact* c);
void Collide();
b2BroadPhase m_broadPhase;
b2Contact* m_contactList;
int32 m_contactCount;
b2ContactFilter* m_contactFilter;
b2ContactListener* m_contactListener;
b2BlockAllocator* m_allocator;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2Fixture.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_FIXTURE_H
#define B2_FIXTURE_H
#include "b2Body.h"
#include "../Collision/b2Collision.h"
#include "../Collision/Shapes/b2Shape.h"
class b2BlockAllocator;
class b2Body;
class b2BroadPhase;
class b2Fixture;
/// This holds contact filtering data.
struct b2Filter
{
b2Filter()
{
categoryBits = 0x0001;
maskBits = 0xFFFF;
groupIndex = 0;
}
/// The collision category bits. Normally you would just set one bit.
uint16 categoryBits;
/// The collision mask bits. This states the categories that this
/// shape would accept for collision.
uint16 maskBits;
/// Collision groups allow a certain group of objects to never collide (negative)
/// or always collide (positive). Zero means no collision group. Non-zero group
/// filtering always wins against the mask bits.
int16 groupIndex;
};
/// A fixture definition is used to create a fixture. This class defines an
/// abstract fixture definition. You can reuse fixture definitions safely.
struct b2FixtureDef
{
/// The constructor sets the default fixture definition values.
b2FixtureDef()
{
shape = NULL;
userData = NULL;
friction = 0.2f;
restitution = 0.0f;
density = 0.0f;
isSensor = false;
}
/// The shape, this must be set. The shape will be cloned, so you
/// can create the shape on the stack.
const b2Shape* shape;
/// Use this to store application specific fixture data.
void* userData;
/// The friction coefficient, usually in the range [0,1].
float32 friction;
/// The restitution (elasticity) usually in the range [0,1].
float32 restitution;
/// The density, usually in kg/m^2.
float32 density;
/// A sensor shape collects contact information but never generates a collision
/// response.
bool isSensor;
/// Contact filtering data.
b2Filter filter;
};
/// This proxy is used internally to connect fixtures to the broad-phase.
struct b2FixtureProxy
{
b2AABB aabb;
b2Fixture* fixture;
int32 childIndex;
int32 proxyId;
};
/// A fixture is used to attach a shape to a body for collision detection. A fixture
/// inherits its transform from its parent. Fixtures hold additional non-geometric data
/// such as friction, collision filters, etc.
/// Fixtures are created via b2Body::CreateFixture.
/// @warning you cannot reuse fixtures.
class b2Fixture
{
public:
/// Get the type of the child shape. You can use this to down cast to the concrete shape.
/// @return the shape type.
b2Shape::Type GetType() const;
/// Get the child shape. You can modify the child shape, however you should not change the
/// number of vertices because this will crash some collision caching mechanisms.
/// Manipulating the shape may lead to non-physical behavior.
b2Shape* GetShape();
const b2Shape* GetShape() const;
/// Set if this fixture is a sensor.
void SetSensor(bool sensor);
/// Is this fixture a sensor (non-solid)?
/// @return the true if the shape is a sensor.
bool IsSensor() const;
/// Set the contact filtering data. This will not update contacts until the next time
/// step when either parent body is active and awake.
/// This automatically calls Refilter.
void SetFilterData(const b2Filter& filter);
/// Get the contact filtering data.
const b2Filter& GetFilterData() const;
/// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide.
void Refilter();
/// Get the parent body of this fixture. This is NULL if the fixture is not attached.
/// @return the parent body.
b2Body* GetBody();
const b2Body* GetBody() const;
/// Get the next fixture in the parent body's fixture list.
/// @return the next shape.
b2Fixture* GetNext();
const b2Fixture* GetNext() const;
/// Get the user data that was assigned in the fixture definition. Use this to
/// store your application specific data.
void* GetUserData() const;
/// Set the user data. Use this to store your application specific data.
void SetUserData(void* data);
/// Test a point for containment in this fixture.
/// @param p a point in world coordinates.
bool TestPoint(const b2Vec2& p) const;
/// Cast a ray against this shape.
/// @param output the ray-cast results.
/// @param input the ray-cast input parameters.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const;
/// Get the mass data for this fixture. The mass data is based on the density and
/// the shape. The rotational inertia is about the shape's origin. This operation
/// may be expensive.
void GetMassData(b2MassData* massData) const;
/// Set the density of this fixture. This will _not_ automatically adjust the mass
/// of the body. You must call b2Body::ResetMassData to update the body's mass.
void SetDensity(float32 density);
/// Get the density of this fixture.
float32 GetDensity() const;
/// Get the coefficient of friction.
float32 GetFriction() const;
/// Set the coefficient of friction. This will _not_ change the friction of
/// existing contacts.
void SetFriction(float32 friction);
/// Get the coefficient of restitution.
float32 GetRestitution() const;
/// Set the coefficient of restitution. This will _not_ change the restitution of
/// existing contacts.
void SetRestitution(float32 restitution);
/// Get the fixture's AABB. This AABB may be enlarge and/or stale.
/// If you need a more accurate AABB, compute it using the shape and
/// the body transform.
const b2AABB& GetAABB(int32 childIndex) const;
/// Dump this fixture to the log file.
void Dump(int32 bodyIndex);
protected:
friend class b2Body;
friend class b2World;
friend class b2Contact;
friend class b2ContactManager;
b2Fixture();
// We need separation create/destroy functions from the constructor/destructor because
// the destructor cannot access the allocator (no destructor arguments allowed by C++).
void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def);
void Destroy(b2BlockAllocator* allocator);
// These support body activation/deactivation.
void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf);
void DestroyProxies(b2BroadPhase* broadPhase);
void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2);
float32 m_density;
b2Fixture* m_next;
b2Body* m_body;
b2Shape* m_shape;
float32 m_friction;
float32 m_restitution;
b2FixtureProxy* m_proxies;
int32 m_proxyCount;
b2Filter m_filter;
bool m_isSensor;
void* m_userData;
};
inline b2Shape::Type b2Fixture::GetType() const
{
return m_shape->GetType();
}
inline b2Shape* b2Fixture::GetShape()
{
return m_shape;
}
inline const b2Shape* b2Fixture::GetShape() const
{
return m_shape;
}
inline bool b2Fixture::IsSensor() const
{
return m_isSensor;
}
inline const b2Filter& b2Fixture::GetFilterData() const
{
return m_filter;
}
inline void* b2Fixture::GetUserData() const
{
return m_userData;
}
inline void b2Fixture::SetUserData(void* data)
{
m_userData = data;
}
inline b2Body* b2Fixture::GetBody()
{
return m_body;
}
inline const b2Body* b2Fixture::GetBody() const
{
return m_body;
}
inline b2Fixture* b2Fixture::GetNext()
{
return m_next;
}
inline const b2Fixture* b2Fixture::GetNext() const
{
return m_next;
}
inline void b2Fixture::SetDensity(float32 density)
{
b2Assert(b2IsValid(density) && density >= 0.0f);
m_density = density;
}
inline float32 b2Fixture::GetDensity() const
{
return m_density;
}
inline float32 b2Fixture::GetFriction() const
{
return m_friction;
}
inline void b2Fixture::SetFriction(float32 friction)
{
m_friction = friction;
}
inline float32 b2Fixture::GetRestitution() const
{
return m_restitution;
}
inline void b2Fixture::SetRestitution(float32 restitution)
{
m_restitution = restitution;
}
inline bool b2Fixture::TestPoint(const b2Vec2& p) const
{
return m_shape->TestPoint(m_body->GetTransform(), p);
}
inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const
{
return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex);
}
inline void b2Fixture::GetMassData(b2MassData* massData) const
{
m_shape->ComputeMass(massData, m_density);
}
inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const
{
b2Assert(0 <= childIndex && childIndex < m_proxyCount);
return m_proxies[childIndex].aabb;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2Island.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_ISLAND_H
#define B2_ISLAND_H
#include "../Common/b2Math.h"
#include "b2Body.h"
#include "b2TimeStep.h"
class b2Contact;
class b2Joint;
class b2StackAllocator;
class b2ContactListener;
struct b2ContactVelocityConstraint;
struct b2Profile;
/// This is an internal class.
class b2Island
{
public:
b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity,
b2StackAllocator* allocator, b2ContactListener* listener);
~b2Island();
void Clear()
{
m_bodyCount = 0;
m_contactCount = 0;
m_jointCount = 0;
}
void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep);
void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB);
void Add(b2Body* body)
{
b2Assert(m_bodyCount < m_bodyCapacity);
body->m_islandIndex = m_bodyCount;
m_bodies[m_bodyCount] = body;
++m_bodyCount;
}
void Add(b2Contact* contact)
{
b2Assert(m_contactCount < m_contactCapacity);
m_contacts[m_contactCount++] = contact;
}
void Add(b2Joint* joint)
{
b2Assert(m_jointCount < m_jointCapacity);
m_joints[m_jointCount++] = joint;
}
void Report(const b2ContactVelocityConstraint* constraints);
b2StackAllocator* m_allocator;
b2ContactListener* m_listener;
b2Body** m_bodies;
b2Contact** m_contacts;
b2Joint** m_joints;
b2Position* m_positions;
b2Velocity* m_velocities;
int32 m_bodyCount;
int32 m_jointCount;
int32 m_contactCount;
int32 m_bodyCapacity;
int32 m_contactCapacity;
int32 m_jointCapacity;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2TimeStep.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIME_STEP_H
#define B2_TIME_STEP_H
#include "../Common/b2Math.h"
/// Profiling data. Times are in milliseconds.
struct b2Profile
{
float32 step;
float32 collide;
float32 solve;
float32 solveInit;
float32 solveVelocity;
float32 solvePosition;
float32 broadphase;
float32 solveTOI;
};
/// This is an internal structure.
struct b2TimeStep
{
float32 dt; // time step
float32 inv_dt; // inverse time step (0 if dt == 0).
float32 dtRatio; // dt * inv_dt0
int32 velocityIterations;
int32 positionIterations;
bool warmStarting;
};
/// This is an internal structure.
struct b2Position
{
b2Vec2 c;
float32 a;
};
/// This is an internal structure.
struct b2Velocity
{
b2Vec2 v;
float32 w;
};
/// Solver Data
struct b2SolverData
{
b2TimeStep step;
b2Position* positions;
b2Velocity* velocities;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2World.h
================================================
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WORLD_H
#define B2_WORLD_H
#include "../Common/b2Math.h"
#include "../Common/b2BlockAllocator.h"
#include "../Common/b2StackAllocator.h"
#include "b2ContactManager.h"
#include "b2WorldCallbacks.h"
#include "b2TimeStep.h"
struct b2AABB;
struct b2BodyDef;
struct b2Color;
struct b2JointDef;
class b2Body;
class b2Draw;
class b2Fixture;
class b2Joint;
/// The world class manages all physics entities, dynamic simulation,
/// and asynchronous queries. The world also contains efficient memory
/// management facilities.
class b2World
{
public:
/// Construct a world object.
/// @param gravity the world gravity vector.
b2World(const b2Vec2& gravity);
/// Destruct the world. All physics entities are destroyed and all heap memory is released.
~b2World();
/// Register a destruction listener. The listener is owned by you and must
/// remain in scope.
void SetDestructionListener(b2DestructionListener* listener);
/// Register a contact filter to provide specific control over collision.
/// Otherwise the default filter is used (b2_defaultFilter). The listener is
/// owned by you and must remain in scope.
void SetContactFilter(b2ContactFilter* filter);
/// Register a contact event listener. The listener is owned by you and must
/// remain in scope.
void SetContactListener(b2ContactListener* listener);
/// Register a routine for debug drawing. The debug draw functions are called
/// inside with b2World::DrawDebugData method. The debug draw object is owned
/// by you and must remain in scope.
void SetDebugDraw(b2Draw* debugDraw);
/// Create a rigid body given a definition. No reference to the definition
/// is retained.
/// @warning This function is locked during callbacks.
b2Body* CreateBody(const b2BodyDef* def);
/// Destroy a rigid body given a definition. No reference to the definition
/// is retained. This function is locked during callbacks.
/// @warning This automatically deletes all associated shapes and joints.
/// @warning This function is locked during callbacks.
void DestroyBody(b2Body* body);
/// Create a joint to constrain bodies together. No reference to the definition
/// is retained. This may cause the connected bodies to cease colliding.
/// @warning This function is locked during callbacks.
b2Joint* CreateJoint(const b2JointDef* def);
/// Destroy a joint. This may cause the connected bodies to begin colliding.
/// @warning This function is locked during callbacks.
void DestroyJoint(b2Joint* joint);
/// Take a time step. This performs collision detection, integration,
/// and constraint solution.
/// @param timeStep the amount of time to simulate, this should not vary.
/// @param velocityIterations for the velocity constraint solver.
/// @param positionIterations for the position constraint solver.
void Step( float32 timeStep,
int32 velocityIterations,
int32 positionIterations);
/// Manually clear the force buffer on all bodies. By default, forces are cleared automatically
/// after each call to Step. The default behavior is modified by calling SetAutoClearForces.
/// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain
/// a fixed sized time step under a variable frame-rate.
/// When you perform sub-stepping you will disable auto clearing of forces and instead call
/// ClearForces after all sub-steps are complete in one pass of your game loop.
/// @see SetAutoClearForces
void ClearForces();
/// Call this to draw shapes and other debug draw data. This is intentionally non-const.
void DrawDebugData();
/// Query the world for all fixtures that potentially overlap the
/// provided AABB.
/// @param callback a user implemented callback class.
/// @param aabb the query box.
void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const;
/// Ray-cast the world for all fixtures in the path of the ray. Your callback
/// controls whether you get the closest point, any point, or n-points.
/// The ray-cast ignores shapes that contain the starting point.
/// @param callback a user implemented callback class.
/// @param point1 the ray starting point
/// @param point2 the ray ending point
void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const;
/// Get the world body list. With the returned body, use b2Body::GetNext to get
/// the next body in the world list. A NULL body indicates the end of the list.
/// @return the head of the world body list.
b2Body* GetBodyList();
const b2Body* GetBodyList() const;
/// Get the world joint list. With the returned joint, use b2Joint::GetNext to get
/// the next joint in the world list. A NULL joint indicates the end of the list.
/// @return the head of the world joint list.
b2Joint* GetJointList();
const b2Joint* GetJointList() const;
/// Get the world contact list. With the returned contact, use b2Contact::GetNext to get
/// the next contact in the world list. A NULL contact indicates the end of the list.
/// @return the head of the world contact list.
/// @warning contacts are created and destroyed in the middle of a time step.
/// Use b2ContactListener to avoid missing contacts.
b2Contact* GetContactList();
const b2Contact* GetContactList() const;
/// Enable/disable sleep.
void SetAllowSleeping(bool flag);
bool GetAllowSleeping() const { return m_allowSleep; }
/// Enable/disable warm starting. For testing.
void SetWarmStarting(bool flag) { m_warmStarting = flag; }
bool GetWarmStarting() const { return m_warmStarting; }
/// Enable/disable continuous physics. For testing.
void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; }
bool GetContinuousPhysics() const { return m_continuousPhysics; }
/// Enable/disable single stepped continuous physics. For testing.
void SetSubStepping(bool flag) { m_subStepping = flag; }
bool GetSubStepping() const { return m_subStepping; }
/// Get the number of broad-phase proxies.
int32 GetProxyCount() const;
/// Get the number of bodies.
int32 GetBodyCount() const;
/// Get the number of joints.
int32 GetJointCount() const;
/// Get the number of contacts (each may have 0 or more contact points).
int32 GetContactCount() const;
/// Get the height of the dynamic tree.
int32 GetTreeHeight() const;
/// Get the balance of the dynamic tree.
int32 GetTreeBalance() const;
/// Get the quality metric of the dynamic tree. The smaller the better.
/// The minimum is 1.
float32 GetTreeQuality() const;
/// Change the global gravity vector.
void SetGravity(const b2Vec2& gravity);
/// Get the global gravity vector.
b2Vec2 GetGravity() const;
/// Is the world locked (in the middle of a time step).
bool IsLocked() const;
/// Set flag to control automatic clearing of forces after each time step.
void SetAutoClearForces(bool flag);
/// Get the flag that controls automatic clearing of forces after each time step.
bool GetAutoClearForces() const;
/// Shift the world origin. Useful for large worlds.
/// The body shift formula is: position -= newOrigin
/// @param newOrigin the new origin with respect to the old origin
void ShiftOrigin(const b2Vec2& newOrigin);
/// Get the contact manager for testing.
const b2ContactManager& GetContactManager() const;
/// Get the current profile.
const b2Profile& GetProfile() const;
/// Dump the world into the log file.
/// @warning this should be called outside of a time step.
void Dump();
private:
// m_flags
enum
{
e_newFixture = 0x0001,
e_locked = 0x0002,
e_clearForces = 0x0004
};
friend class b2Body;
friend class b2Fixture;
friend class b2ContactManager;
friend class b2Controller;
void Solve(const b2TimeStep& step);
void SolveTOI(const b2TimeStep& step);
void DrawJoint(b2Joint* joint);
void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color);
b2BlockAllocator m_blockAllocator;
b2StackAllocator m_stackAllocator;
int32 m_flags;
b2ContactManager m_contactManager;
b2Body* m_bodyList;
b2Joint* m_jointList;
int32 m_bodyCount;
int32 m_jointCount;
b2Vec2 m_gravity;
bool m_allowSleep;
b2DestructionListener* m_destructionListener;
b2Draw* m_debugDraw;
// This is used to compute the time step ratio to
// support a variable time step.
float32 m_inv_dt0;
// These are for debugging the solver.
bool m_warmStarting;
bool m_continuousPhysics;
bool m_subStepping;
bool m_stepComplete;
b2Profile m_profile;
};
inline b2Body* b2World::GetBodyList()
{
return m_bodyList;
}
inline const b2Body* b2World::GetBodyList() const
{
return m_bodyList;
}
inline b2Joint* b2World::GetJointList()
{
return m_jointList;
}
inline const b2Joint* b2World::GetJointList() const
{
return m_jointList;
}
inline b2Contact* b2World::GetContactList()
{
return m_contactManager.m_contactList;
}
inline const b2Contact* b2World::GetContactList() const
{
return m_contactManager.m_contactList;
}
inline int32 b2World::GetBodyCount() const
{
return m_bodyCount;
}
inline int32 b2World::GetJointCount() const
{
return m_jointCount;
}
inline int32 b2World::GetContactCount() const
{
return m_contactManager.m_contactCount;
}
inline void b2World::SetGravity(const b2Vec2& gravity)
{
m_gravity = gravity;
}
inline b2Vec2 b2World::GetGravity() const
{
return m_gravity;
}
inline bool b2World::IsLocked() const
{
return (m_flags & e_locked) == e_locked;
}
inline void b2World::SetAutoClearForces(bool flag)
{
if (flag)
{
m_flags |= e_clearForces;
}
else
{
m_flags &= ~e_clearForces;
}
}
/// Get the flag that controls automatic clearing of forces after each time step.
inline bool b2World::GetAutoClearForces() const
{
return (m_flags & e_clearForces) == e_clearForces;
}
inline const b2ContactManager& b2World::GetContactManager() const
{
return m_contactManager;
}
inline const b2Profile& b2World::GetProfile() const
{
return m_profile;
}
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Dynamics/b2WorldCallbacks.h
================================================
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WORLD_CALLBACKS_H
#define B2_WORLD_CALLBACKS_H
#include "../Common/b2Settings.h"
struct b2Vec2;
struct b2Transform;
class b2Fixture;
class b2Body;
class b2Joint;
class b2Contact;
struct b2ContactResult;
struct b2Manifold;
/// Joints and fixtures are destroyed when their associated
/// body is destroyed. Implement this listener so that you
/// may nullify references to these joints and shapes.
class b2DestructionListener
{
public:
virtual ~b2DestructionListener() {}
/// Called when any joint is about to be destroyed due
/// to the destruction of one of its attached bodies.
virtual void SayGoodbye(b2Joint* joint) = 0;
/// Called when any fixture is about to be destroyed due
/// to the destruction of its parent body.
virtual void SayGoodbye(b2Fixture* fixture) = 0;
};
/// Implement this class to provide collision filtering. In other words, you can implement
/// this class if you want finer control over contact creation.
class b2ContactFilter
{
public:
virtual ~b2ContactFilter() {}
/// Return true if contact calculations should be performed between these two shapes.
/// @warning for performance reasons this is only called when the AABBs begin to overlap.
virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB);
};
/// Contact impulses for reporting. Impulses are used instead of forces because
/// sub-step forces may approach infinity for rigid body collisions. These
/// match up one-to-one with the contact points in b2Manifold.
struct b2ContactImpulse
{
float32 normalImpulses[b2_maxManifoldPoints];
float32 tangentImpulses[b2_maxManifoldPoints];
int32 count;
};
/// Implement this class to get contact information. You can use these results for
/// things like sounds and game logic. You can also get contact results by
/// traversing the contact lists after the time step. However, you might miss
/// some contacts because continuous physics leads to sub-stepping.
/// Additionally you may receive multiple callbacks for the same contact in a
/// single time step.
/// You should strive to make your callbacks efficient because there may be
/// many callbacks per time step.
/// @warning You cannot create/destroy Box2D entities inside these callbacks.
class b2ContactListener
{
public:
virtual ~b2ContactListener() {}
/// Called when two fixtures begin to touch.
virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
/// Called when two fixtures cease to touch.
virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
/// This is called after a contact is updated. This allows you to inspect a
/// contact before it goes to the solver. If you are careful, you can modify the
/// contact manifold (e.g. disable contact).
/// A copy of the old manifold is provided so that you can detect changes.
/// Note: this is called only for awake bodies.
/// Note: this is called even when the number of contact points is zero.
/// Note: this is not called for sensors.
/// Note: if you set the number of contact points to zero, you will not
/// get an EndContact callback. However, you may get a BeginContact callback
/// the next step.
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
B2_NOT_USED(contact);
B2_NOT_USED(oldManifold);
}
/// This lets you inspect a contact after the solver is finished. This is useful
/// for inspecting impulses.
/// Note: the contact manifold does not include time of impact impulses, which can be
/// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly
/// in a separate data structure.
/// Note: this is only called for contacts that are touching, solid, and awake.
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
B2_NOT_USED(contact);
B2_NOT_USED(impulse);
}
};
/// Callback class for AABB queries.
/// See b2World::Query
class b2QueryCallback
{
public:
virtual ~b2QueryCallback() {}
/// Called for each fixture found in the query AABB.
/// @return false to terminate the query.
virtual bool ReportFixture(b2Fixture* fixture) = 0;
};
/// Callback class for ray casts.
/// See b2World::RayCast
class b2RayCastCallback
{
public:
virtual ~b2RayCastCallback() {}
/// Called for each fixture found in the query. You control how the ray cast
/// proceeds by returning a float:
/// return -1: ignore this fixture and continue
/// return 0: terminate the ray cast
/// return fraction: clip the ray to this point
/// return 1: don't clip the ray and continue
/// @param fixture the fixture hit by the ray
/// @param point the point of initial intersection
/// @param normal the normal vector at the point of intersection
/// @return -1 to filter, 0 to terminate, fraction to clip the ray for
/// closest hit, 1 to continue
virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction) = 0;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/Box2D/Rope/b2Rope.h
================================================
/*
* Copyright (c) 2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_ROPE_H
#define B2_ROPE_H
#include "../Common/b2Math.h"
class b2Draw;
///
struct b2RopeDef
{
b2RopeDef()
{
vertices = NULL;
count = 0;
masses = NULL;
gravity.SetZero();
damping = 0.1f;
k2 = 0.9f;
k3 = 0.1f;
}
///
b2Vec2* vertices;
///
int32 count;
///
float32* masses;
///
b2Vec2 gravity;
///
float32 damping;
/// Stretching stiffness
float32 k2;
/// Bending stiffness. Values above 0.5 can make the simulation blow up.
float32 k3;
};
///
class b2Rope
{
public:
b2Rope();
~b2Rope();
///
void Initialize(const b2RopeDef* def);
///
void Step(float32 timeStep, int32 iterations);
///
int32 GetVertexCount() const
{
return m_count;
}
///
const b2Vec2* GetVertices() const
{
return m_ps;
}
///
void Draw(b2Draw* draw) const;
///
void SetAngle(float32 angle);
private:
void SolveC2();
void SolveC3();
int32 m_count;
b2Vec2* m_ps;
b2Vec2* m_p0s;
b2Vec2* m_vs;
float32* m_ims;
float32* m_Ls;
float32* m_as;
b2Vec2 m_gravity;
float32 m_damping;
float32 m_k2;
float32 m_k3;
};
#endif
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/Config.hpp
================================================
/*********************************************************************
Matt Marchant 2016 - 2020
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
#pragma once
//check which platform we're on and create export macros as necessary
#if !defined(TMXLITE_STATIC)
#if defined(_WIN32)
//windows compilers need specific (and different) keywords for export
#define TMXLITE_EXPORT_API __declspec(dllexport)
//for vc compilers we also need to turn off this annoying C4251 warning
#ifdef _MSC_VER
#pragma warning(disable: 4251)
#endif //_MSC_VER
#else //linux, FreeBSD, Mac OS X
#if __GNUC__ >= 4
//gcc 4 has special keywords for showing/hiding symbols,
//the same keyword is used for both importing and exporting
#define TMXLITE_EXPORT_API __attribute__ ((__visibility__ ("default")))
#else
//gcc < 4 has no mechanism to explicitly hide symbols, everything's exported
#define TMXLITE_EXPORT_API
#endif //__GNUC__
#endif //_WIN32
#else
//static build doesn't need import/export macros
#define TMXLITE_EXPORT_API
#endif //TMXLITE_STATIC
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/FreeFuncs.cpp
================================================
/*********************************************************************
Matt Marchant 2016
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as 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 "FreeFuncs.hpp"
#include "detail/Log.hpp"
#include "miniz.h"
#include
bool tmx::decompress(const char* source, std::vector& dest, std::size_t inSize, std::size_t expectedSize)
{
if (!source)
{
LOG("Input string is empty, decompression failed.", Logger::Type::Error);
return false;
}
int currentSize = static_cast(expectedSize);
std::vector byteArray(expectedSize / sizeof(unsigned char));
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.next_in = (Bytef*)source;
stream.avail_in = static_cast(inSize);
stream.next_out = (Bytef*)byteArray.data();
stream.avail_out = static_cast(expectedSize);
//we'd prefer to use inflateInit2 but it appears
//to be incorrect in miniz. This is fine for zlib
//compressed data, but gzip compressed streams
//will fail to inflate. IMO still preferable to
//trying to build/link zlib
if (inflateInit(&stream/*, 15 + 32*/) != Z_OK)
{
LOG("inflate init failed", Logger::Type::Error);
return false;
}
int result = 0;
do
{
result = inflate(&stream, Z_SYNC_FLUSH);
switch (result)
{
case Z_NEED_DICT:
case Z_STREAM_ERROR:
result = Z_DATA_ERROR;
case Z_DATA_ERROR:
Logger::log("If using gzip compression try using zlib instead", Logger::Type::Info);
case Z_MEM_ERROR:
inflateEnd(&stream);
Logger::log(std::to_string(result), Logger::Type::Error);
return false;
}
if (result != Z_STREAM_END)
{
int oldSize = currentSize;
currentSize *= 2;
std::vector newArray(currentSize / sizeof(unsigned char));
std::memcpy(newArray.data(), byteArray.data(), currentSize / 2);
byteArray = std::move(newArray);
stream.next_out = (Bytef*)(byteArray.data() + oldSize);
stream.avail_out = oldSize;
}
} while (result != Z_STREAM_END);
if (stream.avail_in != 0)
{
LOG("stream.avail_in is 0", Logger::Type::Error);
LOG("zlib decompression failed.", Logger::Type::Error);
return false;
}
const int outSize = currentSize - stream.avail_out;
inflateEnd(&stream);
std::vector newArray(outSize / sizeof(unsigned char));
std::memcpy(newArray.data(), byteArray.data(), outSize);
byteArray = std::move(newArray);
//copy bytes to vector
dest.insert(dest.begin(), byteArray.begin(), byteArray.end());
return true;
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/FreeFuncs.hpp
================================================
/*********************************************************************
Matt Marchant 2016
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
/*********************************************************************
base64_decode
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*********************************************************************/
#pragma once
#include "detail/Android.hpp"
#include "detail/Log.hpp"
#include "Types.hpp"
#include
#include
#include
#include
#include
namespace tmx
{
//using inline here just to supress unused warnings on gcc
bool decompress(const char* source, std::vector& dest, std::size_t inSize, std::size_t expectedSize);
static inline std::string base64_decode(std::string const& encoded_string)
{
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::function is_base64 =
[](unsigned char c)->bool
{
return (isalnum(c) || (c == '+') || (c == '/'));
};
auto in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4)
{
for (i = 0; i < 4; i++)
{
char_array_4[i] = static_cast(base64_chars.find(char_array_4[i]));
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
{
ret += char_array_3[i];
}
i = 0;
}
}
if (i)
{
for (j = i; j < 4; j++)
{
char_array_4[j] = 0;
}
for (j = 0; j < 4; j++)
{
char_array_4[j] = static_cast(base64_chars.find(char_array_4[j]));
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
{
ret += char_array_3[j];
}
}
return ret;
}
static inline Colour colourFromString(std::string str)
{
//removes preceding #
auto result = str.find_last_of('#');
if (result != std::string::npos)
{
str = str.substr(result + 1);
}
if (str.size() == 6 || str.size() == 8)
{
unsigned int value, r, g, b;
unsigned int a = 255;
std::stringstream input(str);
input >> std::hex >> value;
r = (value >> 16) & 0xff;
g = (value >> 8) & 0xff;
b = value & 0xff;
if (str.size() == 8)
{
a = (value >> 24) & 0xff;
}
return{ std::uint8_t(r), std::uint8_t(g), std::uint8_t(b), std::uint8_t(a) };
}
Logger::log(str + ": not a valid colour string", Logger::Type::Error);
return{};
}
static inline std::string resolveFilePath(std::string path, const std::string& workingDir)
{
static const std::string match("../");
std::size_t result = path.find(match);
std::size_t count = 0;
while (result != std::string::npos)
{
count++;
path = path.substr(result + match.size());
result = path.find(match);
}
if (workingDir.empty()) return path;
std::string outPath = workingDir;
for (auto i = 0u; i < count; ++i)
{
result = outPath.find_last_of('/');
if (result != std::string::npos)
{
outPath = outPath.substr(0, result);
}
}
// this does only work on windows
#ifndef __ANDROID__
return std::move(outPath += '/' + path);
#endif
// todo: make resolveFilePath work with subfolders on
// android - currently only the root folder is working
#ifdef __ANDROID__
return std::move(outPath = path);
#endif
}
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/ImageLayer.cpp
================================================
/*********************************************************************
Matt Marchant 2016
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as 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 "ImageLayer.hpp"
#include "FreeFuncs.hpp"
#include "detail/pugixml.hpp"
#include "detail/Log.hpp"
using namespace tmx;
ImageLayer::ImageLayer(const std::string& workingDir)
: m_workingDir (workingDir),
m_hasTransparency (false)
{
}
//public
void ImageLayer::parse(const pugi::xml_node& node, Map*)
{
std::string attribName = node.name();
if (attribName != "imagelayer")
{
Logger::log("Node not an image layer, node skipped", Logger::Type::Error);
return;
}
setName(node.attribute("name").as_string());
setOpacity(node.attribute("opacity").as_float(1.f));
setVisible(node.attribute("visible").as_bool(true));
setOffset(node.attribute("offsetx").as_int(), node.attribute("offsety").as_int());
setSize(node.attribute("width").as_uint(), node.attribute("height").as_uint());
for (const auto& child : node.children())
{
attribName = child.name();
if (attribName == "image")
{
attribName = child.attribute("source").as_string();
if (attribName.empty())
{
Logger::log("Image Layer has missing source property", Logger::Type::Warning);
return;
}
if (child.attribute("width") && child.attribute("height"))
{
m_imageSize.x = child.attribute("width").as_uint();
m_imageSize.y = child.attribute("height").as_uint();
}
m_filePath = resolveFilePath(attribName, m_workingDir);
if (child.attribute("trans"))
{
attribName = child.attribute("trans").as_string();
m_transparencyColour = colourFromString(attribName);
m_hasTransparency = true;
}
}
else if (attribName == "properties")
{
for (const auto& p : child.children())
{
addProperty(p);
}
}
}
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/ImageLayer.hpp
================================================
/*********************************************************************
Matt Marchant 2016 - 2019
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
#pragma once
#include "Config.hpp"
#include "Layer.hpp"
#include "Types.hpp"
namespace tmx
{
/*!
\brief Image layers contain a single image which make up that
layer. The parser contains the fully resolved path to the image
relative to the working directory.
*/
class TMXLITE_EXPORT_API ImageLayer final : public Layer
{
public:
explicit ImageLayer(const std::string&);
~ImageLayer() = default;
Type getType() const override { return Layer::Type::Image; }
void parse(const pugi::xml_node&, Map*) override;
/*!
\brief Returns the path, relative to the working directory,
of the image used by the image layer.
*/
const std::string& getImagePath() const { return m_filePath; }
/*!
\brief Returns the colour used by the image to represent transparent
pixels. By default this is (0, 0, 0, 0)
*/
const Colour& getTransparencyColour() const { return m_transparencyColour; }
/*!
\brief Returns true if the image used by this layer specifically states a
colour to use as transparency
*/
bool hasTransparency() const { return m_hasTransparency; }
/*!
\brief Returns the size of the image of the image layer in pixels.
*/
const Vector2u& getImageSize() const { return m_imageSize; }
private:
std::string m_workingDir;
std::string m_filePath;
Colour m_transparencyColour;
bool m_hasTransparency;
Vector2u m_imageSize;
};
template <>
inline ImageLayer& Layer::getLayerAs()
{
assert(getType() == Type::Image);
return *dynamic_cast(this);
}
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/Layer.hpp
================================================
/*********************************************************************
Matt Marchant 2016 - 2019
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
#pragma once
#include "Config.hpp"
#include "Property.hpp"
#include "Types.hpp"
#include
#include
#include
namespace pugi
{
class xml_node;
}
namespace tmx
{
class Map;
class TileLayer;
class ObjectGroup;
class ImageLayer;
class LayerGroup;
/*!
\brief Represents a layer of a tmx format tile map.
This is an abstract base class from which all layer
types are derived.
*/
class TMXLITE_EXPORT_API Layer
{
public:
using Ptr = std::unique_ptr;
Layer() : m_opacity(1.f), m_visible(true) {};
virtual ~Layer() = default;
/*!
\brief Layer type as returned by getType()
Tile: this layer is a TileLayer type
Object: This layer is an ObjectGroup type
Image: This layer is an ImageLayer type
Group: This layer is a LayerGroup type
*/
enum class Type
{
Tile,
Object,
Image,
Group
};
/*!
\brief Returns a Type value representing the concrete type.
Use this when deciding which conrete layer type to use when
calling the templated function getLayerAs()
*/
virtual Type getType() const = 0;
/*!
\brief Use this to get a reference to the concrete layer type
which this layer points to.
Use getType() to return the type value of this layer and determine
if the concrete type is TileLayer, ObjectGroup, ImageLayer, or LayerGroup
*/
template
T& getLayerAs();
/*{
throw("Not a valid layer type");
return *dynamic_cast(this);
}*/
template
const T& getLayerAs() const { return getLayerAs(); }
/*!
\brief Attempts to parse the specific node layer type
*/
virtual void parse(const pugi::xml_node&, Map* = nullptr) = 0;
/*!
\brief Returns the name of the layer
*/
const std::string& getName() const { return m_name; }
/*!
\brief Returns the opacity value for the layer
*/
float getOpacity() const { return m_opacity; }
/*!
\brief Returns whether this layer is visible or not
*/
bool getVisible() const { return m_visible; }
/*!
\brief Returns the offset from the top left corner
of the layer, in pixels
*/
const Vector2i& getOffset() const { return m_offset; }
/*!
\brief Returns the size of the layer, in pixels.
This will be the same as the map size for fixed size maps.
*/
const Vector2u& getSize() const { return m_size; }
/*!
\brief Returns the list of properties of this layer
*/
const std::vector& getProperties() const { return m_properties; }
protected:
void setName(const std::string& name) { m_name = name; }
void setOpacity(float opacity) { m_opacity = opacity; }
void setVisible(bool visible) { m_visible = visible; }
void setOffset(std::int32_t x, std::int32_t y) { m_offset = Vector2i(x, y); }
void setSize(std::uint32_t width, std::uint32_t height) { m_size = Vector2u(width, height); }
void addProperty(const pugi::xml_node& node) { m_properties.emplace_back(); m_properties.back().parse(node); }
private:
std::string m_name;
float m_opacity;
bool m_visible;
Vector2i m_offset;
Vector2u m_size;
std::vector m_properties;
};
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/LayerGroup.cpp
================================================
/*********************************************************************
Grant Gangi 2019
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as 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 "detail/pugixml.hpp"
#include "LayerGroup.hpp"
#include "FreeFuncs.hpp"
#include "ObjectGroup.hpp"
#include "ImageLayer.hpp"
#include "TileLayer.hpp"
#include "detail/Log.hpp"
using namespace tmx;
LayerGroup::LayerGroup(const std::string& workingDir, const Vector2u& tileCount)
: m_workingDir(workingDir),
m_tileCount(tileCount)
{
}
//public
void LayerGroup::parse(const pugi::xml_node& node, Map* map)
{
assert(map);
std::string attribString = node.name();
if (attribString != "group")
{
Logger::log("Node was not a group layer, node will be skipped.", Logger::Type::Error);
return;
}
setName(node.attribute("name").as_string());
setOpacity(node.attribute("opacity").as_float(1.f));
setVisible(node.attribute("visible").as_bool(true));
setOffset(node.attribute("offsetx").as_int(), node.attribute("offsety").as_int());
setSize(node.attribute("width").as_uint(), node.attribute("height").as_uint());
// parse children
for (const auto& child : node.children())
{
attribString = child.name();
if (attribString == "properties")
{
for (const auto& p : child.children())
{
addProperty(p);
}
}
else if (attribString == "layer")
{
m_layers.emplace_back(std::make_unique(m_tileCount.x * m_tileCount.y));
m_layers.back()->parse(child, map);
}
else if (attribString == "objectgroup")
{
m_layers.emplace_back(std::make_unique());
m_layers.back()->parse(child, map);
}
else if (attribString == "imagelayer")
{
m_layers.emplace_back(std::make_unique(m_workingDir));
m_layers.back()->parse(child, map);
}
else if (attribString == "group")
{
m_layers.emplace_back(std::make_unique(m_workingDir, m_tileCount));
m_layers.back()->parse(child, map);
}
else
{
LOG("Unidentified name " + attribString + ": node skipped", Logger::Type::Warning);
}
}
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/LayerGroup.hpp
================================================
/*********************************************************************
Grant Gangi 2019
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
#pragma once
#include "Config.hpp"
#include "Layer.hpp"
#include "Types.hpp"
#include
namespace tmx
{
/*!
\brief Layer groups are used to organize the layers of
the map in a hierarchy. They can contain all other layer
types including more layer groups to further nest layers.
*/
class TMXLITE_EXPORT_API LayerGroup final : public Layer
{
public:
LayerGroup(const std::string& workDir, const Vector2u& tileCount);
~LayerGroup() = default;
LayerGroup(const LayerGroup&) = delete;
const LayerGroup& operator = (const LayerGroup&) = delete;
LayerGroup(LayerGroup&&) = default;
LayerGroup& operator = (LayerGroup&&) = default;
Type getType() const override { return Layer::Type::Group; }
void parse(const pugi::xml_node&, Map*) override;
/*!
\brief Returns a reference to the vector containing the layer data.
Layers are pointer-to-baseclass, the concrete type of which can be
found via Layer::getType()
\see Layer
*/
const std::vector& getLayers() const { return m_layers; }
private:
std::vector m_layers;
std::string m_workingDir;
Vector2u m_tileCount;
};
template <>
inline LayerGroup& Layer::getLayerAs()
{
assert(getType() == Type::Group);
return *dynamic_cast(this);
}
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/Map.cpp
================================================
/*********************************************************************
Matt Marchant 2016
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as 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 "detail/pugixml.hpp"
#include "Map.hpp"
#include "FreeFuncs.hpp"
#include "ObjectGroup.hpp"
#include "ImageLayer.hpp"
#include "TileLayer.hpp"
#include "LayerGroup.hpp"
#include "detail/Log.hpp"
#include "detail/Android.hpp"
#include
using namespace tmx;
namespace
{
std::string getFilePath(const std::string& path)
{
//TODO this doesn't actually check that there is a file at the
//end of the path, or that it's even a valid path...
static auto searchFunc = [](const char separator, const std::string& path)->std::string
{
std::size_t i = path.rfind(separator, path.length());
if (i != std::string::npos)
{
return(path.substr(0, i + 1));
}
return "";
};
#ifdef _WIN32 //try windows formatted paths first
std::string retVal = searchFunc('\\', path);
if (!retVal.empty()) return retVal;
#endif
return searchFunc('/', path);
}
}
Map::Map()
: m_orientation (Orientation::None),
m_renderOrder (RenderOrder::None),
m_infinite (false),
m_hexSideLength (0.f),
m_staggerAxis (StaggerAxis::None),
m_staggerIndex (StaggerIndex::None)
{
}
//public
bool Map::load(const std::string& path)
{
reset();
//open the doc
pugi::xml_document doc;
auto result = doc.load_file(path.c_str());
if (!result)
{
Logger::log("Failed opening " + path, Logger::Type::Error);
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
return false;
}
//make sure we have consistent path separators
m_workingDirectory = path;
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
m_workingDirectory = getFilePath(m_workingDirectory);
if (!m_workingDirectory.empty() &&
m_workingDirectory.back() == '/')
{
m_workingDirectory.pop_back();
}
//find the map node and bail if it doesn't exist
auto mapNode = doc.child("map");
if (!mapNode)
{
Logger::log("Failed opening map: " + path + ", no map node found", Logger::Type::Error);
return reset();
}
return parseMapNode(mapNode);
}
bool Map::loadFromString(const std::string& data, const std::string& workingDir)
{
reset();
//open the doc
pugi::xml_document doc;
auto result = doc.load_string(data.c_str());
if (!result)
{
Logger::log("Failed opening map", Logger::Type::Error);
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
return false;
}
//make sure we have consistent path separators
m_workingDirectory = workingDir;
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
m_workingDirectory = getFilePath(m_workingDirectory);
if (!m_workingDirectory.empty() &&
m_workingDirectory.back() == '/')
{
m_workingDirectory.pop_back();
}
//find the map node and bail if it doesn't exist
auto mapNode = doc.child("map");
if (!mapNode)
{
Logger::log("Failed opening map: no map node found", Logger::Type::Error);
return reset();
}
return parseMapNode(mapNode);
}
//private
bool Map::parseMapNode(const pugi::xml_node& mapNode)
{
//parse map attributes
std::size_t pointPos = 0;
std::string attribString = mapNode.attribute("version").as_string();
if (attribString.empty() || (pointPos = attribString.find('.')) == std::string::npos)
{
Logger::log("Invalid map version value, map not loaded.", Logger::Type::Error);
return reset();
}
m_version.upper = STOI(attribString.substr(0, pointPos));
m_version.lower = STOI(attribString.substr(pointPos + 1));
attribString = mapNode.attribute("orientation").as_string();
if (attribString.empty())
{
Logger::log("Missing map orientation attribute, map not loaded.", Logger::Type::Error);
return reset();
}
if (attribString == "orthogonal")
{
m_orientation = Orientation::Orthogonal;
}
else if (attribString == "isometric")
{
m_orientation = Orientation::Isometric;
}
else if (attribString == "staggered")
{
m_orientation = Orientation::Staggered;
}
else if (attribString == "hexagonal")
{
m_orientation = Orientation::Hexagonal;
}
else
{
Logger::log(attribString + " format maps aren't supported yet, sorry! Map not loaded", Logger::Type::Error);
return reset();
}
attribString = mapNode.attribute("renderorder").as_string();
//this property is optional for older version of map files
if (!attribString.empty())
{
if (attribString == "right-down")
{
m_renderOrder = RenderOrder::RightDown;
}
else if (attribString == "right-up")
{
m_renderOrder = RenderOrder::RightUp;
}
else if (attribString == "left-down")
{
m_renderOrder = RenderOrder::LeftDown;
}
else if (attribString == "left-up")
{
m_renderOrder = RenderOrder::LeftUp;
}
else
{
Logger::log(attribString + ": invalid render order. Map not loaded.", Logger::Type::Error);
return reset();
}
}
if (mapNode.attribute("infinite"))
{
m_infinite = mapNode.attribute("infinite").as_int() != 0;
}
unsigned width = mapNode.attribute("width").as_int();
unsigned height = mapNode.attribute("height").as_int();
if (width && height)
{
m_tileCount = { width, height };
}
else
{
Logger::log("Invalid map tile count, map not loaded", Logger::Type::Error);
return reset();
}
width = mapNode.attribute("tilewidth").as_int();
height = mapNode.attribute("tileheight").as_int();
if (width && height)
{
m_tileSize = { width, height };
}
else
{
Logger::log("Invalid tile size, map not loaded", Logger::Type::Error);
return reset();
}
m_hexSideLength = mapNode.attribute("hexsidelength").as_float();
if (m_orientation == Orientation::Hexagonal && m_hexSideLength <= 0)
{
Logger::log("Invalid he side length found, map not loaded", Logger::Type::Error);
return reset();
}
attribString = mapNode.attribute("staggeraxis").as_string();
if (attribString == "x")
{
m_staggerAxis = StaggerAxis::X;
}
else if (attribString == "y")
{
m_staggerAxis = StaggerAxis::Y;
}
if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal)
&& m_staggerAxis == StaggerAxis::None)
{
Logger::log("Map missing stagger axis property. Map not loaded.", Logger::Type::Error);
return reset();
}
attribString = mapNode.attribute("staggerindex").as_string();
if (attribString == "odd")
{
m_staggerIndex = StaggerIndex::Odd;
}
else if (attribString == "even")
{
m_staggerIndex = StaggerIndex::Even;
}
if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal)
&& m_staggerIndex == StaggerIndex::None)
{
Logger::log("Map missing stagger index property. Map not loaded.", Logger::Type::Error);
return reset();
}
//colour property is optional
attribString = mapNode.attribute("backgroundcolor").as_string();
if (!attribString.empty())
{
m_backgroundColour = colourFromString(attribString);
}
//TODO do we need next object ID? technically we won't be creating
//new objects outside of the scene in xygine.
//parse all child nodes
for (const auto& node : mapNode.children())
{
std::string name = node.name();
if (name == "tileset")
{
m_tilesets.emplace_back(m_workingDirectory);
m_tilesets.back().parse(node, this);
}
else if (name == "layer")
{
m_layers.emplace_back(std::make_unique(m_tileCount.x * m_tileCount.y));
m_layers.back()->parse(node);
}
else if (name == "objectgroup")
{
m_layers.emplace_back(std::make_unique());
m_layers.back()->parse(node, this);
}
else if (name == "imagelayer")
{
m_layers.emplace_back(std::make_unique(m_workingDirectory));
m_layers.back()->parse(node, this);
}
else if (name == "properties")
{
const auto& children = node.children();
for (const auto& child : children)
{
m_properties.emplace_back();
m_properties.back().parse(child);
}
}
else if (name == "group")
{
m_layers.emplace_back(std::make_unique(m_workingDirectory, m_tileCount));
m_layers.back()->parse(node, this);
}
else
{
LOG("Unidentified name " + name + ": node skipped", Logger::Type::Warning);
}
}
// fill animated tiles for easier lookup into map
for(const auto& ts : m_tilesets)
{
for(const auto& tile : ts.getTiles())
{
if (!tile.animation.frames.empty())
{
m_animTiles[tile.ID + ts.getFirstGID()] = tile;
}
}
}
return true;
}
bool Map::reset()
{
m_orientation = Orientation::None;
m_renderOrder = RenderOrder::None;
m_tileCount = { 0u, 0u };
m_tileSize = { 0u, 0u };
m_hexSideLength = 0.f;
m_staggerAxis = StaggerAxis::None;
m_staggerIndex = StaggerIndex::None;
m_backgroundColour = {};
m_workingDirectory = "";
m_tilesets.clear();
m_layers.clear();
m_properties.clear();
m_templateObjects.clear();
m_templateTilesets.clear();
return false;
}
================================================
FILE: app/src/main/cpp/isEngine/ext_lib/TMXLite/Map.hpp
================================================
/*********************************************************************
Matt Marchant 2016
http://trederia.blogspot.com
tmxlite - Zlib license.
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
*********************************************************************/
#pragma once
#include "Tileset.hpp"
#include "Layer.hpp"
#include "Property.hpp"
#include "Types.hpp"
#include "Object.hpp"
#include
#include
#include
#include
namespace tmx
{
/*!
\brief Holds the xml version of the loaded map
*/
struct TMXLITE_EXPORT_API Version
{
//major/minor are apparently reserved by gcc
std::uint16_t upper;
std::uint16_t lower;
Version(std::uint16_t maj = 0, std::uint16_t min = 0)
: upper(maj), lower(min) {}
};
enum class Orientation
{
Orthogonal,
Isometric,
Staggered,
Hexagonal,
None
};
enum class RenderOrder
{
RightDown,
RightUp,
LeftDown,
LeftUp,
None
};
enum class StaggerAxis
{
X, Y, None
};
enum class StaggerIndex
{
Even, Odd, None
};
/*!
\brief Parser for TMX format tile maps.
This class can be used to parse the XML format tile maps created
with the Tiled map editor, providing an interface to create drawable and
physics objects. Typical usage would be to create an instance of this
class before calling load() providing a path to the *.tmx file to be
loaded. Then layers or objects can be requested from the Map class
to be interpreted as needed.
*/
class TMXLITE_EXPORT_API Map final
{
public:
Map();
~Map() = default;
Map(const Map&) = delete;
Map& operator = (const Map&) = delete;
Map(Map&&) = default;
Map& operator = (Map&&) = default;
/*!
\brief Attempts to parse the tilemap at the given location.
\param std::string Path to map file to try to parse
\returns true if map was parsed successfully else returns false.
In debug mode this will attempt to log any errors to the console.
*/
bool load(const std::string&);
/*!
\brief Loads a map from a document stored in a string
\param data A std::string containing the map data to load
\param workingDir A std::string containing the working directory
in which to find assets such as tile sets or images
\returns true if successful, else false
*/
bool loadFromString(const std::string& data, const std::string& workingDir);
/*!
\brief Returns the version of the tile map last parsed.
If no tile map has yet been parsed the version will read 0, 0
*/
const Version& getVersion() const { return m_version; }
/*!
\brief Returns the orientation of the map if one is loaded,
else returns None
*/
Orientation getOrientation() const { return m_orientation; }
/*!
\brief Returns the RenderOrder of the map if one is loaded,
else returns None
*/
RenderOrder getRenderOrder() const { return m_renderOrder; }
/*!
\brief Returns the tile count of the map in the X and Y directions
*/
const Vector2u& getTileCount() const { return m_tileCount; }
/*!
\brief Returns the size of the tile grid in this map.
Actual tile sizes may vary and will be extended / shrunk about
the bottom left corner of the tile.
*/
const Vector2u& getTileSize() const { return m_tileSize; }
/*!
\brief Returns the bounds of the map
*/
FloatRect getBounds() const { return FloatRect(0.f, 0.f, static_cast(m_tileCount.x * m_tileSize.x), static_cast(m_tileCount.y * m_tileSize.y)); }
/*!
\brief Returns the length of an edge of a tile if a Hexagonal
map is loaded.
The length returned is in pixels of the straight edge running
along the axis returned by getStaggerAxis(). If no map is loaded
or the loaded map is not of Hexagonal orientation this function
returns 0.f
*/
float getHexSideLength() const { return m_hexSideLength; }
/*!
\brief Stagger axis of the map.
If either a Staggered or Hexagonal tile map is loaded this returns
which axis the map is staggered along, else returns None.
*/
StaggerAxis getStaggerAxis() const { return m_staggerAxis; }
/*!
\brief Stagger Index of the loaded map.
If a Staggered or Hexagonal map is loaded this returns whether
the even or odd rows of tiles are staggered, otherwise it returns None.
*/
StaggerIndex getStaggerIndex() const { return m_staggerIndex; }
/*!
\brief Returns the background colour of the map.
*/
const Colour& getBackgroundColour() const { return m_backgroundColour; }
/*!
\brief Returns a reference to the vector of tile sets used by the map
*/
const std::vector& getTilesets() const { return m_tilesets; }
/*!
\brief Returns a reference to the vector containing the layer data.
Layers are pointer-to-baseclass, the concrete type of which can be
found via Layer::getType()
\see Layer
*/
const std::vector& getLayers() const { return m_layers; }
/*!
\brief Returns a vector of Property objects loaded by the map
*/
const std::vector& getProperties() const { return m_properties; }
/*!
\brief Returns a Hashmap of all animated tiles accessible by TileID
*/
const std::map