--HG-- branch : minor
@@ -3,3 +3,4 @@
db7cd0682883ed357adef013a326bbb26de28c98 0.6.2
9240be0fe0ea1070bc604954ab2e81320e278ad9 0.7.0
18d79c306466d188919c238d23e50ea705b07c03 0.7.1
+bcca82b60d0f5cd724edbe4ed65db18ab95d4691 0.7.2
@@ -1,3 +1,113 @@
+LOVE 0.8.0 [Rubber Piggy]
+-------------------------
+
+ * Added release error screen.
+ * Added alpha to love.graphics.setBackgroundColor.
+ * Added Canvas:clear(r, g, b, a).
+ * Added Canvas support to love.graphics.drawq.
+ * Added Canvas:getWidth and Canvas:getHeight.
+ * Added love.graphics.arc.
+ * Added seek and tell to Source objects.
+ * Added color interpolation to ParticleSystem.
+ * Added automatic PO2 padding for systems not supporting the OpenGL extension.
+ * Added UTF-8 support for fonts.
+ * Added Box2D error handling for some commonly failing functions.
+ * Added ability for fused release games to have their write dir in appdata.
+ * Added shear transformation to drawing functions.
+ * Added origin to font printing.
+ * Added love.graphics.getMode.
+ * Added per-sprite colors on SpriteBatches.
+ * Added pixel effects.
+ * Added love.graphics.isSupported.
+ * Added love.graphics.getCanvas.
+ * Added love.event.quit.
+ * Added stencil masks.
+ * Added alternative SpriteBatch provider, it should work everywhere now.
+ * Added a loader for binary modules.
+ * Added Thread:getKeys.
+ * Added option of fractions for Quads.
+ * Added PNG, JPEG and GIF support to ImageData:encode.
+ * Added 64-bit support for Mac OS X.
+ * Added premultiplied blending mode.
+ * Added functions to set/get default image filter modes.
+ * Added SpriteBatch:set.
+ * Added new events system, with support for custom events and long event names.
+ * Added sound attenuation by distance.
+ * Added SpriteBatch:getImage.
+ * Fixed wrapping for single words.
+ * Fixed tracebacks not showing filenames.
+ * Fixed love.graphics.push/pop capable of causing overflows/underflows.
+ * Fixed setScissor on Canvases.
+ * Fixed several issues with audio, e.g. clicks and pops in mp3s.
+ * Fixed crashes when bodies were destroyed during collisions.
+ * Fixed bound SpriteBatches corrupting when drawing.
+ * Fixed thread-safety issues with ImageData.
+ * Fixed memory leaks in audio sources.
+ * Fixed thread's set (previously send) accidentally changing the type.
+ * Fixed SoundData allocating the wrong number of samples.
+ * Fixed SpriteBatch support on Intel cards.
+ * Fixed love.filesystem.lines() leaking.
+ * Fixed Source controls inconsistencies.
+ * Fixed most leaking on unclosed File objects.
+ * Fixed crashes when operating on non-existent files.
+ * Fixed a bug where empty files on windows would never reach eof.
+ * Fixed crash when SoundData runs out of memory.
+ * Fixed ordering of loaders, love should have priority over Lua.
+ * Fixed several miscellaneous memory leaks.
+ * Fixed love.filesystem's priority for require.
+ * Fixed a few cases where strings with \0 in them would not be stored correctly.
+ * Fixed love's startup time being in the first dt.
+ * Fixed internal string conversions, they are faster now.
+ * Fixed (bad) performance of ImageData:paste.
+ * Renamed SpriteBatch's lock/unlock to bind/unbind.
+ * Renamed Framebuffer to Canvas.
+ * Renamed love.thread.send/receive to set/get.
+ * Renamed love.graphics.setRenderTarget to setCanvas.
+ * Removed canvas auto-clearing.
+ * Removed EncodedImageData.
+ * Removed old syntax for require (with extension).
+ * Removed love.graphics.setFont([file], [size]).
+ * Removed Thread:kill.
+ * Updated love.joystick to be 1-indexed.
+ * Updated Sources to update more cleanly and control more intuitively.
+ * Updated font engine.
+ * Updated line drawing to a custom system.
+ * Updated love.timer.sleep to use seconds, like the rest of love.
+ * Updated love.timer to be more accurate.
+ * Updated love.graphics.circle to have max(10, r) as default for segments.
+ * Updated ImageData:encode to write to files directly.
+ * Updated version compatibility system to actually do something.
+ * Updated love.run's order, events are checked just before update.
+ * Updated Box2D to version 2.2.1.
+LOVE 0.7.2 [Game Slave]
+-----------------------
+ * Added Framebuffer:get/setWrap.
+ * Added love.event.clear.
+ * Added support for any number of arguments to love.keyboard.isDown, love.mouse.isDown and love.joystick.isDown.
+ * Added SpriteBatch:setImage().
+ * Fixed fused games not working.
+ * Fixed ParticleSystem:setSize ignoring the variation argument.
+ * Fixed some file-opening exceptions not being caught.
+ * Fixed files loaded by libmodplug being too loud.
+ * Fixed paths with periods in them not working.
+ * Fixed love.graphics.getBlendMode not detecting subtractive and multiplicative blend modes.
+ * Fixed crash when there was no memory available for newImageData(w, h).
+ * Updated PhysicsFS version to 2.0.2 on Windows
+ * Updated OpenAL Soft version to 1.13 on Windows
+ * Updated libmodplug version to 0.8.8.1 on Windows
+ * Updated FreeType version to 2.4.4 on Windows
+ * Updated libmpg123 version to 1.13.2 on Windows
+ * Windows binary no longer depends on VC2005 runtime.
+ * Windows binary no longer depends on SSE2 support.
LOVE 0.7.1 [Game Slave]
-----------------------
@@ -13,14 +13,17 @@ AC_SEARCH_LIBS([SDL_Init], [SDL], [], AC_MSG_ERROR([Can't LÖVE without SDL]))
AC_SEARCH_LIBS([glLoadIdentity], [GL], [], AC_MSG_ERROR([Can't LÖVE without OpenGL]))
#AC_SEARCH_LIBS([gluOrtho2D], [GLU], [], AC_MSG_ERROR([Can't LÖVE without OpenGL Utility Library]))
AC_SEARCH_LIBS([alSourcePlay], [openal], [], AC_MSG_ERROR([Can't LÖVE without OpenAL]))
-AC_ARG_ENABLE([luajit],
- [ --enable-luajit Use LuaJIT instead of lua],
- AC_SEARCH_LIBS(
- [lua_pcall],
- [luajit luajit-5.1],
- AC_SUBST([INCLUDE_LUA], [-I/usr/include/luajit-2.0]),
- AC_MSG_ERROR([Can't LÖVE without LuaJIT])
- ),
+lua=lua
+AC_ARG_WITH([luajit],
+ [AS_HELP_STRING([--with-luajit], [Use LuaJIT instead of lua and llvm-lua])],
+ [lua=luajit],
+ [])
+AC_ARG_WITH([llvm-lua],
+ [AS_HELP_STRING([--with-llvm-lua], [Use llvm-lua instead of lua and LuaJIT])],
+ [lua=llvm-lua],
+AS_IF([test "$lua" == "lua"],
AC_SEARCH_LIBS(
[lua_pcall],
[lua lua5.1],
@@ -29,7 +32,24 @@ AC_ARG_ENABLE([luajit],
fi,
AC_MSG_ERROR([Can't LÖVE without Lua])
)
-)
+ )
+AS_IF([test "$lua" == "luajit"],
+ AC_SEARCH_LIBS(
+ [lua_pcall],
+ [luajit luajit-5.1],
+ AC_SUBST([INCLUDE_LUA], [-I/usr/include/luajit-2.0]),
+ AC_MSG_ERROR([Can't LÖVE without LuaJIT])
+AS_IF([test "$lua" == "llvm-lua"],
+ [llvm-lua],
+ [],
+ AC_MSG_ERROR([Can't LÖVE without llvm-lua])
AC_SEARCH_LIBS([ilInit], [IL], [], AC_MSG_ERROR([Can't LÖVE without DevIL]))
AC_SEARCH_LIBS([mng_initialize], [mng], [], AC_MSG_ERROR([DevIL needs MNG]))
AC_SEARCH_LIBS([TIFFOpen], [tiff], [], AC_MSG_ERROR([DevIL needs TIFF]))
@@ -39,6 +59,9 @@ AC_SEARCH_LIBS([ModPlug_Load], [modplug], [], AC_MSG_ERROR([Can't LÖVE without
AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [], AC_MSG_ERROR([Can't LÖVE without Mpg123]))
AC_SEARCH_LIBS([mpg123_seek_64], [mpg123], AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]), AC_SUBST([FILE_OFFSET],[]))
AC_SEARCH_LIBS([ov_open], [vorbisfile], [], AC_MSG_ERROR([Can't LÖVE without VorbisFile]))
+AC_ARG_ENABLE([headless],
+ [ --enable-headless Build with less SDL],
+ AC_DEFINE([LOVE_HEADLESS], [], [Build with less SDL]), [])
AC_CONFIG_FILES([
Makefile
src/Makefile
@@ -8,20 +8,20 @@ InstallDir $PROGRAMFILES\LOVE
InstallDirRegKey HKCU "Software\LOVE" ""
# Graphics
-!define MUI_ICON "love\extra\nsis\love.ico"
-!define MUI_UNICON "love\extra\nsis\love.ico"
+!define MUI_ICON "${LOVEICODIR}\love.ico"
+!define MUI_UNICON "${LOVEICODIR}\love.ico"
!define MUI_ABORTWARNING
!define MUI_HEADERIMAGE
-!define MUI_HEADERIMAGE_BITMAP "love\extra\nsis\top.bmp" # optional
-!define MUI_WELCOMEFINISHPAGE_BITMAP "love\extra\nsis\left.bmp"
-!define MUI_UNWELCOMEFINISHPAGE_BITMAP "love\extra\nsis\left.bmp"
+!define MUI_HEADERIMAGE_BITMAP "${LOVEICODIR}\top.bmp" # optional
+!define MUI_WELCOMEFINISHPAGE_BITMAP "${LOVEICODIR}\left.bmp"
+!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${LOVEICODIR}\left.bmp"
!define MUI_WELCOMEPAGE_TITLE "LÖVE Setup"
!define MUI_WELCOMEPAGE_TEXT "This will install LÖVE, the unquestionably awesome Lua game framework."
# Pages
!insertmacro MUI_PAGE_WELCOME
-!insertmacro MUI_PAGE_LICENSE "love\license.txt"
+!insertmacro MUI_PAGE_LICENSE "${LOVELICDIR}\license.txt"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
@@ -38,12 +38,13 @@ Section "LOVE" MainProg
SectionIn RO
SetOutPath $INSTDIR
- File "love\platform\msvc2010\Release\love.exe"
- File "love\platform\msvc2010\DevIL.dll"
- File "love\platform\msvc2010\SDL.dll"
- File "love\platform\msvc2010\OpenAL32.dll"
- File "love\extra\nsis\love.ico"
- File "love\extra\nsis\game.ico"
+ File "${LOVEBINDIR}\love.exe"
+ File "${LOVEBINDIR}\DevIL.dll"
+ File "${LOVEBINDIR}\SDL.dll"
+ File "${LOVEBINDIR}\OpenAL32.dll"
+ # File "${LOVEBINDIR}\lua51.dll"
+ File "${LOVEICODIR}\love.ico"
+ File "${LOVEICODIR}\game.ico"
# Uninstaller
WriteUninstaller $INSTDIR\Uninstall.exe
@@ -88,6 +89,7 @@ Section "Uninstall"
Delete $INSTDIR\"SDL.dll"
Delete $INSTDIR\"love.exe"
Delete $INSTDIR\"OpenAL32.dll"
+ # Delete $INSTDIR\"lua51.dll"
Delete $INSTDIR\"game.ico"
Delete $INSTDIR\"love.ico"
RMDir $INSTDIR
@@ -0,0 +1,12 @@
+function b64(name)
+ local i = io.popen("base64 " .. name)
+ local encoded = i:read("*a")
+ i:close()
+ local output = ("local %s =\n%q"):format(name:gsub("%.", "_"), encoded)
+ return output
+end
+for i, v in ipairs(arg) do
+ print(b64(v))
@@ -17,4 +17,866 @@ appreciated but is not required.
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
-distribution.
+distribution.
+-------
+LÖVE also uses the following LGPL libraries:
+ - SDL
+ Website: http://libsdl.org
+ Source download: http://www.libsdl.org/release/SDL-1.2.14.tar.gz
+ - libmpg123
+ Website: http://www.mpg123.de/
+ Source download: http://sourceforge.net/projects/mpg123/files/latest/download
+ - OpenAL
+ Website: http://connect.creativelabs.com/openal/default.aspx
+ Source download: http://connect.creativelabs.com/openal/Downloads/openal-soft-1.13.tbz2
+ - DevIL
+ Website: http://openil.sourceforge.net/
+ Source download: http://downloads.sourceforge.net/openil/DevIL-1.7.8.tar.gz
+Following are the LGPL and GPL license texts:
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+ 0. Additional Definitions.
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+ 1. Exception to Section 3 of the GNU GPL.
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+ 2. Conveying Modified Versions.
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+ 3. Object Code Incorporating Material from Library Header Files.
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+ 4. Combined Works.
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+ d) Do one of the following:
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+ 5. Combined Libraries.
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+ 6. Revised Versions of the GNU Lesser General Public License.
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+ GNU GENERAL PUBLIC LICENSE
+ Preamble
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+ The precise terms and conditions for copying, distribution and
+modification follow.
+ TERMS AND CONDITIONS
+ 0. Definitions.
+ "This License" refers to version 3 of the GNU General Public License.
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+ 1. Source Code.
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+ The Corresponding Source for a work in source code form is that
+same work.
+ 2. Basic Permissions.
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+ 4. Conveying Verbatim Copies.
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+ 5. Conveying Modified Source Versions.
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+ 6. Conveying Non-Source Forms.
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+ 7. Additional Terms.
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+ 8. Termination.
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+ 9. Acceptance Not Required for Having Copies.
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+ 10. Automatic Licensing of Downstream Recipients.
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+ 11. Patents.
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+ 12. No Surrender of Others' Freedom.
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+ 13. Use with the GNU Affero General Public License.
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+ 14. Revised Versions of this License.
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+ 15. Disclaimer of Warranty.
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+ 16. Limitation of Liability.
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+ 17. Interpretation of Sections 15 and 16.
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+ END OF TERMS AND CONDITIONS
+ How to Apply These Terms to Your New Programs
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+Also add information on how to contact you by electronic and paper mail.
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
@@ -7,28 +7,18 @@
<key>CFBundleDocumentTypes</key>
<array>
<dict>
- <key>CFBundleTypeExtensions</key>
- <array>
- <string>love</string>
- </array>
<key>CFBundleTypeIconFile</key>
<string>LoveDocument.icns</string>
<key>CFBundleTypeName</key>
- <string>Love Project</string>
- <key>CFBundleTypeOSTypes</key>
- <string>LOVE</string>
- <key>CFBundleTypeMIMETypes</key>
- <string>application/x-love-game</string>
+ <string>LÖVE Project</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
- <key>LSIsAppleDefaultForType</key>
- <true/>
- <key>LSTypeIsPackage</key>
+ <key>LSItemContentTypes</key>
+ <array>
+ <string>org.love2d.love-game</string>
+ </array>
+ <key>LSHandlerRank</key>
+ <string>Owner</string>
</dict>
@@ -39,8 +29,32 @@
</array>
+ <string>None</string>
+ <key>CFBundleExecutable</key>
+ <string>love</string>
+ <key>CFBundleIconFile</key>
+ <string>Love.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.love2d.love</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>LÖVE</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.8.0</string>
+ <key>CFBundleSignature</key>
+ <string>LoVe</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>© 2006-2012 LÖVE Development Team</string>
+ <key>NSMainNibFile</key>
+ <string>SDLMain</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
<key>UTExportedTypeDeclarations</key>
@@ -48,12 +62,14 @@
<string>com.pkware.zip-archive</string>
- <key>UTTypeIdentifier</key>
- <string>org.love2d.love-game</string>
<key>UTTypeDescription</key>
<key>UTTypeIconFile</key>
+ <key>UTTypeIdentifier</key>
+ <key>UTTypeReferenceURL</key>
+ <string>http://love2d.org/wiki/Game_Distribution</string>
<key>UTTypeTagSpecification</key>
<key>com.apple.ostype</key>
@@ -65,29 +81,7 @@
<key>public.mime-type</key>
<string>application/x-love-game</string>
- <key>UTTypeReferenceURL</key>
- <string>http://love2d.org/wiki/Game_Distribution</string>
- <key>CFBundleExecutable</key>
- <key>CFBundleIconFile</key>
- <string>Love.icns</string>
- <key>CFBundleIdentifier</key>
- <string>org.love2d.love</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <key>CFBundlePackageType</key>
- <string>LoVe</string>
- <key>CFBundleSignature</key>
- <key>CFBundleVersion</key>
- <string>0.7.1</string>
- <key>NSMainNibFile</key>
- <string>SDLMain</string>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
</plist>
@@ -12,15 +12,62 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\common\b64.cpp" />
+ <ClCompile Include="..\..\src\common\delay.cpp" />
<ClCompile Include="..\..\src\common\Exception.cpp" />
<ClCompile Include="..\..\src\common\Matrix.cpp" />
- <ClCompile Include="..\..\src\common\MemoryData.cpp" />
+ <ClCompile Include="..\..\src\common\Memoizer.cpp" />
<ClCompile Include="..\..\src\common\Object.cpp" />
<ClCompile Include="..\..\src\common\Reference.cpp" />
<ClCompile Include="..\..\src\common\runtime.cpp" />
<ClCompile Include="..\..\src\common\utf8.cpp" />
+ <ClCompile Include="..\..\src\common\Variant.cpp" />
<ClCompile Include="..\..\src\common\Vector.cpp" />
<ClCompile Include="..\..\src\common\wrap_Data.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2BroadPhase.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2CollideCircle.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2CollideEdge.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2CollidePolygon.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2Collision.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2Distance.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2DynamicTree.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\b2TimeOfImpact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\Shapes\b2ChainShape.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\Shapes\b2CircleShape.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\Shapes\b2EdgeShape.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2BlockAllocator.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2Draw.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2Math.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2Settings.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2StackAllocator.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Common\b2Timer.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2Body.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2ContactManager.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2Fixture.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2Island.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2World.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\b2WorldCallbacks.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2CircleContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2Contact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ContactSolver.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2PolygonContact.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2DistanceJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2FrictionJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2GearJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2Joint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2MouseJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2PrismaticJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2PulleyJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2RevoluteJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2RopeJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2WeldJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2WheelJoint.cpp" />
+ <ClCompile Include="..\..\src\libraries\Box2D\Rope\b2Rope.cpp" />
<ClCompile Include="..\..\src\libraries\luasocket\libluasocket\auxiliar.c">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">TurnOffAllWarnings</WarningLevel>
</ClCompile>
@@ -64,6 +111,7 @@
<ClCompile Include="..\..\src\love.cpp">
<ShowIncludes Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ShowIncludes>
+ <ClCompile Include="..\..\src\modules\audio\Audio.cpp" />
<ClCompile Include="..\..\src\modules\audio\null\Audio.cpp" />
<ClCompile Include="..\..\src\modules\audio\null\Source.cpp" />
<ClCompile Include="..\..\src\modules\audio\openal\Audio.cpp" />
@@ -91,25 +139,31 @@
<ClCompile Include="..\..\src\modules\font\wrap_GlyphData.cpp" />
<ClCompile Include="..\..\src\modules\font\wrap_Rasterizer.cpp" />
<ClCompile Include="..\..\src\modules\graphics\Drawable.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\DrawQable.cpp" />
<ClCompile Include="..\..\src\modules\graphics\Graphics.cpp" />
<ClCompile Include="..\..\src\modules\graphics\Image.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\Canvas.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\Font.cpp" />
- <ClCompile Include="..\..\src\modules\graphics\opengl\Framebuffer.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\GLee.c">
<ClCompile Include="..\..\src\modules\graphics\opengl\Graphics.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\Image.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\OpenGL.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\ParticleSystem.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\PixelEffect.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\Quad.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\SpriteBatch.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\VertexBuffer.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Canvas.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Font.cpp" />
- <ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Framebuffer.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Graphics.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Image.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_ParticleSystem.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\opengl\wrap_PixelEffect.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_Quad.cpp" />
<ClCompile Include="..\..\src\modules\graphics\opengl\wrap_SpriteBatch.cpp" />
+ <ClCompile Include="..\..\src\modules\graphics\Quad.cpp" />
<ClCompile Include="..\..\src\modules\graphics\Volatile.cpp" />
<ClCompile Include="..\..\src\modules\image\devil\Image.cpp" />
<ClCompile Include="..\..\src\modules\image\devil\ImageData.cpp" />
@@ -121,16 +175,20 @@
<ClCompile Include="..\..\src\modules\joystick\sdl\wrap_Joystick.cpp" />
<ClCompile Include="..\..\src\modules\keyboard\Keyboard.cpp" />
<ClCompile Include="..\..\src\modules\keyboard\sdl\Keyboard.cpp" />
- <ClCompile Include="..\..\src\modules\keyboard\sdl\wrap_Keyboard.cpp" />
+ <ClCompile Include="..\..\src\modules\keyboard\wrap_Keyboard.cpp" />
<ClCompile Include="..\..\src\modules\mouse\Mouse.cpp" />
<ClCompile Include="..\..\src\modules\mouse\sdl\Mouse.cpp" />
- <ClCompile Include="..\..\src\modules\mouse\sdl\wrap_Mouse.cpp" />
+ <ClCompile Include="..\..\src\modules\mouse\wrap_Mouse.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\Body.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\Body.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\ChainShape.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\CircleShape.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\Contact.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\DistanceJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\EdgeShape.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\Fixture.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\FrictionJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\GearJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\graham\GrahamScanConvexHull.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\Joint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\MouseJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\Physics.cpp" />
@@ -138,43 +196,19 @@
<ClCompile Include="..\..\src\modules\physics\box2d\PrismaticJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\PulleyJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\RevoluteJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\RopeJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\Shape.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2BroadPhase.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2CollideCircle.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2CollidePoly.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2Collision.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2Distance.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2PairManager.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\b2TimeOfImpact.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\Shapes\b2CircleShape.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\Shapes\b2PolygonShape.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Collision\Shapes\b2Shape.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Common\b2BlockAllocator.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Common\b2Math.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Common\b2Settings.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Common\b2StackAllocator.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\b2Body.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\b2ContactManager.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\b2Island.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\b2World.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\b2WorldCallbacks.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Contacts\b2CircleContact.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Contacts\b2Contact.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Contacts\b2ContactSolver.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Contacts\b2PolyAndCircleContact.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Contacts\b2PolyContact.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2DistanceJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2GearJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2Joint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2MouseJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2PrismaticJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2PulleyJoint.cpp" />
- <ClCompile Include="..\..\src\modules\physics\box2d\Source\Dynamics\Joints\b2RevoluteJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\WeldJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\WheelJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\World.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_Body.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_ChainShape.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_CircleShape.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_Contact.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_DistanceJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_EdgeShape.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_Fixture.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_FrictionJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_GearJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_Joint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_MouseJoint.cpp" />
@@ -183,7 +217,10 @@
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_PrismaticJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_PulleyJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_RevoluteJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_RopeJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_Shape.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_WeldJoint.cpp" />
+ <ClCompile Include="..\..\src\modules\physics\box2d\wrap_WheelJoint.cpp" />
<ClCompile Include="..\..\src\modules\physics\box2d\wrap_World.cpp" />
<ClCompile Include="..\..\src\modules\physics\Joint.cpp" />
<ClCompile Include="..\..\src\modules\physics\Shape.cpp" />
@@ -198,20 +235,36 @@
<ClCompile Include="..\..\src\modules\sound\wrap_Decoder.cpp" />
<ClCompile Include="..\..\src\modules\sound\wrap_Sound.cpp" />
<ClCompile Include="..\..\src\modules\sound\wrap_SoundData.cpp" />
- <ClCompile Include="..\..\src\modules\thread\sdl\Thread.cpp" />
- <ClCompile Include="..\..\src\modules\thread\sdl\wrap_Thread.cpp" />
+ <ClCompile Include="..\..\src\modules\thread\posix\threads.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="..\..\src\modules\thread\sdl\threads.cpp">
+ <ClCompile Include="..\..\src\modules\thread\Thread.cpp" />
+ <ClCompile Include="..\..\src\modules\thread\threads.cpp" />
+ <ClCompile Include="..\..\src\modules\thread\win32\threads.cpp">
+ <ClCompile Include="..\..\src\modules\thread\wrap_Thread.cpp" />
<ClCompile Include="..\..\src\modules\timer\sdl\Timer.cpp" />
- <ClCompile Include="..\..\src\modules\timer\sdl\wrap_Timer.cpp" />
+ <ClCompile Include="..\..\src\modules\timer\wrap_Timer.cpp" />
+ <ClCompile Include="..\..\src\modules\window\sdl\Window.cpp" />
+ <ClCompile Include="..\..\src\modules\window\Window.cpp" />
<ClInclude Include="..\..\src\common\b64.h" />
<ClInclude Include="..\..\src\common\config.h" />
<ClInclude Include="..\..\src\common\Data.h" />
+ <ClInclude Include="..\..\src\common\delay.h" />
<ClInclude Include="..\..\src\common\EnumMap.h" />
<ClInclude Include="..\..\src\common\Exception.h" />
<ClInclude Include="..\..\src\common\math.h" />
<ClInclude Include="..\..\src\common\Matrix.h" />
- <ClInclude Include="..\..\src\common\MemoryData.h" />
+ <ClInclude Include="..\..\src\common\Memoizer.h" />
<ClInclude Include="..\..\src\common\Module.h" />
<ClInclude Include="..\..\src\common\Object.h" />
<ClInclude Include="..\..\src\common\Reference.h" />
@@ -219,9 +272,56 @@
<ClInclude Include="..\..\src\common\StringMap.h" />
<ClInclude Include="..\..\src\common\types.h" />
<ClInclude Include="..\..\src\common\utf8.h" />
+ <ClInclude Include="..\..\src\common\Variant.h" />
<ClInclude Include="..\..\src\common\Vector.h" />
<ClInclude Include="..\..\src\common\version.h" />
<ClInclude Include="..\..\src\common\wrap_Data.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Box2D.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\b2BroadPhase.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\b2Collision.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\b2Distance.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\b2DynamicTree.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\b2TimeOfImpact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\Shapes\b2ChainShape.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\Shapes\b2CircleShape.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\Shapes\b2EdgeShape.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\Shapes\b2PolygonShape.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Collision\Shapes\b2Shape.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2BlockAllocator.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2Draw.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2GrowableStack.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2Math.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2Settings.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2StackAllocator.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Common\b2Timer.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2Body.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2ContactManager.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2Fixture.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2Island.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2TimeStep.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2World.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\b2WorldCallbacks.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2CircleContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2Contact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2ContactSolver.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Contacts\b2PolygonContact.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2DistanceJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2FrictionJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2GearJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2Joint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2MouseJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2PrismaticJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2PulleyJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2RevoluteJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2RopeJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2WeldJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Dynamics\Joints\b2WheelJoint.h" />
+ <ClInclude Include="..\..\src\libraries\Box2D\Rope\b2Rope.h" />
<ClInclude Include="..\..\src\libraries\luasocket\luasocket.h" />
<ClInclude Include="..\..\src\libraries\utf8\utf8.h" />
<ClInclude Include="..\..\src\libraries\utf8\utf8\checked.h" />
@@ -256,23 +356,29 @@
<ClInclude Include="..\..\src\modules\font\wrap_GlyphData.h" />
<ClInclude Include="..\..\src\modules\font\wrap_Rasterizer.h" />
<ClInclude Include="..\..\src\modules\graphics\Drawable.h" />
+ <ClInclude Include="..\..\src\modules\graphics\DrawQable.h" />
<ClInclude Include="..\..\src\modules\graphics\Graphics.h" />
<ClInclude Include="..\..\src\modules\graphics\Image.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\Canvas.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\Font.h" />
- <ClInclude Include="..\..\src\modules\graphics\opengl\Framebuffer.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\GLee.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\Graphics.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\Image.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\OpenGL.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\ParticleSystem.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\PixelEffect.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\Quad.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\SpriteBatch.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\VertexBuffer.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Canvas.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Font.h" />
- <ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Framebuffer.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Graphics.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Image.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_ParticleSystem.h" />
+ <ClInclude Include="..\..\src\modules\graphics\opengl\wrap_PixelEffect.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_Quad.h" />
<ClInclude Include="..\..\src\modules\graphics\opengl\wrap_SpriteBatch.h" />
+ <ClInclude Include="..\..\src\modules\graphics\Quad.h" />
<ClInclude Include="..\..\src\modules\graphics\Volatile.h" />
<ClInclude Include="..\..\src\modules\image\devil\Image.h" />
<ClInclude Include="..\..\src\modules\image\devil\ImageData.h" />
@@ -285,14 +391,19 @@
<ClInclude Include="..\..\src\modules\joystick\sdl\wrap_Joystick.h" />
<ClInclude Include="..\..\src\modules\keyboard\Keyboard.h" />
<ClInclude Include="..\..\src\modules\keyboard\sdl\Keyboard.h" />
- <ClInclude Include="..\..\src\modules\keyboard\sdl\wrap_Keyboard.h" />
+ <ClInclude Include="..\..\src\modules\keyboard\wrap_Keyboard.h" />
<ClInclude Include="..\..\src\modules\mouse\Mouse.h" />
<ClInclude Include="..\..\src\modules\mouse\sdl\Mouse.h" />
- <ClInclude Include="..\..\src\modules\mouse\sdl\wrap_Mouse.h" />
+ <ClInclude Include="..\..\src\modules\mouse\wrap_Mouse.h" />
+ <ClInclude Include="..\..\src\modules\physics\Body.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\Body.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\ChainShape.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\CircleShape.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\Contact.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\DistanceJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\EdgeShape.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\Fixture.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\FrictionJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\GearJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\Joint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\MouseJoint.h" />
@@ -301,12 +412,19 @@
<ClInclude Include="..\..\src\modules\physics\box2d\PrismaticJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\PulleyJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\RevoluteJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\RopeJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\Shape.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\WeldJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\WheelJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\World.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_Body.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_ChainShape.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_CircleShape.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_Contact.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_DistanceJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_EdgeShape.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_Fixture.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_FrictionJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_GearJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_Joint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_MouseJoint.h" />
@@ -315,15 +433,33 @@
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_PrismaticJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_PulleyJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_RevoluteJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_RopeJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_Shape.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_WeldJoint.h" />
+ <ClInclude Include="..\..\src\modules\physics\box2d\wrap_WheelJoint.h" />
<ClInclude Include="..\..\src\modules\physics\box2d\wrap_World.h" />
<ClInclude Include="..\..\src\modules\physics\Joint.h" />
<ClInclude Include="..\..\src\modules\physics\Shape.h" />
- <ClInclude Include="..\..\src\modules\thread\sdl\Thread.h" />
- <ClInclude Include="..\..\src\modules\thread\sdl\wrap_Thread.h" />
- <ClInclude Include="..\..\src\modules\thread\ThreadModule.h" />
+ <ClInclude Include="..\..\src\modules\thread\posix\threads.h">
+ </ClInclude>
+ <ClInclude Include="..\..\src\modules\thread\sdl\threads.h">
+ <ClInclude Include="..\..\src\modules\thread\Thread.h" />
+ <ClInclude Include="..\..\src\modules\thread\threads.h" />
+ <ClInclude Include="..\..\src\modules\thread\win32\threads.h">
+ <ClInclude Include="..\..\src\modules\thread\wrap_Thread.h" />
<ClInclude Include="..\..\src\modules\timer\sdl\Timer.h" />
- <ClInclude Include="..\..\src\modules\timer\sdl\wrap_Timer.h" />
+ <ClInclude Include="..\..\src\modules\timer\Timer.h" />
+ <ClInclude Include="..\..\src\modules\timer\wrap_Timer.h" />
+ <ClInclude Include="..\..\src\modules\window\sdl\Window.h" />
+ <ClInclude Include="..\..\src\modules\window\Window.h" />
<ResourceCompile Include="app.rc" />
@@ -362,19 +498,19 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>include;include\SDL;include\AL;..\..\src;..\..\src\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>include;include\SDL;include\AL;..\..\src;..\..\src\libraries;..\..\src\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ObjectFileName>%(Identity)_d.obj</ObjectFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
- <PreprocessorDefinitions>VC_EXTRALEAN;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;VC_EXTRALEAN;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>lib</AdditionalLibraryDirectories>
- <AdditionalDependencies>opengl32.lib;glu32.lib;DevIL.lib;freetype242MT.lib;libmpg123.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;lua.lib;modplug_d.lib;OpenAL32.lib;physfs.lib;SDL.lib;SDLmain.lib;libFLAC_static_D.lib;libFLAC++_static_D.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>opengl32.lib;glu32.lib;DevIL.lib;freetype244MT.lib;libmpg123.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;lua.lib;modplug_d.lib;OpenAL32.lib;physfs.lib;SDL.lib;SDLmain.lib;libFLAC_static_D.lib;libFLAC++_static_D.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<AdditionalOptions>/FORCE:MULTIPLE %(AdditionalOptions)</AdditionalOptions>
</Link>
@@ -385,11 +521,11 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
+ <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
<ObjectFileName>%(Identity).obj</ObjectFileName>
- <PreprocessorDefinitions>VC_EXTRALEAN;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;VC_EXTRALEAN;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>
</StringPooling>
<MinimalRebuild>
@@ -400,9 +536,10 @@
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <AdditionalDependencies>opengl32.lib;glu32.lib;DevIL.lib;freetype242MT.lib;libmpg123.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;lua.lib;modplug.lib;OpenAL32.lib;physfs.lib;SDL.lib;SDLmain.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>opengl32.lib;glu32.lib;DevIL.lib;freetype244MT.lib;libmpg123.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;lua.lib;modplug.lib;OpenAL32.lib;physfs.lib;SDL.lib;SDLmain.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
+ <AdditionalOptions>/FORCE:MULTIPLE %(AdditionalOptions)</AdditionalOptions>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
@@ -1,10 +1,25 @@
#!/bin/bash
-if ! sh platform/unix/gen-makefile; then
- echo "You should be doing this from the root directory of the project."
+automagic() {
+ if ! sh platform/unix/gen-makefile; then
+ echo "You should be doing this from the root directory of the project."
+ exit 1
+ fi
+ autoheader 2>&1 || return 1 # Gimmie config.h.in
+ libtoolize --force 2>&1 || return 1
+ aclocal 2>&1 || return 1
+ autoconf 2>&1 || return 1
+ automake -a 2>&1 || return 1
+}
+if [[ $1 == "-d" ]]; then
+ automagic
+else
+ automagic > /dev/null
+fi
+if [ $? -eq 1 ]; then
+ echo "Failed, please contact the developers."
exit 1
+ echo "Success, carry on configuring."
fi
-autoheader # Gimmie config.h.in
-libtoolize --force
-aclocal
-autoconf
-automake -a
@@ -21,3 +21,6 @@
./modules/native/tcc/libtcc/stab.h
./libraries/luasocket/libluasocket/wsocket.*
./modules/sound/lullaby/FLACDecoder.*
+./modules/thread/sdl/*
+./modules/thread/win32/*
+./modules/thread/posix/*
@@ -3,7 +3,8 @@ echo Generating src/Makefile.am ...
cd src
inc_current=.
inc_modules="$inc_current/modules"
-echo "AM_CPPFLAGS = -I$inc_current -I$inc_modules -I/usr/include/AL -I/usr/include/freetype2 \$(INCLUDE_LUA) -I/usr/include/SDL \$(FILE_OFFSET)
+inc_libraries="$inc_current/libraries"
+echo "AM_CPPFLAGS = -I$inc_current -I$inc_modules -I$inc_libraries -I/usr/include/AL -I/usr/include/freetype2 \$(INCLUDE_LUA) -I/usr/include/SDL \$(FILE_OFFSET)
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES =
SUBDIRS =
@@ -0,0 +1,67 @@
+LÖVE is an *awesome* framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, Mac OS X and Linux.
+Documentation
+-------------
+We use our [wiki][wiki] for documentation.
+If you need further help, feel free to ask on our [forums][forums], and last but not least there's the irc channel [#love on Freenode][irc].
+Compilation
+-----------
+###Windows
+Use the project files for Visual C++ 2008 or 2010 (2010 preferred) located in the platform dir.
+###*nix
+Run platform/unix/automagic, then run ./configure and make.
+###OSX
+Use the XCode project in platform/macosx.
+For both Windows and OSX there are dependencies available [here][dependencies].
+Repository information
+----------------------
+We use the 'default' branch for development, and therefore it should not be considered stable.
+Also used is the 'minor' branch, which is used for features in the next minor version and it is
+not our development target (which would be the next revision). (Version numbers formatted major.minor.revision.)
+We tag all our releases (since we started using mercurial), and have binary downloads available for them.
+Builds
+------
+Releases are found in the 'downloads' section on bitbucket, are linked on [the site][site],
+and there's a ppa for ubuntu, [ppa:bartbes/love-stable][stableppa].
+There are also unstable/nightly builds:
+- For windows they are located [here][winbuilds].
+- For ubuntu linux they are in [ppa:bartbes/love-unstable][unstableppa]
+- For arch linux there's [love-hg][aur] in the AUR.
+- For other linuxes and OSX there are currently no official builds.
+Dependencies
+------------
+- SDL
+- OpenGL
+- OpenAL
+- Lua / LuaJIT / LLVM-lua
+- DevIL with MNG and TIFF
+- FreeType
+- PhysicsFS
+- ModPlug
+- mpg123
+- Vorbisfile
+[site]: http://love2d.org
+[wiki]: http://love2d.org/wiki
+[forums]: http://love2d.org/forums
+[irc]: irc://irc.freenode.net/love
+[dependencies]: http://love2d.org/sdk
+[winbuilds]: http://love2d.org/builds
+[stableppa]: https://launchpad.net/~bartbes/+archive/love-stable
+[unstableppa]: https://launchpad.net/~bartbes/+archive/love-unstable
+[aur]: http://aur.archlinux.org/packages.php?ID=35279
@@ -1,25 +0,0 @@
-
-! WARNING !
------------
-This software is not complete. This is just a preview. Don't expect to find any
-interface consistencies between releases at all. With each release, everything
-you once knew and loved may be brutally murdered. By which I mean removed and/or
-changed.
-RUNNING GAMES
--------------
-In Windows or other graphical enviroments, just open the .love file you want to
-run with the love binary, such as love.exe. (~^-^)~
-In a console, type "love" followed by the relative or absolute path to a directory
-(or archive).
-Examples:
-* love mygame.love
-* love /home/hax/ultragame
-Remember that what you are trying to run at least should contain the file "main.lua".
@@ -1,56 +1,56 @@
-/**
-* Copyright (c) 2006-2011 LOVE Development Team
-*
-* This software is provided 'as-is', without any express or implied
-* warranty. In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-**/
-#ifndef LOVE_DATA_H
-#define LOVE_DATA_H
-// LOVE
-#include "config.h"
-#include "Object.h"
-namespace love
-{
- /**
- * This class is a simple abstraction over all objects which contain data.
- **/
- class Data : public Object
- {
- public:
- * Destructor.
- virtual ~Data() {};
- * Gets a pointer to the data. This pointer will obviously not
- * be valid if the Data object is destroyed.
- virtual void * getData() const = 0 ;
- * Gets the size of the Data in bytes.
- virtual int getSize() const = 0;
- }; // Data
-} // love
-#endif // LOVE_DATA_H
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+#ifndef LOVE_DATA_H
+#define LOVE_DATA_H
+// LOVE
+#include "config.h"
+#include "Object.h"
+namespace love
+{
+ /**
+ * This class is a simple abstraction over all objects which contain data.
+ **/
+ class Data : public Object
+ {
+ public:
+ * Destructor.
+ virtual ~Data() {};
+ * Gets a pointer to the data. This pointer will obviously not
+ * be valid if the Data object is destroyed.
+ virtual void * getData() const = 0 ;
+ * Gets the size of the Data in bytes.
+ virtual int getSize() const = 0;
+ }; // Data
+} // love
+#endif // LOVE_DATA_H
@@ -1,14 +1,14 @@
/**
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
@@ -41,7 +41,7 @@ namespace love
Value values_u[PEAK];
public:
struct Entry
{
T t;
@@ -52,27 +52,27 @@ namespace love
unsigned n = size/sizeof(Entry);
- for(unsigned i = 0; i<n; ++i)
+ for (unsigned i = 0; i<n; ++i)
unsigned e_t = (unsigned)entries[i].t;
unsigned e_u = (unsigned)entries[i].u;
- if(e_t < PEAK)
+ if (e_t < PEAK)
values_u[e_t].v = e_u;
values_u[e_t].set = true;
}
- if(e_u < PEAK)
+ if (e_u < PEAK)
values_t[e_u].v = e_t;
values_t[e_u].set = true;
bool find(T t, U & u)
- if((unsigned)t < PEAK && values_u[(unsigned)t].set)
+ if ((unsigned)t < PEAK && values_u[(unsigned)t].set)
u = (U)values_u[(unsigned)t].v;
return true;
@@ -83,7 +83,7 @@ namespace love
bool find(U u, T & t)
- if((unsigned)u < PEAK && values_t[(unsigned)u].set)
+ if ((unsigned)u < PEAK && values_t[(unsigned)u].set)
t = (T)values_t[(unsigned)u].v;
@@ -1,38 +1,62 @@
-#include "Exception.h"
- Exception::Exception(const char * fmt, ...)
- va_list args;
- va_start(args, fmt);
- vsnprintf(buffer, BUFFER_SIZE, fmt, args);
- va_end(args);
- }
- const char * Exception::what() const throw()
- return (const char *)buffer;
-}
+#include "Exception.h"
+#include <common/config.h>
+#include <iostream>
+using namespace std;
+ Exception::Exception(const char * fmt, ...)
+ va_list args;
+ int size_buffer = 256, size_out;
+ char * buffer;
+ while (true)
+ buffer = new char[size_buffer];
+ memset(buffer, 0, size_buffer);
+ va_start(args, fmt);
+ size_out = vsnprintf(buffer, size_buffer, fmt, args);
+ va_end(args);
+ // see http://perfec.to/vsnprintf/pasprintf.c
+ // if size_out ...
+ // == -1 --> output was truncated
+ // == size_buffer --> output was truncated
+ // == size_buffer-1 --> ambiguous, /may/ have been truncated
+ // > size_buffer --> output was truncated, and size_out
+ // bytes would have been written
+ if (size_out == size_buffer || size_out == -1 || size_out == size_buffer-1)
+ size_buffer *= 2;
+ else if (size_out > size_buffer)
+ size_buffer = size_out + 2; // to avoid the ambiguous case
+ else
+ break;
+ delete[] buffer;
+ }
+ message = std::string(buffer);
@@ -1,68 +1,64 @@
-#ifndef LOVE_EXCEPTION_H
-#define LOVE_EXCEPTION_H
-#include <exception>
-#include <cstdarg> // vararg
-#include <cstdio> // vsnprintf
- * A convenient vararg-enabled exception class.
- class Exception : public std::exception
- private:
- * The vsnprintf operates on a buffer this large.
- static const int BUFFER_SIZE = 256;
- * The buffer for vsnprintf.
- char buffer[BUFFER_SIZE];
- * Creates a new Exception according to printf-rules.
- *
- * See: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
- * @param fmt The format string (see printf).
- Exception(const char * fmt, ...);
- * Returns a string containing reason for the exception.
- * @return A description of the exception.
- virtual const char * what() const throw();
- }; // class
-#endif // LOVE_EXCEPTION_H
+#ifndef LOVE_EXCEPTION_H
+#define LOVE_EXCEPTION_H
+#include <exception>
+#include <cstdarg> // vararg
+#include <cstdio> // vsnprintf
+#include <cstring> // strncpy
+#include <string>
+ * A convenient vararg-enabled exception class.
+ class Exception : public std::exception
+ private:
+ std::string message;
+ * Creates a new Exception according to printf-rules.
+ *
+ * See: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
+ * @param fmt The format string (see printf).
+ Exception(const char * fmt, ...);
+ virtual ~Exception() throw() {}
+ * Returns a string containing reason for the exception.
+ * @return A description of the exception.
+ inline virtual const char * what() const throw()
+ { return message.c_str(); }
+ }; // class
+#endif // LOVE_EXCEPTION_H
@@ -1,182 +1,196 @@
-#include "Matrix.h"
-// STD
-#include <cstring> // memcpy
-#include <cmath>
- // | e0 e4 e8 e12 |
- // | e1 e5 e9 e13 |
- // | e2 e6 e10 e14 |
- // | e3 e7 e11 e15 |
- Matrix::Matrix()
- setIdentity();
- Matrix::~Matrix()
- Matrix Matrix::operator * (const Matrix & m) const
- Matrix t;
- t.e[0] = (e[0]*m.e[0]) + (e[4]*m.e[1]) + (e[8]*m.e[2]) + (e[12]*m.e[3]);
- t.e[4] = (e[0]*m.e[4]) + (e[4]*m.e[5]) + (e[8]*m.e[6]) + (e[12]*m.e[7]);
- t.e[8] = (e[0]*m.e[8]) + (e[4]*m.e[9]) + (e[8]*m.e[10]) + (e[12]*m.e[11]);
- t.e[12] = (e[0]*m.e[12]) + (e[4]*m.e[13]) + (e[8]*m.e[14]) + (e[12]*m.e[15]);
- t.e[1] = (e[1]*m.e[0]) + (e[5]*m.e[1]) + (e[9]*m.e[2]) + (e[13]*m.e[3]);
- t.e[5] = (e[1]*m.e[4]) + (e[5]*m.e[5]) + (e[9]*m.e[6]) + (e[13]*m.e[7]);
- t.e[9] = (e[1]*m.e[8]) + (e[5]*m.e[9]) + (e[9]*m.e[10]) + (e[13]*m.e[11]);
- t.e[13] = (e[1]*m.e[12]) + (e[5]*m.e[13]) + (e[9]*m.e[14]) + (e[13]*m.e[15]);
- t.e[2] = (e[2]*m.e[0]) + (e[6]*m.e[1]) + (e[10]*m.e[2]) + (e[14]*m.e[3]);
- t.e[6] = (e[2]*m.e[4]) + (e[6]*m.e[5]) + (e[10]*m.e[6]) + (e[14]*m.e[7]);
- t.e[10] = (e[2]*m.e[8]) + (e[6]*m.e[9]) + (e[10]*m.e[10]) + (e[14]*m.e[11]);
- t.e[14] = (e[2]*m.e[12]) + (e[6]*m.e[13]) + (e[10]*m.e[14]) + (e[14]*m.e[15]);
- t.e[3] = (e[3]*m.e[0]) + (e[7]*m.e[1]) + (e[11]*m.e[2]) + (e[15]*m.e[3]);
- t.e[7] = (e[3]*m.e[4]) + (e[7]*m.e[5]) + (e[11]*m.e[6]) + (e[15]*m.e[7]);
- t.e[11] = (e[3]*m.e[8]) + (e[7]*m.e[9]) + (e[11]*m.e[10]) + (e[15]*m.e[11]);
- t.e[15] = (e[3]*m.e[12]) + (e[7]*m.e[13]) + (e[11]*m.e[14]) + (e[15]*m.e[15]);
- return t;
- void Matrix::operator *= (const Matrix & m)
- Matrix t = (*this) * m;
- memcpy((void*)this->e, (void*)t.e, sizeof(float)*16);
- const float * Matrix::getElements() const
- return e;
- void Matrix::setIdentity()
- memset(e, 0, sizeof(float)*16);
- e[0] = e[5] = e[10] = e[15] = 1;
- void Matrix::setTranslation(float x, float y)
- e[12] = x;
- e[13] = y;
- void Matrix::setRotation(float rad)
- float c = cos(rad), s = sin(rad);
- e[0] = c; e[4] = -s;
- e[1] = s; e[5] = c;
- void Matrix::setScale(float sx, float sy)
- e[0] = sx;
- e[5] = sy;
- void Matrix::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy)
- memset(e, 0, sizeof(float)*16); // zero out matrix
- float c = cos(angle), s = sin(angle);
- // matrix multiplication carried out on paper:
- // |1 x| |c -s | |sx | |1 -ox|
- // | 1 y| |s c | | sy | | 1 -oy|
- // | 1 | | 1 | | 1 | | 1 |
- // | 1| | 1| | 1| | 1 |
- // move rotate scale origin
- e[10] = e[15] = 1.0f;
- e[0] = sx * c;
- e[1] = sx * s;
- e[4] = -sy * s;
- e[5] = sy * c;
- e[12] = -ox * e[0] - oy * e[4] + x;
- e[13] = -ox * e[1] - oy * e[5] + y;
- void Matrix::translate(float x, float y)
- t.setTranslation(x, y);
- this->operator *=(t);
- void Matrix::rotate(float rad)
- t.setRotation(rad);
- void Matrix::scale(float sx, float sy)
- t.setScale(sx, sy);
- // | x |
- // | y |
- // | 0 |
- // | 1 |
- void Matrix::transform(vertex * dst, const vertex * src, int size) const
- for(int i = 0;i<size;i++)
- // Store in temp variables in case src = dst
- float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
- float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
- dst[i].x = x;
- dst[i].y = y;
+#include "Matrix.h"
+// STD
+#include <cstring> // memcpy
+#include <cmath>
+ // | e0 e4 e8 e12 |
+ // | e1 e5 e9 e13 |
+ // | e2 e6 e10 e14 |
+ // | e3 e7 e11 e15 |
+ Matrix::Matrix()
+ setIdentity();
+ Matrix::~Matrix()
+ Matrix Matrix::operator * (const Matrix & m) const
+ Matrix t;
+ t.e[0] = (e[0]*m.e[0]) + (e[4]*m.e[1]) + (e[8]*m.e[2]) + (e[12]*m.e[3]);
+ t.e[4] = (e[0]*m.e[4]) + (e[4]*m.e[5]) + (e[8]*m.e[6]) + (e[12]*m.e[7]);
+ t.e[8] = (e[0]*m.e[8]) + (e[4]*m.e[9]) + (e[8]*m.e[10]) + (e[12]*m.e[11]);
+ t.e[12] = (e[0]*m.e[12]) + (e[4]*m.e[13]) + (e[8]*m.e[14]) + (e[12]*m.e[15]);
+ t.e[1] = (e[1]*m.e[0]) + (e[5]*m.e[1]) + (e[9]*m.e[2]) + (e[13]*m.e[3]);
+ t.e[5] = (e[1]*m.e[4]) + (e[5]*m.e[5]) + (e[9]*m.e[6]) + (e[13]*m.e[7]);
+ t.e[9] = (e[1]*m.e[8]) + (e[5]*m.e[9]) + (e[9]*m.e[10]) + (e[13]*m.e[11]);
+ t.e[13] = (e[1]*m.e[12]) + (e[5]*m.e[13]) + (e[9]*m.e[14]) + (e[13]*m.e[15]);
+ t.e[2] = (e[2]*m.e[0]) + (e[6]*m.e[1]) + (e[10]*m.e[2]) + (e[14]*m.e[3]);
+ t.e[6] = (e[2]*m.e[4]) + (e[6]*m.e[5]) + (e[10]*m.e[6]) + (e[14]*m.e[7]);
+ t.e[10] = (e[2]*m.e[8]) + (e[6]*m.e[9]) + (e[10]*m.e[10]) + (e[14]*m.e[11]);
+ t.e[14] = (e[2]*m.e[12]) + (e[6]*m.e[13]) + (e[10]*m.e[14]) + (e[14]*m.e[15]);
+ t.e[3] = (e[3]*m.e[0]) + (e[7]*m.e[1]) + (e[11]*m.e[2]) + (e[15]*m.e[3]);
+ t.e[7] = (e[3]*m.e[4]) + (e[7]*m.e[5]) + (e[11]*m.e[6]) + (e[15]*m.e[7]);
+ t.e[11] = (e[3]*m.e[8]) + (e[7]*m.e[9]) + (e[11]*m.e[10]) + (e[15]*m.e[11]);
+ t.e[15] = (e[3]*m.e[12]) + (e[7]*m.e[13]) + (e[11]*m.e[14]) + (e[15]*m.e[15]);
+ return t;
+ void Matrix::operator *= (const Matrix & m)
+ Matrix t = (*this) * m;
+ memcpy((void*)this->e, (void*)t.e, sizeof(float)*16);
+ const float * Matrix::getElements() const
+ return e;
+ void Matrix::setIdentity()
+ memset(e, 0, sizeof(float)*16);
+ e[0] = e[5] = e[10] = e[15] = 1;
+ void Matrix::setTranslation(float x, float y)
+ e[12] = x;
+ e[13] = y;
+ void Matrix::setRotation(float rad)
+ float c = cos(rad), s = sin(rad);
+ e[0] = c; e[4] = -s;
+ e[1] = s; e[5] = c;
+ void Matrix::setScale(float sx, float sy)
+ e[0] = sx;
+ e[5] = sy;
+ void Matrix::setShear(float kx, float ky)
+ e[1] = ky;
+ e[4] = kx;
+ void Matrix::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+ memset(e, 0, sizeof(float)*16); // zero out matrix
+ float c = cos(angle), s = sin(angle);
+ // matrix multiplication carried out on paper:
+ // |1 x| |c -s | |sx | | 1 ky | |1 -ox|
+ // | 1 y| |s c | | sy | |kx 1 | | 1 -oy|
+ // | 1 | | 1 | | 1 | | 1 | | 1 |
+ // | 1| | 1| | 1| | 1| | 1 |
+ // move rotate scale skew origin
+ e[10] = e[15] = 1.0f;
+ e[0] = c * sx - ky * s * sy; // = a
+ e[1] = s * sx + ky * c * sy; // = b
+ e[4] = kx * c * sx - s * sy; // = c
+ e[5] = kx * s * sx + c * sy; // = d
+ e[12] = x - ox * e[0] - oy * e[4];
+ e[13] = y - ox * e[1] - oy * e[5];
+ void Matrix::translate(float x, float y)
+ t.setTranslation(x, y);
+ this->operator *=(t);
+ void Matrix::rotate(float rad)
+ t.setRotation(rad);
+ void Matrix::scale(float sx, float sy)
+ t.setScale(sx, sy);
+ void Matrix::shear(float kx, float ky)
+ t.setShear(kx,ky);
+ // | x |
+ // | y |
+ // | 0 |
+ // | 1 |
+ void Matrix::transform(vertex * dst, const vertex * src, int size) const
+ for (int i = 0;i<size;i++)
+ // Store in temp variables in case src = dst
+ float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
+ float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
+ dst[i].x = x;
+ dst[i].y = y;
@@ -1,150 +1,166 @@
-#ifndef LOVE_MATRIX_H
-#define LOVE_MATRIX_H
-#include "math.h"
- * This class is the basis for all transformations in LOVE. Althought not
- * really needed for 2D, it contains 4x4 elements to be compatible with
- * OpenGL without conversions.
- class Matrix
- * | e0 e4 e8 e12 |
- * | e1 e5 e9 e13 |
- * | e2 e6 e10 e14 |
- * | e3 e7 e11 e15 |
- float e[16];
- * Creates a new identity matrix.
- Matrix();
- ~Matrix();
- * Multiplies this Matrix with another Matrix, changing neither.
- * @param m The Matrix to multiply with this Matrix.
- * @return The combined matrix.
- Matrix operator * (const Matrix & m) const;
- * Multiplies a Matrix into this Matrix.
- * @param m The Matrix to combine into this Matrix.
- void operator *= (const Matrix & m);
- * Gets a pointer to the 16 array elements.
- * @return The array elements.
- const float * getElements() const;
- * Resets this Matrix to the identity matrix.
- void setIdentity();
- * Resets this Matrix to a translation.
- * @param x Translation along x-axis.
- * @param y Translation along y-axis.
- void setTranslation(float x, float y);
- * Resets this Matrix to a rotaion.
- * @param r The angle in radians.
- void setRotation(float r);
- * Resets this Matrix to a scale transformation.
- * @param sx Scale factor along the x-axis.
- * @param sy Scale factor along the y-axis.
- void setScale(float sx, float sy);
- * Creates a transformation with a certain position, orientation, scale
- * and offset. Perfect for Drawables -- what a coincidence!
- * @param x The translation along the x-axis.
- * @param y The translation along the y-axis.
- * @param angle The rotation (rad) around the center with offset (ox,oy).
- * @param sx Scale along x-axis.
- * @param sy Scale along y-axis.
- * @param ox The offset for rotation along the x-axis.
- * @param oy The offset for rotation along the y-axis.
- void setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy);
- * Multiplies this Matrix with a translation.
- void translate(float x, float y);
- * Multiplies this Matrix with a rotation.
- * @param r Angle in radians.
- void rotate(float r);
- * Multiplies this Matrix with a scale transformation.
- void scale(float sx, float sy);
- * Transforms an array of vertices by this Matrix. The sources and
- * destination arrays may be the same.
- * @param dst Storage for the transformed vertices.
- * @param src The source vertices.
- * @param size The number of vertices.
- void transform(vertex * dst, const vertex * src, int size) const;
- }; // Matrix
-} //love
-#endif// LOVE_MATRIX_H
+#ifndef LOVE_MATRIX_H
+#define LOVE_MATRIX_H
+#include "math.h"
+ * This class is the basis for all transformations in LOVE. Althought not
+ * really needed for 2D, it contains 4x4 elements to be compatible with
+ * OpenGL without conversions.
+ class Matrix
+ * | e0 e4 e8 e12 |
+ * | e1 e5 e9 e13 |
+ * | e2 e6 e10 e14 |
+ * | e3 e7 e11 e15 |
+ float e[16];
+ * Creates a new identity matrix.
+ Matrix();
+ ~Matrix();
+ * Multiplies this Matrix with another Matrix, changing neither.
+ * @param m The Matrix to multiply with this Matrix.
+ * @return The combined matrix.
+ Matrix operator * (const Matrix & m) const;
+ * Multiplies a Matrix into this Matrix.
+ * @param m The Matrix to combine into this Matrix.
+ void operator *= (const Matrix & m);
+ * Gets a pointer to the 16 array elements.
+ * @return The array elements.
+ const float * getElements() const;
+ * Resets this Matrix to the identity matrix.
+ void setIdentity();
+ * Resets this Matrix to a translation.
+ * @param x Translation along x-axis.
+ * @param y Translation along y-axis.
+ void setTranslation(float x, float y);
+ * Resets this Matrix to a rotation.
+ * @param r The angle in radians.
+ void setRotation(float r);
+ * Resets this Matrix to a scale transformation.
+ * @param sx Scale factor along the x-axis.
+ * @param sy Scale factor along the y-axis.
+ void setScale(float sx, float sy);
+ * Resets this Matrix to a shear transformation.
+ * @param kx Shear along x-axis.
+ * @param ky Shear along y-axis.
+ void setShear(float kx, float ky);
+ * Creates a transformation with a certain position, orientation, scale
+ * and offset. Perfect for Drawables -- what a coincidence!
+ * @param x The translation along the x-axis.
+ * @param y The translation along the y-axis.
+ * @param angle The rotation (rad) around the center with offset (ox,oy).
+ * @param sx Scale along x-axis.
+ * @param sy Scale along y-axis.
+ * @param ox The offset for rotation along the x-axis.
+ * @param oy The offset for rotation along the y-axis.
+ * @param kx Shear along x-axis
+ * @param ky Shear along y-axis
+ void setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
+ * Multiplies this Matrix with a translation.
+ void translate(float x, float y);
+ * Multiplies this Matrix with a rotation.
+ * @param r Angle in radians.
+ void rotate(float r);
+ * Multiplies this Matrix with a scale transformation.
+ void scale(float sx, float sy);
+ * Multiplies this Matrix with a shear transformation.
+ * @param kx Shear along the x-axis.
+ * @param ky Shear along the y-axis.
+ void shear(float kx, float ky);
+ * Transforms an array of vertices by this Matrix. The sources and
+ * destination arrays may be the same.
+ * @param dst Storage for the transformed vertices.
+ * @param src The source vertices.
+ * @param size The number of vertices.
+ void transform(vertex * dst, const vertex * src, int size) const;
+ }; // Matrix
+} //love
+#endif// LOVE_MATRIX_H
@@ -0,0 +1,44 @@
+#include "Memoizer.h"
+#include <cstddef>
+ std::map<void *, void *> Memoizer::objectMap;
+ void Memoizer::add(void * key, void * val)
+ objectMap[key] = val;
+ void Memoizer::remove(void * key)
+ objectMap.erase(key);
+ void * Memoizer::find(void * key)
+ if (objectMap.count(key)) return objectMap[key];
+ return NULL;
@@ -1,5 +1,5 @@
*
@@ -18,24 +18,29 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
-#ifndef LOVE_THREAD_THREAD_H
-#define LOVE_THREAD_THREAD_H
+#ifndef LOVE_MEMOIZER_H
+#define LOVE_MEMOIZER_H
-#include <common/Module.h>
-#include <string>
+#include <map>
namespace love
-namespace thread
- class ThreadModule : public Module
+ class Memoizer
+ static std::map<void *, void *> objectMap;
- virtual ~ThreadModule(){};
- virtual void unregister(const std::string & name) = 0;
- }; // ThreadModule
-} // thread
+ static void add(void * key, void * val);
+ static void remove(void * key);
+ static void * find(void * key);
+ }; // Memoizer
} // love
-#endif // LOVE_THREAD_THREAD_H
+#endif // LOVE_MEMOIZER_H
@@ -29,7 +29,7 @@
- * Abstract superclass for all modules.
+ * Abstract superclass for all modules.
class Module : public Object
@@ -43,8 +43,8 @@ namespace love
* Gets the name of the module. This is used in case of errors
* and other messages.
- * @return The full name of the module, eg. love.graphics.opengl.
+ * @return The full name of the module, eg. love.graphics.opengl.
virtual const char * getName() const = 0;
@@ -45,7 +45,7 @@ namespace love
void Object::release()
- if(--count <= 0)
+ if (--count <= 0)
delete this;
@@ -1,70 +1,81 @@
-#include "Reference.h"
- Reference::Reference()
- : L(0), idx(LUA_REFNIL)
- Reference::Reference(lua_State * L)
- ref(L);
- Reference::~Reference()
- unref();
- void Reference::ref(lua_State * L)
- unref(); // Just to be safe.
- this->L = L;
- idx = luaL_ref(L, LUA_GLOBALSINDEX);
- void Reference::unref()
- if(idx != LUA_REFNIL)
- luaL_unref(L, LUA_GLOBALSINDEX, idx);
- idx = LUA_REFNIL;
- void Reference::push()
- lua_rawgeti(L, LUA_GLOBALSINDEX, idx);
- else
- lua_pushnil(L);
- lua_State * Reference::getL()
- return L;
+#include "Reference.h"
+ const char REFERENCE_TABLE_NAME[] = "love-references";
+ Reference::Reference()
+ : L(0), idx(LUA_REFNIL)
+ Reference::Reference(lua_State * L)
+ ref(L);
+ Reference::~Reference()
+ unref();
+ void Reference::ref(lua_State * L)
+ unref(); // Just to be safe.
+ this->L = L;
+ luax_insist(L, LUA_REGISTRYINDEX, REFERENCE_TABLE_NAME);
+ lua_insert(L, -2); // Move reference table behind value.
+ idx = luaL_ref(L, -2);
+ lua_pop(L, 1);
+ void Reference::unref()
+ if (idx != LUA_REFNIL)
+ luaL_unref(L, -1, idx);
+ idx = LUA_REFNIL;
+ void Reference::push()
+ lua_rawgeti(L, -1, idx);
+ lua_remove(L, -2);
+ lua_pushnil(L);
+ lua_State * Reference::getL()
+ return L;
@@ -49,7 +49,7 @@ namespace love
Reference();
- * Creates the object and a reference to the value
+ * Creates the object and a reference to the value
* on the top of the stack.
Reference(lua_State * L);
@@ -58,11 +58,11 @@ namespace love
* Deletes the reference, if any.
virtual ~Reference();
* Creates a reference to the value on the
* top of the stack.
void ref(lua_State * L);
@@ -54,12 +54,12 @@ namespace love
StringMap(Entry * entries, unsigned num)
- for(unsigned i = 0; i < SIZE; ++i)
+ for (unsigned i = 0; i < SIZE; ++i)
reverse[i] = 0;
unsigned n = num/sizeof(Entry);
- for(unsigned i = 0; i < n; ++i)
+ for (unsigned i = 0; i < n; ++i)
add(entries[i].key, entries[i].value);
@@ -67,9 +67,9 @@ namespace love
bool streq(const char * a, const char * b)
- while(*a != 0 && *b != 0)
+ while (*a != 0 && *b != 0)
- if(*a != *b)
+ if (*a != *b)
return false;
++a;
++b;
@@ -80,15 +80,18 @@ namespace love
bool find(const char * key, T & t)
- //unsigned str_hash = djb2(key);
+ unsigned str_hash = djb2(key);
- for(unsigned i = 0; i < MAX; ++i)
+ for (unsigned i = 0; i < MAX; ++i)
- //unsigned str_i = (str_hash + i) % MAX; //this isn't used, is this intentional?
+ unsigned str_i = (str_hash + i) % MAX; //this isn't used, is this intentional?
+ if (!records[str_i].set)
+ return false;
- if(records[i].set && streq(records[i].key, key))
+ if (streq(records[str_i].key, key))
- t = records[i].value;
+ t = records[str_i].value;
@@ -100,10 +103,10 @@ namespace love
unsigned index = (unsigned)key;
- if(index >= SIZE)
+ if (index >= SIZE)
- if(reverse[index] != 0)
+ if (reverse[index] != 0)
str = reverse[index];
@@ -118,12 +121,12 @@ namespace love
unsigned str_hash = djb2(key);
bool inserted = false;
unsigned str_i = (str_hash + i) % MAX;
- if(!records[str_i].set)
inserted = true;
records[str_i].set = true;
@@ -135,7 +138,7 @@ namespace love
unsigned index = (unsigned)value;
printf("\nConstant %s out of bounds with %i!\n", key, index);
@@ -0,0 +1,173 @@
+#include "Variant.h"
+#include <common/StringMap.h>
+ extern StringMap<Type, TYPE_MAX_ENUM> types;
+ love::Type extractudatatype(lua_State * L, int idx)
+ Type t = INVALID_ID;
+ if (!lua_isuserdata(L, idx))
+ if (luaL_getmetafield (L, idx, "__tostring") == 0)
+ lua_pushvalue(L, idx);
+ int result = lua_pcall(L, 1, 1, 0);
+ if (result == 0)
+ types.find(lua_tostring(L, -1), t);
+ if (result == 0 || result == LUA_ERRRUN)
+ Variant::Variant(bool boolean)
+ type = BOOLEAN;
+ data.boolean = boolean;
+ Variant::Variant(double number)
+ type = NUMBER;
+ data.number = number;
+ Variant::Variant(const char *string, size_t len)
+ type = STRING;
+ char *buf = new char[len+1];
+ memset(buf, 0, len+1);
+ memcpy(buf, string, len);
+ data.string.str = buf;
+ data.string.len = len;
+ Variant::Variant(char c)
+ type = CHARACTER;
+ data.character = c;
+ Variant::Variant(void *userdata)
+ type = LUSERDATA;
+ data.userdata = userdata;
+ Variant::Variant(love::Type udatatype, void *userdata)
+ type = FUSERDATA;
+ this->udatatype = udatatype;
+ if (udatatype != INVALID_ID)
+ Proxy *p = (Proxy *) userdata;
+ flags = p->flags;
+ data.userdata = p->data;
+ ((love::Object *) data.userdata)->retain();
+ Variant::~Variant()
+ switch(type)
+ case STRING:
+ delete[] data.string.str;
+ case FUSERDATA:
+ ((love::Object *) data.userdata)->release();
+ default:
+ Variant *Variant::fromLua(lua_State *L, int n)
+ Variant *v = NULL;
+ size_t len;
+ const char *str;
+ switch(lua_type(L, n))
+ case LUA_TBOOLEAN:
+ v = new Variant(luax_toboolean(L, n));
+ case LUA_TNUMBER:
+ v = new Variant(lua_tonumber(L, n));
+ case LUA_TSTRING:
+ str = lua_tolstring(L, n, &len);
+ v = new Variant(str, len);
+ case LUA_TLIGHTUSERDATA:
+ v = new Variant(lua_touserdata(L, n));
+ case LUA_TUSERDATA:
+ v = new Variant(extractudatatype(L, n), lua_touserdata(L, n));
+ return v;
+ void Variant::toLua(lua_State *L)
+ case BOOLEAN:
+ lua_pushboolean(L, data.boolean);
+ case CHARACTER:
+ lua_pushlstring(L, &data.character, 1);
+ case NUMBER:
+ lua_pushnumber(L, data.number);
+ lua_pushlstring(L, data.string.str, data.string.len);
+ case LUSERDATA:
+ lua_pushlightuserdata(L, data.userdata);
+ const char *name = NULL;
+ love::types.find(udatatype, name);
+ luax_newtype(L, name, flags, data.userdata);
+ // I know this is not the same
+ // sadly, however, it's the most
+ // I can do (at the moment).
@@ -0,0 +1,73 @@
+#ifndef LOVE_VARIANT_H
+#define LOVE_VARIANT_H
+#include <common/runtime.h>
+#include <common/Object.h>
+#include <cstring>
+ class Variant : public love::Object
+ enum Type
+ UNKNOWN = 0,
+ BOOLEAN,
+ NUMBER,
+ CHARACTER,
+ STRING,
+ LUSERDATA,
+ FUSERDATA
+ } type;
+ union
+ bool boolean;
+ char character;
+ double number;
+ struct {
+ } string;
+ void *userdata;
+ } data;
+ love::Type udatatype;
+ bits flags;
+ Variant(bool boolean);
+ Variant(double number);
+ Variant(const char *string, size_t len);
+ Variant(char c);
+ Variant(void *userdata);
+ Variant(love::Type udatatype, void *userdata);
+ virtual ~Variant();
+ static Variant *fromLua(lua_State *L, int n);
+ void toLua(lua_State *L);
+ }; // Variant
+#endif // LOVE_VARIANT_H
@@ -1,26 +1,26 @@
-#include "Vector.h"
- // Implementation in header.
+#include "Vector.h"
+ // Implementation in header.
@@ -1,310 +1,310 @@
-#ifndef LOVE_VECTOR_H
-#define LOVE_VECTOR_H
- * 2D Vector class.
- * @author Anders Ruud
- * @date 2006-05-13
- class Vector
- // The components.
- float x, y;
- * Creates a new (1,1) Vector.
- Vector();
- * Creates a new Vector.
- * @param x The x position/dimension.
- * @param y The y position/dimension.
- Vector(float x, float y);
- * Gets the length of the Vector.
- * @return The length of the Vector.
- * This method requires sqrt() and should be used
- * carefully.
- float getLength() const;
- * Normalizes the Vector.
- * @return The old length of the Vector.
- float normalize();
- * Gets a normal to the Vector.
- * @return A normal to the Vector.
- Vector getNormal() const;
- * Adds a Vector to this Vector.
- * @param v The Vector we want to add to this Vector.
- * @return The resulting Vector.
- Vector operator + (const Vector & v) const;
- * Substracts a Vector to this Vector.
- * @param v The Vector we want to subtract to this Vector.
- Vector operator - (const Vector & v) const;
- * Resizes a Vector by a scalar.
- * @param s The scalar with which to resize the Vector.
- Vector operator * (float s) const;
- Vector operator / (float s) const;
- * Reverses the Vector.
- * @return The reversed Vector.
- Vector operator - () const;
- * Adds a Vector to this Vector, and also saves changes in the first Vector.
- void operator += (const Vector & v);
- * Subtracts a Vector to this Vector, and also saves changes in the first Vector.
- void operator -= (const Vector & v);
- * Resizes the Vector, and also saves changes in the first Vector.
- * @param s The scalar by which we want to resize the Vector.
- void operator *= (float s);
- void operator /= (float s);
- * Calculates the dot product of two Vectors.
- * @return The dot product of the two Vectors.
- float operator * (const Vector & v) const;
- * Calculates the cross product of two Vectors.
- * @return The cross product of the two Vectors.
- float operator ^ (const Vector & v) const;
- bool operator == (const Vector & v) const;
- bool operator < (const Vector & v) const;
- * Gets the x value of the Vector.
- * @return The x value of the Vector.
- float getX() const;
- float getY() const;
- * Sets the x value of the Vector.
- * @param The x value of the Vector.
- void setX(float x);
- void setY(float y);
- };
- inline float Vector::getLength() const
- return sqrt(x*x + y*y);
- inline Vector Vector::getNormal() const
- return Vector(-y, x);
- inline float Vector::normalize()
- float len = getLength();
- if(len > 0)
- (*this) /= len;
- return len;
- * Inline methods must have body in header.
- inline Vector::Vector()
- x = 1;
- y = 1;
- inline Vector::Vector(float x, float y)
- this->x = x;
- this->y = y;
- inline Vector Vector::operator + (const Vector & v) const
- return Vector(x + v.x, y + v.y);
- inline Vector Vector::operator - (const Vector & v) const
- return Vector(x - v.getX(), y - v.getY());
- inline Vector Vector::operator * (float s) const
- return Vector(x*s, y*s);
- inline Vector Vector::operator / (float s) const
- return Vector(x/s, y/s);
- inline Vector Vector::operator - () const
- return Vector(-x, -y);
- inline void Vector::operator += (const Vector & v)
- x += v.getX();
- y += v.getY();
- inline void Vector::operator -= (const Vector & v)
- x -= v.getX();
- y -= v.getY();
- inline void Vector::operator *= (float s)
- x *= s;
- y *= s;
- inline void Vector::operator /= (float s)
- x /= s;
- y /= s;
- inline float Vector::operator * (const Vector & v) const
- return x * v.getX() + y * v.getY();
- inline float Vector::operator ^ (const Vector & v) const
- return x * v.getY() - y * v.getX();
- inline bool Vector::operator == (const Vector & v) const
- return getLength() == v.getLength();
- inline bool Vector::operator < (const Vector & v) const
- return getLength() < v.getLength();
- * Accessor methods
- inline float Vector::getX() const
- return x;
- inline float Vector::getY() const
- return y;
- inline void Vector::setX(float x)
- inline void Vector::setY(float y)
-#endif// LOVE_VECTOR_H
+#ifndef LOVE_VECTOR_H
+#define LOVE_VECTOR_H
+ * 2D Vector class.
+ * @author Anders Ruud
+ * @date 2006-05-13
+ class Vector
+ // The components.
+ float x, y;
+ * Creates a new (1,1) Vector.
+ Vector();
+ * Creates a new Vector.
+ * @param x The x position/dimension.
+ * @param y The y position/dimension.
+ Vector(float x, float y);
+ * Gets the length of the Vector.
+ * @return The length of the Vector.
+ * This method requires sqrt() and should be used
+ * carefully.
+ float getLength() const;
+ * Normalizes the Vector.
+ * @return The old length of the Vector.
+ float normalize();
+ * Gets a normal to the Vector.
+ * @return A normal to the Vector.
+ Vector getNormal() const;
+ * Adds a Vector to this Vector.
+ * @param v The Vector we want to add to this Vector.
+ * @return The resulting Vector.
+ Vector operator + (const Vector & v) const;
+ * Substracts a Vector to this Vector.
+ * @param v The Vector we want to subtract to this Vector.
+ Vector operator - (const Vector & v) const;
+ * Resizes a Vector by a scalar.
+ * @param s The scalar with which to resize the Vector.
+ Vector operator * (float s) const;
+ Vector operator / (float s) const;
+ * Reverses the Vector.
+ * @return The reversed Vector.
+ Vector operator - () const;
+ * Adds a Vector to this Vector, and also saves changes in the first Vector.
+ void operator += (const Vector & v);
+ * Subtracts a Vector to this Vector, and also saves changes in the first Vector.
+ void operator -= (const Vector & v);
+ * Resizes the Vector, and also saves changes in the first Vector.
+ * @param s The scalar by which we want to resize the Vector.
+ void operator *= (float s);
+ void operator /= (float s);
+ * Calculates the dot product of two Vectors.
+ * @return The dot product of the two Vectors.
+ float operator * (const Vector & v) const;
+ * Calculates the cross product of two Vectors.
+ * @return The cross product of the two Vectors.
+ float operator ^ (const Vector & v) const;
+ bool operator == (const Vector & v) const;
+ bool operator < (const Vector & v) const;
+ * Gets the x value of the Vector.
+ * @return The x value of the Vector.
+ float getX() const;
+ float getY() const;
+ * Sets the x value of the Vector.
+ * @param The x value of the Vector.
+ void setX(float x);
+ void setY(float y);
+ };
+ inline float Vector::getLength() const
+ return sqrt(x*x + y*y);
+ inline Vector Vector::getNormal() const
+ return Vector(-y, x);
+ inline float Vector::normalize()
+ float len = getLength();
+ if (len > 0)
+ (*this) /= len;
+ return len;
+ * Inline methods must have body in header.
+ inline Vector::Vector()
+ x = 1;
+ y = 1;
+ inline Vector::Vector(float x, float y)
+ this->x = x;
+ this->y = y;
+ inline Vector Vector::operator + (const Vector & v) const
+ return Vector(x + v.x, y + v.y);
+ inline Vector Vector::operator - (const Vector & v) const
+ return Vector(x - v.getX(), y - v.getY());
+ inline Vector Vector::operator * (float s) const
+ return Vector(x*s, y*s);
+ inline Vector Vector::operator / (float s) const
+ return Vector(x/s, y/s);
+ inline Vector Vector::operator - () const
+ return Vector(-x, -y);
+ inline void Vector::operator += (const Vector & v)
+ x += v.getX();
+ y += v.getY();
+ inline void Vector::operator -= (const Vector & v)
+ x -= v.getX();
+ y -= v.getY();
+ inline void Vector::operator *= (float s)
+ x *= s;
+ y *= s;
+ inline void Vector::operator /= (float s)
+ x /= s;
+ y /= s;
+ inline float Vector::operator * (const Vector & v) const
+ return x * v.getX() + y * v.getY();
+ inline float Vector::operator ^ (const Vector & v) const
+ return x * v.getY() - y * v.getX();
+ inline bool Vector::operator == (const Vector & v) const
+ return getLength() == v.getLength();
+ inline bool Vector::operator < (const Vector & v) const
+ return getLength() < v.getLength();
+ * Accessor methods
+ inline float Vector::getX() const
+ return x;
+ inline float Vector::getY() const
+ return y;
+ inline void Vector::setX(float x)
+ inline void Vector::setY(float y)
+#endif// LOVE_VECTOR_H
@@ -25,7 +25,7 @@ namespace love
static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
void b64_decode_block(char in[4], char out[3])
out[0] = (char)(in[0] << 2 | in[1] >> 4);
out[1] = (char)(in[1] << 4 | in[2] >> 2);
out[2] = (char)(((in[2] << 6) & 0xc0) | in[3]);
@@ -41,33 +41,34 @@ namespace love
char in[4], out[3], v;
int i, len, pos = 0;
- while(pos <= slen)
+ while (pos <= slen)
- for(len = 0, i = 0; i < 4 && pos <= slen; i++ )
+ for (len = 0, i = 0; i < 4 && pos <= slen; i++ )
v = 0;
- while(pos <= slen && v == 0 )
+ while (pos <= slen && v == 0 )
v = src[pos++];
v = (char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);
- if(v)
+ if (v)
v = (char)((v == '$') ? 0 : v - 61);
- if(pos <= slen)
+ if (pos <= slen)
len++;
in[i] = (char)(v - 1);
else
in[i] = 0;
- if(len) {
+ if (len)
b64_decode_block(in, out);
- for(i = 0; i < len - 1; i++)
+ for (i = 0; i < len - 1; i++)
*(d++) = out[i];
@@ -48,6 +48,10 @@
# define _CRT_SECURE_NO_WARNINGS
#endif
+#ifndef LOVE_UNUSED
+# define LOVE_UNUSED(x) (void)sizeof(x)
+#endif
#ifndef LOVE_BUILD
# define LOVE_BUILD
# define LOVE_BUILD_STANDALONE
@@ -68,4 +72,10 @@
# define NOMINMAX
+// Autotools config.h
+#ifdef HAVE_CONFIG_H
+# include <../config.h>
+# undef VERSION
#endif // LOVE_CONFIG_H
@@ -0,0 +1,41 @@
+#include "delay.h"
+namespace love {
+ void delay(unsigned int ms) {
+#if LOVE_THREADS == LOVE_THREADS_POSIX
+ struct timespec ts1, ts2;
+ ts1.tv_sec = ms / 1000;
+ ts1.tv_nsec = (ms % 1000) * 1000000;
+ // FIXME: handle signals
+ nanosleep(&ts1, &ts2);
+#elif LOVE_THREADS == LOVE_THREADS_WIN32
+ Sleep(ms);
+#elif LOVE_THREADS == LOVE_THREADS_SDL
+ SDL_Delay(ms);
+} // namespace love
@@ -0,0 +1,33 @@
+#ifndef DELAY_H_
+#define DELAY_H_
+#include <thread/threads.h>
+ void delay(unsigned int ms);
+}; // namespace love
+#endif /* DELAY_H_ */
@@ -0,0 +1,64 @@
+#ifndef LOVE_INT_H
+#define LOVE_INT_H
+#ifndef LOVE_WINDOWS
+#include <stdint.h>
+#define LOVE_INT8_MAX 0x7F
+#define LOVE_UINT8_MAX 0xFF
+#define LOVE_INT16_MAX 0x7FFF
+#define LOVE_UINT16_MAX 0xFFFF
+#define LOVE_INT32_MAX 0x7FFFFFFF
+#define LOVE_UINT32_MAX 0xFFFFFFFF
+#define LOVE_INT64_MAX 0x7FFFFFFFFFFFFFFF
+#define LOVE_UINT64_MAX 0xFFFFFFFFFFFFFFFF
+// Blame Microsoft
+#ifdef LOVE_WINDOWS
+ typedef __int8 int8;
+ typedef unsigned __int8 uint8;
+ typedef __int16 int16;
+ typedef unsigned __int16 uint16;
+ typedef __int32 int32;
+ typedef unsigned __int32 uint32;
+ typedef __int64 int64;
+ typedef unsigned __int64 uint64;
+#else
+ typedef int8_t int8;
+ typedef uint8_t uint8;
+ typedef int16_t int16;
+ typedef uint16_t uint16;
+ typedef int32_t int32;
+ typedef uint32_t uint32;
+ typedef int64_t int64;
+ typedef uint64_t uint64;
+#endif // LOVE_INT_H
@@ -1,84 +1,98 @@
-#ifndef LOVE_MATH_H
-#define LOVE_MATH_H
-#include <cstdlib> // for rand()
-/* Definitions of useful mathematical constants
- * M_E - e
- * M_LOG2E - log2(e)
- * M_LOG10E - log10(e)
- * M_LN2 - ln(2)
- * M_LN10 - ln(10)
- * M_PI - pi
- * M_PI_2 - pi/2
- * M_PI_4 - pi/4
- * M_1_PI - 1/pi
- * M_2_PI - 2/pi
- * M_2_SQRTPI - 2/sqrt(pi)
- * M_SQRT2 - sqrt(2)
- * M_SQRT1_2 - 1/sqrt(2)
- */
-#define LOVE_M_E 2.71828182845904523536
-#define LOVE_M_LOG2E 1.44269504088896340736
-#define LOVE_M_LOG10E 0.434294481903251827651
-#define LOVE_M_LN2 0.693147180559945309417
-#define LOVE_M_LN10 2.30258509299404568402
-#define LOVE_M_PI 3.14159265358979323846
-#define LOVE_M_PI_2 1.57079632679489661923
-#define LOVE_M_PI_4 0.785398163397448309616
-#define LOVE_M_1_PI 0.318309886183790671538
-#define LOVE_M_2_PI 0.636619772367581343076
-#define LOVE_M_2_SQRTPI 1.12837916709551257390
-#define LOVE_M_SQRT2 1.41421356237309504880
-#define LOVE_M_SQRT1_2 0.707106781186547524401
-#define LOVE_M_TORAD (float)(LOVE_M_PI/180.0)
-#define LOVE_M_TODEG (float)(180.0/LOVE_M_PI)
-#define LOVE_TORAD(x) (float)(x*LOVE_M_TORAD)
-#define LOVE_TODEG(x) (float)(x*LOVE_M_TODEG)
-struct vertex
- unsigned char r, g, b, a;
- float s, t;
-};
-template<typename T>
-inline T random()
- return T(rand()) / (T(RAND_MAX)+T(1));
-inline T random(T min, T max)
- return random<T>() * (max - min) + min;
-#endif // LOVE_MATH_H
+#ifndef LOVE_MATH_H
+#define LOVE_MATH_H
+#include <climits> // for CHAR_BIT
+#include <cstdlib> // for rand()
+/* Definitions of useful mathematical constants
+ * M_E - e
+ * M_LOG2E - log2(e)
+ * M_LOG10E - log10(e)
+ * M_LN2 - ln(2)
+ * M_LN10 - ln(10)
+ * M_PI - pi
+ * M_PI_2 - pi/2
+ * M_PI_4 - pi/4
+ * M_1_PI - 1/pi
+ * M_2_PI - 2/pi
+ * M_2_SQRTPI - 2/sqrt(pi)
+ * M_SQRT2 - sqrt(2)
+ * M_SQRT1_2 - 1/sqrt(2)
+ */
+#define LOVE_M_E 2.71828182845904523536
+#define LOVE_M_LOG2E 1.44269504088896340736
+#define LOVE_M_LOG10E 0.434294481903251827651
+#define LOVE_M_LN2 0.693147180559945309417
+#define LOVE_M_LN10 2.30258509299404568402
+#define LOVE_M_PI 3.14159265358979323846
+#define LOVE_M_PI_2 1.57079632679489661923
+#define LOVE_M_PI_4 0.785398163397448309616
+#define LOVE_M_1_PI 0.318309886183790671538
+#define LOVE_M_2_PI 0.636619772367581343076
+#define LOVE_M_2_SQRTPI 1.12837916709551257390
+#define LOVE_M_SQRT2 1.41421356237309504880
+#define LOVE_M_SQRT1_2 0.707106781186547524401
+#define LOVE_M_TORAD (float)(LOVE_M_PI/180.0)
+#define LOVE_M_TODEG (float)(180.0/LOVE_M_PI)
+#define LOVE_TORAD(x) (float)(x*LOVE_M_TORAD)
+#define LOVE_TODEG(x) (float)(x*LOVE_M_TODEG)
+struct vertex
+ unsigned char r, g, b, a;
+ float s, t;
+};
+inline int next_p2(int x)
+ x += (x == 0);
+ x--;
+ for (unsigned int i = 1; i < sizeof(int)*CHAR_BIT; i <<= 1) x |= x >> i;
+ return ++x;
+inline float next_p2(float x)
+ return static_cast<float>(next_p2(static_cast<int>(x)));
+template<typename T>
+inline T random()
+ return T(rand()) / (T(RAND_MAX)+T(1));
+inline T random(T min, T max)
+ return random<T>() * (max - min) + min;
+#endif // LOVE_MATH_H
@@ -1,432 +1,480 @@
-#include "runtime.h"
-#include "Module.h"
-#include "StringMap.h"
-#include <iostream>
-// SDL
-#include <SDL_mutex.h>
-#include <SDL_thread.h>
- static SDL_mutex *gcmutex = 0;
- void *_gcmutex = 0;
- unsigned int _gcthread = 0;
- * Called when an object is collected. The object is released
- * once in this function, possibly deleting it.
- static int w__gc(lua_State * L)
- if (!gcmutex)
- gcmutex = SDL_CreateMutex();
- _gcmutex = (void*) gcmutex;
- Proxy * p = (Proxy *)lua_touserdata(L, 1);
- Object * t = (Object *)p->data;
- if(p->own)
- SDL_mutexP(gcmutex);
- _gcthread = (unsigned int) SDL_ThreadID();
- t->release();
- SDL_mutexV(gcmutex);
- return 0;
- static int w__tostring(lua_State * L)
- lua_pushvalue(L, lua_upvalueindex(1));
- return 1;
- static int w__typeOf(lua_State * L)
- Type t = luax_type(L, 2);
- luax_pushboolean(L, p->flags[t]);
- Reference * luax_refif(lua_State * L, int type)
- Reference * r = 0;
- // Create a reference only if the test succeeds.
- if(lua_type(L, -1) == type)
- r = new Reference(L);
- else // Pop the value even if it fails (but also if it succeeds).
- lua_pop(L, 1);
- return r;
- void luax_printstack(lua_State * L)
- for(int i = 1;i<=lua_gettop(L);i++)
- std::cout << i << " - " << luaL_typename(L, i) << std::endl;
- bool luax_toboolean(lua_State * L, int idx)
- return (lua_toboolean(L, idx) != 0);
- void luax_pushboolean(lua_State * L, bool b)
- lua_pushboolean(L, b ? 1 : 0);
- bool luax_optboolean(lua_State * L, int idx, bool b)
- if(lua_isboolean(L, idx) == 1)
- return (lua_toboolean(L, idx) == 1 ? true : false);
- return b;
- int luax_assert_argc(lua_State * L, int min)
- int argc = lua_gettop(L);
- if( argc < min )
- return luaL_error(L, "Incorrect number of arguments. Got [%d], expected at least [%d]", argc, min);
- int luax_assert_argc(lua_State * L, int min, int max)
- if( argc < min || argc > max)
- return luaL_error(L, "Incorrect number of arguments. Got [%d], expected [%d-%d]", argc, min, max);
- int luax_assert_function(lua_State * L, int n)
- if(!lua_isfunction(L, n))
- return luaL_error(L, "Argument must be of type \"function\".");
- int luax_register_module(lua_State * L, const WrappedModule & m)
- // Put a reference to the C++ module in Lua.
- luax_getregistry(L, REGISTRY_MODULES);
- Proxy * p = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
- p->own = true;
- p->data = m.module;
- p->flags = m.flags;
- luaL_newmetatable(L, m.module->getName());
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
- lua_pushcfunction(L, w__gc);
- lua_setfield(L, -2, "__gc");
- lua_setmetatable(L, -2);
- lua_setfield(L, -2, m.name); // _modules[name] = proxy
- // Gets the love table.
- luax_insistglobal(L, "love");
- // Create new table for module.
- lua_newtable(L);
- // Register all the functions.
- luaL_register(L, 0, m.functions);
- // Register types.
- if(m.types != 0)
- for(const lua_CFunction * t = m.types; *t != 0; t++)
- (*t)(L);
- lua_setfield(L, -2, m.name); // love.graphics = table
- lua_pop(L, 1); // love
- int luax_preload(lua_State * L, lua_CFunction f, const char * name)
- lua_getglobal(L, "package");
- lua_getfield(L, -1, "preload");
- lua_pushcfunction(L, f);
- lua_setfield(L, -2, name);
- lua_pop(L, 2);
- int luax_register_type(lua_State * L, const char * tname, const luaL_Reg * f)
- luaL_newmetatable(L, tname);
- // m.__index = m
- // setup gc
- // Add tostring function.
- lua_pushstring(L, tname);
- lua_pushcclosure(L, w__tostring, 1);
- lua_setfield(L, -2, "__tostring");
- // Add tostring to as type() as well.
- lua_setfield(L, -2, "type");
- // Add typeOf
- lua_pushcfunction(L, w__typeOf);
- lua_setfield(L, -2, "typeOf");
- if(f != 0)
- luaL_register(L, 0, f);
- lua_pop(L, 1); // Pops metatable.
- int luax_register_searcher(lua_State * L, lua_CFunction f)
- // Add the package loader to the package.loaders table.
- if(lua_isnil(L, -1))
- return luaL_error(L, "Can't register searcher: package table does not exist.");
- lua_getfield(L, -1, "loaders");
- return luaL_error(L, "Can't register searcher: package.loaders table does not exist.");
- int len = lua_objlen(L, -1);
- lua_pushinteger(L, len+1);
- lua_settable(L, -3);
- void luax_newtype(lua_State * L, const char * name, bits flags, void * data, bool own)
- Proxy * u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
- u->data = data;
- u->flags = flags;
- u->own = own;
- luaL_newmetatable(L, name);
- bool luax_istype(lua_State * L, int idx, love::bits type)
- if(lua_isuserdata(L, idx) == 0)
- return false;
- return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type);
- int luax_getfunction(lua_State * L, const char * mod, const char * fn)
- lua_getglobal(L, "love");
- if(lua_isnil(L, -1)) return luaL_error(L, "Could not find global love!");
- lua_getfield(L, -1, mod);
- if(lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s!", mod);
- lua_getfield(L, -1, fn);
- if(lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s.%s!", mod, fn);
- lua_remove(L, -2); // remove mod
- lua_remove(L, -2); // remove fn
- int luax_convobj(lua_State * L, int idx, const char * mod, const char * fn)
- // Convert string to a file.
- luax_getfunction(L, mod, fn);
- lua_pushvalue(L, idx); // The initial argument.
- lua_call(L, 1, 1); // Call the function, one arg, one return value.
- lua_replace(L, idx); // Replace the initial argument with the new object.
- int luax_convobj(lua_State * L, int idxs[], int n, const char * mod, const char * fn)
- for (int i = 0; i < n; i++) {
- lua_pushvalue(L, idxs[i]); // The arguments.
- lua_call(L, n, 1); // Call the function, n args, one return value.
- lua_replace(L, idxs[0]); // Replace the initial argument with the new object.
- int luax_strtofile(lua_State * L, int idx)
- return luax_convobj(L, idx, "filesystem", "newFile");
- int luax_filetodata(lua_State * L, int idx)
- return luax_convobj(L, idx, "filesystem", "read");
- int luax_insist(lua_State * L, int idx, const char * k)
- lua_getfield(L, idx, k);
- // Create if necessary.
- if(!lua_istable(L, -1))
- lua_pop(L, 1); // Pop the non-table.
- lua_pushvalue(L, -1); // Duplicate the table to leave on top.
- lua_setfield(L, -3, k); // k[idx] = table
- int luax_insistglobal(lua_State * L, const char * k)
- lua_getglobal(L, k);
- lua_setglobal(L, k);
- int luax_insistlove(lua_State * L, const char * k)
- luax_insist(L, -1, k);
- // The love table should be replaced with the top stack
- // item. Only the reqested table should remain on the stack.
- lua_replace(L, -2);
- int luax_getregistry(lua_State * L, Registry r)
- switch(r)
- case REGISTRY_GC:
- return luax_insistlove(L, "_gc");
- case REGISTRY_MODULES:
- return luax_insistlove(L, "_modules");
- default:
- return luaL_error(L, "Attempted to use invalid registry.");
- StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
- {"Invalid", INVALID_ID},
- {"Object", OBJECT_ID},
- {"Data", DATA_ID},
- {"Module", MODULE_ID},
- // Filesystem
- {"File", FILESYSTEM_FILE_ID},
- {"FileData", FILESYSTEM_FILE_DATA_ID},
- // Font
- {"GlyphData", FONT_GLYPH_DATA_ID},
- {"Rasterizer", FONT_RASTERIZER_ID},
- // Graphics
- {"Drawable", GRAPHICS_DRAWABLE_ID},
- {"Image", GRAPHICS_IMAGE_ID},
- {"Quad", GRAPHICS_QUAD_ID},
- {"Glyph", GRAPHICS_GLYPH_ID},
- {"Font", GRAPHICS_FONT_ID},
- {"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
- {"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},
- {"VertexBuffer", GRAPHICS_VERTEX_BUFFER_ID},
- // Image
- {"ImageData", IMAGE_IMAGE_DATA_ID},
- // Audio
- {"Source", AUDIO_SOURCE_ID},
- // Sound
- {"SoundData", SOUND_SOUND_DATA_ID},
- {"Decoder", SOUND_DECODER_ID},
- // Physics
- {"World", PHYSICS_WORLD_ID},
- {"Contact", PHYSICS_CONTACT_ID},
- {"Body", PHYSICS_BODY_ID},
- {"Shape", PHYSICS_SHAPE_ID},
- {"CircleShape", PHYSICS_CIRCLE_SHAPE_ID},
- {"PolygonShape", PHYSICS_POLYGON_SHAPE_ID},
- {"Joint", PHYSICS_JOINT_ID},
- {"MouseJoint", PHYSICS_MOUSE_JOINT_ID},
- {"DistanceJoint", PHYSICS_DISTANCE_JOINT_ID},
- {"PrismaticJoint", PHYSICS_PRISMATIC_JOINT_ID},
- {"RevoluteJoint", PHYSICS_REVOLUTE_JOINT_ID},
- {"PulleyJoint", PHYSICS_PULLEY_JOINT_ID},
- {"GearJoint", PHYSICS_GEAR_JOINT_ID},
- // Thread
- {"Thread", THREAD_THREAD_ID},
- // The modules themselves. Only add abstracted modules here.
- {"filesystem", MODULE_FILESYSTEM_ID},
- {"image", MODULE_IMAGE_ID},
- {"sound", MODULE_SOUND_ID},
- StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries));
- Type luax_type(lua_State * L, int idx)
- Type t = INVALID_ID;
- types.find(luaL_checkstring(L, idx), t);
+#include "runtime.h"
+#include "Module.h"
+#include "StringMap.h"
+ static thread::Mutex *gcmutex = 0;
+ void *_gcmutex = 0;
+ unsigned int _gcthread = 0;
+ * Called when an object is collected. The object is released
+ * once in this function, possibly deleting it.
+ static int w__gc(lua_State * L)
+ if (!gcmutex)
+ gcmutex = new thread::Mutex();
+ _gcmutex = (void*) gcmutex;
+ Proxy * p = (Proxy *)lua_touserdata(L, 1);
+ Object * t = (Object *)p->data;
+ if (p->own)
+ thread::Lock lock(gcmutex);
+ _gcthread = thread::ThreadBase::threadId();
+ t->release();
+ return 0;
+ static int w__tostring(lua_State * L)
+ lua_pushvalue(L, lua_upvalueindex(1));
+ return 1;
+ static int w__typeOf(lua_State * L)
+ Type t = luax_type(L, 2);
+ luax_pushboolean(L, p->flags[t]);
+ static int w__eq(lua_State * L)
+ Proxy * p1 = (Proxy *)lua_touserdata(L, 1);
+ Proxy * p2 = (Proxy *)lua_touserdata(L, 2);
+ luax_pushboolean(L, p1->data == p2->data);
+ Reference * luax_refif(lua_State * L, int type)
+ Reference * r = 0;
+ // Create a reference only if the test succeeds.
+ if (lua_type(L, -1) == type)
+ r = new Reference(L);
+ else // Pop the value even if it fails (but also if it succeeds).
+ return r;
+ void luax_printstack(lua_State * L)
+ for (int i = 1;i<=lua_gettop(L);i++)
+ std::cout << i << " - " << luaL_typename(L, i) << std::endl;
+ bool luax_toboolean(lua_State * L, int idx)
+ return (lua_toboolean(L, idx) != 0);
+ void luax_pushboolean(lua_State * L, bool b)
+ lua_pushboolean(L, b ? 1 : 0);
+ bool luax_optboolean(lua_State * L, int idx, bool b)
+ if (lua_isboolean(L, idx) == 1)
+ return (lua_toboolean(L, idx) == 1 ? true : false);
+ return b;
+ std::string luax_checkstring(lua_State * L, int idx)
+ const char * str = luaL_checklstring(L, idx, &len);
+ return std::string(str, len);
+ void luax_pushstring(lua_State * L, std::string str)
+ lua_pushlstring(L, str.data(), str.size());
+ int luax_assert_argc(lua_State * L, int min)
+ int argc = lua_gettop(L);
+ if ( argc < min )
+ return luaL_error(L, "Incorrect number of arguments. Got [%d], expected at least [%d]", argc, min);
+ int luax_assert_argc(lua_State * L, int min, int max)
+ if ( argc < min || argc > max)
+ return luaL_error(L, "Incorrect number of arguments. Got [%d], expected [%d-%d]", argc, min, max);
+ int luax_assert_function(lua_State * L, int n)
+ if (!lua_isfunction(L, n))
+ return luaL_error(L, "Argument must be of type \"function\".");
+ int luax_register_module(lua_State * L, const WrappedModule & m)
+ // Put a reference to the C++ module in Lua.
+ luax_getregistry(L, REGISTRY_MODULES);
+ Proxy * p = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
+ p->own = true;
+ p->data = m.module;
+ p->flags = m.flags;
+ luaL_newmetatable(L, m.module->getName());
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ lua_pushcfunction(L, w__gc);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+ lua_setfield(L, -2, m.name); // _modules[name] = proxy
+ // Gets the love table.
+ luax_insistglobal(L, "love");
+ // Create new table for module.
+ lua_newtable(L);
+ // Register all the functions.
+ luaL_register(L, 0, m.functions);
+ // Register types.
+ if (m.types != 0)
+ for (const lua_CFunction * t = m.types; *t != 0; t++)
+ (*t)(L);
+ lua_setfield(L, -3, m.name); // love.graphics = table
+ lua_remove(L, -2); // love
+ int luax_preload(lua_State * L, lua_CFunction f, const char * name)
+ lua_getglobal(L, "package");
+ lua_getfield(L, -1, "preload");
+ lua_pushcfunction(L, f);
+ lua_setfield(L, -2, name);
+ lua_pop(L, 2);
+ int luax_register_type(lua_State * L, const char * tname, const luaL_Reg * f)
+ luaL_newmetatable(L, tname);
+ // m.__index = m
+ // setup gc
+ // Add equality
+ lua_pushcfunction(L, w__eq);
+ lua_setfield(L, -2, "__eq");
+ // Add tostring function.
+ lua_pushstring(L, tname);
+ lua_pushcclosure(L, w__tostring, 1);
+ lua_setfield(L, -2, "__tostring");
+ // Add tostring to as type() as well.
+ lua_setfield(L, -2, "type");
+ // Add typeOf
+ lua_pushcfunction(L, w__typeOf);
+ lua_setfield(L, -2, "typeOf");
+ if (f != 0)
+ luaL_register(L, 0, f);
+ lua_pop(L, 1); // Pops metatable.
+ int luax_table_insert(lua_State * L, int tindex, int vindex, int pos)
+ if (tindex < 0)
+ tindex = lua_gettop(L)+1+tindex;
+ if (vindex < 0)
+ vindex = lua_gettop(L)+1+vindex;
+ if (pos == -1)
+ lua_pushvalue(L, vindex);
+ lua_rawseti(L, tindex, lua_objlen(L, tindex)+1);
+ else if (pos < 0)
+ pos = lua_objlen(L, tindex)+1+pos;
+ for (int i = lua_objlen(L, tindex)+1; i > pos; i--)
+ lua_rawgeti(L, tindex, i-1);
+ lua_rawseti(L, tindex, i);
+ lua_rawseti(L, tindex, pos);
+ int luax_register_searcher(lua_State * L, lua_CFunction f, int pos)
+ // Add the package loader to the package.loaders table.
+ if (lua_isnil(L, -1))
+ return luaL_error(L, "Can't register searcher: package table does not exist.");
+ lua_getfield(L, -1, "loaders");
+ return luaL_error(L, "Can't register searcher: package.loaders table does not exist.");
+ luax_table_insert(L, -2, -1, pos);
+ lua_pop(L, 3);
+ void luax_newtype(lua_State * L, const char * name, bits flags, void * data, bool own)
+ Proxy * u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
+ u->data = data;
+ u->flags = flags;
+ u->own = own;
+ luaL_newmetatable(L, name);
+ bool luax_istype(lua_State * L, int idx, love::bits type)
+ if (lua_isuserdata(L, idx) == 0)
+ return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type);
+ int luax_getfunction(lua_State * L, const char * mod, const char * fn)
+ lua_getglobal(L, "love");
+ if (lua_isnil(L, -1)) return luaL_error(L, "Could not find global love!");
+ lua_getfield(L, -1, mod);
+ if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s!", mod);
+ lua_getfield(L, -1, fn);
+ if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s.%s!", mod, fn);
+ lua_remove(L, -2); // remove mod
+ lua_remove(L, -2); // remove fn
+ int luax_convobj(lua_State * L, int idx, const char * mod, const char * fn)
+ // Convert string to a file.
+ luax_getfunction(L, mod, fn);
+ lua_pushvalue(L, idx); // The initial argument.
+ lua_call(L, 1, 1); // Call the function, one arg, one return value.
+ lua_replace(L, idx); // Replace the initial argument with the new object.
+ int luax_convobj(lua_State * L, int idxs[], int n, const char * mod, const char * fn)
+ for (int i = 0; i < n; i++)
+ lua_pushvalue(L, idxs[i]); // The arguments.
+ lua_call(L, n, 1); // Call the function, n args, one return value.
+ lua_replace(L, idxs[0]); // Replace the initial argument with the new object.
+ int luax_strtofile(lua_State * L, int idx)
+ return luax_convobj(L, idx, "filesystem", "newFile");
+ int luax_filetodata(lua_State * L, int idx)
+ return luax_convobj(L, idx, "filesystem", "read");
+ int luax_insist(lua_State * L, int idx, const char * k)
+ // Convert to absolute index if necessary.
+ if (idx < 0 && idx > LUA_REGISTRYINDEX)
+ idx = lua_gettop(L) + ++idx;
+ lua_getfield(L, idx, k);
+ // Create if necessary.
+ if (!lua_istable(L, -1))
+ lua_pop(L, 1); // Pop the non-table.
+ lua_pushvalue(L, -1); // Duplicate the table to leave on top.
+ lua_setfield(L, idx, k); // lua_stack[idx][k] = lua_stack[-1] (table)
+ int luax_insistglobal(lua_State * L, const char * k)
+ lua_getglobal(L, k);
+ lua_setglobal(L, k);
+ int luax_insistlove(lua_State * L, const char * k)
+ luax_insist(L, -1, k);
+ // The love table should be replaced with the top stack
+ // item. Only the reqested table should remain on the stack.
+ lua_replace(L, -2);
+ int luax_getregistry(lua_State * L, Registry r)
+ switch(r)
+ case REGISTRY_GC:
+ return luax_insistlove(L, "_gc");
+ case REGISTRY_MODULES:
+ return luax_insistlove(L, "_modules");
+ return luaL_error(L, "Attempted to use invalid registry.");
+ StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
+ {"Invalid", INVALID_ID},
+ {"Object", OBJECT_ID},
+ {"Data", DATA_ID},
+ {"Module", MODULE_ID},
+ // Filesystem
+ {"File", FILESYSTEM_FILE_ID},
+ {"FileData", FILESYSTEM_FILE_DATA_ID},
+ // Font
+ {"GlyphData", FONT_GLYPH_DATA_ID},
+ {"Rasterizer", FONT_RASTERIZER_ID},
+ // Graphics
+ {"Drawable", GRAPHICS_DRAWABLE_ID},
+ {"Image", GRAPHICS_IMAGE_ID},
+ {"Quad", GRAPHICS_QUAD_ID},
+ {"Font", GRAPHICS_FONT_ID},
+ {"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
+ {"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},
+ {"Canvas", GRAPHICS_CANVAS_ID},
+ // Image
+ {"ImageData", IMAGE_IMAGE_DATA_ID},
+ // Audio
+ {"Source", AUDIO_SOURCE_ID},
+ // Sound
+ {"SoundData", SOUND_SOUND_DATA_ID},
+ {"Decoder", SOUND_DECODER_ID},
+ // Physics
+ {"World", PHYSICS_WORLD_ID},
+ {"Contact", PHYSICS_CONTACT_ID},
+ {"Body", PHYSICS_BODY_ID},
+ {"Shape", PHYSICS_SHAPE_ID},
+ {"CircleShape", PHYSICS_CIRCLE_SHAPE_ID},
+ {"PolygonShape", PHYSICS_POLYGON_SHAPE_ID},
+ {"Joint", PHYSICS_JOINT_ID},
+ {"MouseJoint", PHYSICS_MOUSE_JOINT_ID},
+ {"DistanceJoint", PHYSICS_DISTANCE_JOINT_ID},
+ {"PrismaticJoint", PHYSICS_PRISMATIC_JOINT_ID},
+ {"RevoluteJoint", PHYSICS_REVOLUTE_JOINT_ID},
+ {"PulleyJoint", PHYSICS_PULLEY_JOINT_ID},
+ {"GearJoint", PHYSICS_GEAR_JOINT_ID},
+ // Thread
+ {"Thread", THREAD_THREAD_ID},
+ // The modules themselves. Only add abstracted modules here.
+ {"filesystem", MODULE_FILESYSTEM_ID},
+ {"image", MODULE_IMAGE_ID},
+ {"sound", MODULE_SOUND_ID},
+ StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries));
+ Type luax_type(lua_State * L, int idx)
+ types.find(luaL_checkstring(L, idx), t);
@@ -109,7 +109,7 @@ namespace love
* Converts the value at idx to a bool. It follow the same rules
* as lua_toboolean, but returns a bool instead of an int.
* @param L The Lua state.
- * @param idx The index on the Lua state.
+ * @param idx The index on the Lua stack.
* @return True if the value evaluates to true, false otherwise.
bool luax_toboolean(lua_State * L, int idx);
@@ -118,19 +118,36 @@ namespace love
* Pushes a bool onto the stack. It's the same as lua_pushboolean,
* but with bool instead of int.
- * @paarm b The bool to push.
+ * @param b The bool to push.
void luax_pushboolean(lua_State * L, bool b);
* Converts the value at idx to a bool, or if not present, b is returned.
- * @param idx The index of the Lua state.
+ * @param idx The index of the Lua stack.
* @param b The value to return if no value exist at the specified index.
bool luax_optboolean(lua_State * L, int idx, bool b);
+ * Converts the value at idx to a std::string. It takes care of the string
+ * size and possible embedded nulls.
+ * @param L The Lua state.
+ * @return Copy of the string at the specified index.
+ std::string luax_checkstring(lua_State * L, int idx);
+ * Pushes a std::string onto the stack. It uses the length of the string
+ * for lua_pushlstring's len argument.
+ * @param str The string to push.
+ void luax_pushstring(lua_State * L, std::string str);
* Require at least 'min' number of items on the stack.
@@ -176,13 +193,23 @@ namespace love
int luax_register_type(lua_State * L, const char * tname, const luaL_Reg * f = 0);
+ * Do a table.insert from C
+ * @param L the state
+ * @param tindex the stack index of the table
+ * @param vindex the stack index of the value
+ * @param pos the position to insert it in
+ int luax_table_insert(lua_State * L, int tindex, int vindex, int pos = -1);
* Register a new searcher function for package.loaders. This can for instance enable
* loading of files through love.filesystem using standard require.
* @param f The searcher function.
+ * @param pos The position to insert the loader in.
- int luax_register_searcher(lua_State * L, lua_CFunction f);
+ int luax_register_searcher(lua_State * L, lua_CFunction f, int pos = -1);
* Creates a new Lua-accessible object of the given type, and put it on the stack.
@@ -273,6 +300,28 @@ namespace love
Type luax_type(lua_State * L, int idx);
+ * Convert the value at the specified index to an Lua number, and then
+ * convert to a float.
+ * @param idx The index on the stack.
+ inline float luax_tofloat(lua_State *L, int idx)
+ return static_cast<float>(lua_tonumber(L, idx));
+ * Like luax_tofloat, but checks that the value is a number.
+ * @see luax_tofloat
+ inline float luax_checkfloat(lua_State *L, int idx)
+ return static_cast<float>(luaL_checknumber(L, idx));
* Converts the value at idx to the specified type without checking that
* this conversion is valid. If the type has been previously verified with
@@ -299,12 +348,12 @@ namespace love
template <typename T>
T * luax_checktype(lua_State * L, int idx, const char * name, love::bits type)
luaL_error(L, "Incorrect parameter type: expected userdata.");
Proxy * u = (Proxy *)lua_touserdata(L, idx);
- if((u->flags & type) != type)
+ if ((u->flags & type) != type)
luaL_error(L, "Incorrect parameter type: expected %s", name);
return (T *)u->data;
@@ -316,12 +365,12 @@ namespace love
luax_getregistry(L, REGISTRY_MODULES);
lua_getfield(L, -1, k);
- if(!lua_isuserdata(L, -1))
+ if (!lua_isuserdata(L, -1))
luaL_error(L, "Tried to get nonexisting module %s.", k);
Proxy * u = (Proxy *)lua_touserdata(L, -1);
luaL_error(L, "Incorrect module %s", k);
lua_pop(L, 2);
@@ -1,161 +1,173 @@
-#ifndef LOVE_TYPES_H
-#define LOVE_TYPES_H
-#include <bitset>
- enum Type
- INVALID_ID = 0,
- // Cross-module types.
- OBJECT_ID,
- DATA_ID,
- MODULE_ID,
- // Filesystem.
- FILESYSTEM_FILE_ID,
- FILESYSTEM_FILE_DATA_ID,
- FONT_FONT_DATA_ID,
- FONT_GLYPH_DATA_ID,
- FONT_RASTERIZER_ID,
- GRAPHICS_DRAWABLE_ID,
- GRAPHICS_IMAGE_ID,
- GRAPHICS_QUAD_ID,
- GRAPHICS_GLYPH_ID,
- GRAPHICS_FONT_ID,
- GRAPHICS_PARTICLE_SYSTEM_ID,
- GRAPHICS_SPRITE_BATCH_ID,
- GRAPHICS_VERTEX_BUFFER_ID,
- GRAPHICS_FRAMEBUFFER_ID,
- IMAGE_IMAGE_DATA_ID,
- IMAGE_ENCODED_IMAGE_DATA_ID,
- AUDIO_SOURCE_ID,
- SOUND_SOUND_DATA_ID,
- SOUND_DECODER_ID,
- PHYSICS_WORLD_ID,
- PHYSICS_CONTACT_ID,
- PHYSICS_BODY_ID,
- PHYSICS_SHAPE_ID,
- PHYSICS_CIRCLE_SHAPE_ID,
- PHYSICS_POLYGON_SHAPE_ID,
- PHYSICS_JOINT_ID,
- PHYSICS_MOUSE_JOINT_ID,
- PHYSICS_DISTANCE_JOINT_ID,
- PHYSICS_PRISMATIC_JOINT_ID,
- PHYSICS_REVOLUTE_JOINT_ID,
- PHYSICS_PULLEY_JOINT_ID,
- PHYSICS_GEAR_JOINT_ID,
- THREAD_THREAD_ID,
- MODULE_FILESYSTEM_ID,
- MODULE_IMAGE_ID,
- MODULE_SOUND_ID,
- // Count the number of bits needed.
- TYPE_MAX_ENUM
- typedef std::bitset<TYPE_MAX_ENUM> bits;
- const bits INVALID_T = bits(1) << INVALID_ID;
- const bits OBJECT_T = bits(1) << OBJECT_ID;
- const bits DATA_T = (bits(1) << DATA_ID) | OBJECT_T;
- const bits MODULE_T = (bits(1) << MODULE_ID) | OBJECT_T;
- const bits FILESYSTEM_FILE_T = (bits(1) << FILESYSTEM_FILE_ID) | OBJECT_T;
- const bits FILESYSTEM_FILE_DATA_T = (bits(1) << FILESYSTEM_FILE_DATA_ID) | DATA_T;
- const bits FONT_FONT_DATA_T = (bits(1) << FONT_FONT_DATA_ID) | DATA_T;
- const bits FONT_GLYPH_DATA_T = (bits(1) << FONT_GLYPH_DATA_ID) | DATA_T;
- const bits FONT_RASTERIZER_T = (bits(1) << FONT_RASTERIZER_ID) | OBJECT_T;
- // Graphics.
- const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_ID) | OBJECT_T;
- const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_DRAWABLE_T;
- const bits GRAPHICS_QUAD_T = (bits(1) << GRAPHICS_QUAD_ID) | OBJECT_T;
- const bits GRAPHICS_GLYPH_T = (bits(1) << GRAPHICS_GLYPH_ID) | GRAPHICS_DRAWABLE_T;
- const bits GRAPHICS_FONT_T = (bits(1) << GRAPHICS_FONT_ID) | OBJECT_T;
- const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T;
- const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T;
- const bits GRAPHICS_VERTEX_BUFFER_T = (bits(1) << GRAPHICS_VERTEX_BUFFER_ID) | GRAPHICS_DRAWABLE_T;
- const bits GRAPHICS_FRAMEBUFFER_T = (bits(1) << GRAPHICS_FRAMEBUFFER_ID) | GRAPHICS_DRAWABLE_T;
- // Image.
- const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
- const bits IMAGE_ENCODED_IMAGE_DATA_T = (bits(1) << IMAGE_ENCODED_IMAGE_DATA_ID) | DATA_T;
- // Audio.
- const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
- // Sound.
- const bits SOUND_SOUND_DATA_T = (bits(1) << SOUND_SOUND_DATA_ID) | DATA_T;
- const bits SOUND_DECODER_T = bits(1) << SOUND_DECODER_ID;
- // Physics.
- const bits PHYSICS_WORLD_T = (bits(1) << PHYSICS_WORLD_ID) | OBJECT_T;
- const bits PHYSICS_CONTACT_T = (bits(1) << PHYSICS_CONTACT_ID) | OBJECT_T;
- const bits PHYSICS_BODY_T = (bits(1) << PHYSICS_BODY_ID) | OBJECT_T;
- const bits PHYSICS_SHAPE_T = (bits(1) << PHYSICS_SHAPE_ID) | OBJECT_T;
- const bits PHYSICS_CIRCLE_SHAPE_T = (bits(1) << PHYSICS_CIRCLE_SHAPE_ID) | PHYSICS_SHAPE_T;
- const bits PHYSICS_POLYGON_SHAPE_T = (bits(1) << PHYSICS_POLYGON_SHAPE_ID) | PHYSICS_SHAPE_T;
- const bits PHYSICS_JOINT_T = (bits(1) << PHYSICS_JOINT_ID) | OBJECT_T;
- const bits PHYSICS_MOUSE_JOINT_T = (bits(1) << PHYSICS_MOUSE_JOINT_ID) | PHYSICS_JOINT_T;
- const bits PHYSICS_DISTANCE_JOINT_T = (bits(1) << PHYSICS_DISTANCE_JOINT_ID) | PHYSICS_JOINT_T;
- const bits PHYSICS_PRISMATIC_JOINT_T = (bits(1) << PHYSICS_PRISMATIC_JOINT_ID) | PHYSICS_JOINT_T;
- const bits PHYSICS_REVOLUTE_JOINT_T = (bits(1) << PHYSICS_REVOLUTE_JOINT_ID) | PHYSICS_JOINT_T;
- const bits PHYSICS_PULLEY_JOINT_T = (bits(1) << PHYSICS_PULLEY_JOINT_ID) | PHYSICS_JOINT_T;
- const bits PHYSICS_GEAR_JOINT_T = (bits(1) << PHYSICS_GEAR_JOINT_ID) | PHYSICS_JOINT_T;
- // Thread.
- const bits THREAD_THREAD_T = (bits(1) << THREAD_THREAD_ID) | OBJECT_T;
- // Modules.
- const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;
- const bits MODULE_IMAGE_T = (bits(1) << MODULE_IMAGE_ID) | MODULE_T;
- const bits MODULE_SOUND_T = (bits(1) << MODULE_SOUND_ID) | MODULE_T;
- bool getType(const char * in, Type & out);
- bool getType(Type in, const char *& out);
-#endif // LOVE_TYPES_H
+#ifndef LOVE_TYPES_H
+#define LOVE_TYPES_H
+#include <bitset>
+ INVALID_ID = 0,
+ // Cross-module types.
+ OBJECT_ID,
+ DATA_ID,
+ MODULE_ID,
+ // Filesystem.
+ FILESYSTEM_FILE_ID,
+ FILESYSTEM_FILE_DATA_ID,
+ FONT_GLYPH_DATA_ID,
+ FONT_RASTERIZER_ID,
+ GRAPHICS_DRAWABLE_ID,
+ GRAPHICS_DRAWQABLE_ID,
+ GRAPHICS_IMAGE_ID,
+ GRAPHICS_QUAD_ID,
+ GRAPHICS_FONT_ID,
+ GRAPHICS_PARTICLE_SYSTEM_ID,
+ GRAPHICS_SPRITE_BATCH_ID,
+ GRAPHICS_CANVAS_ID,
+ GRAPHICS_PIXELEFFECT_ID,
+ IMAGE_IMAGE_DATA_ID,
+ IMAGE_ENCODED_IMAGE_DATA_ID,
+ AUDIO_SOURCE_ID,
+ SOUND_SOUND_DATA_ID,
+ SOUND_DECODER_ID,
+ PHYSICS_WORLD_ID,
+ PHYSICS_CONTACT_ID,
+ PHYSICS_BODY_ID,
+ PHYSICS_FIXTURE_ID,
+ PHYSICS_SHAPE_ID,
+ PHYSICS_CIRCLE_SHAPE_ID,
+ PHYSICS_POLYGON_SHAPE_ID,
+ PHYSICS_EDGE_SHAPE_ID,
+ PHYSICS_CHAIN_SHAPE_ID,
+ PHYSICS_JOINT_ID,
+ PHYSICS_MOUSE_JOINT_ID,
+ PHYSICS_DISTANCE_JOINT_ID,
+ PHYSICS_PRISMATIC_JOINT_ID,
+ PHYSICS_REVOLUTE_JOINT_ID,
+ PHYSICS_PULLEY_JOINT_ID,
+ PHYSICS_GEAR_JOINT_ID,
+ PHYSICS_FRICTION_JOINT_ID,
+ PHYSICS_WELD_JOINT_ID,
+ PHYSICS_ROPE_JOINT_ID,
+ PHYSICS_WHEEL_JOINT_ID,
+ THREAD_THREAD_ID,
+ MODULE_FILESYSTEM_ID,
+ MODULE_IMAGE_ID,
+ MODULE_SOUND_ID,
+ // Count the number of bits needed.
+ TYPE_MAX_ENUM
+ typedef std::bitset<TYPE_MAX_ENUM> bits;
+ const bits INVALID_T = bits(1) << INVALID_ID;
+ const bits OBJECT_T = bits(1) << OBJECT_ID;
+ const bits DATA_T = (bits(1) << DATA_ID) | OBJECT_T;
+ const bits MODULE_T = (bits(1) << MODULE_ID) | OBJECT_T;
+ const bits FILESYSTEM_FILE_T = (bits(1) << FILESYSTEM_FILE_ID) | OBJECT_T;
+ const bits FILESYSTEM_FILE_DATA_T = (bits(1) << FILESYSTEM_FILE_DATA_ID) | DATA_T;
+ const bits FONT_GLYPH_DATA_T = (bits(1) << FONT_GLYPH_DATA_ID) | DATA_T;
+ const bits FONT_RASTERIZER_T = (bits(1) << FONT_RASTERIZER_ID) | OBJECT_T;
+ // Graphics.
+ const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_ID) | OBJECT_T;
+ const bits GRAPHICS_DRAWQABLE_T = (bits(1) << GRAPHICS_DRAWQABLE_ID) | GRAPHICS_DRAWABLE_T;
+ const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_DRAWQABLE_T;
+ const bits GRAPHICS_QUAD_T = (bits(1) << GRAPHICS_QUAD_ID) | OBJECT_T;
+ const bits GRAPHICS_FONT_T = (bits(1) << GRAPHICS_FONT_ID) | OBJECT_T;
+ const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T;
+ const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T;
+ const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWQABLE_T;
+ const bits GRAPHICS_PIXELEFFECT_T = (bits(1) << GRAPHICS_PIXELEFFECT_ID) | OBJECT_T;
+ // Image.
+ const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
+ const bits IMAGE_ENCODED_IMAGE_DATA_T = (bits(1) << IMAGE_ENCODED_IMAGE_DATA_ID) | DATA_T;
+ // Audio.
+ const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
+ // Sound.
+ const bits SOUND_SOUND_DATA_T = (bits(1) << SOUND_SOUND_DATA_ID) | DATA_T;
+ const bits SOUND_DECODER_T = bits(1) << SOUND_DECODER_ID;
+ // Physics.
+ const bits PHYSICS_WORLD_T = (bits(1) << PHYSICS_WORLD_ID) | OBJECT_T;
+ const bits PHYSICS_CONTACT_T = (bits(1) << PHYSICS_CONTACT_ID) | OBJECT_T;
+ const bits PHYSICS_BODY_T = (bits(1) << PHYSICS_BODY_ID) | OBJECT_T;
+ const bits PHYSICS_FIXTURE_T = (bits(1) << PHYSICS_FIXTURE_ID) | OBJECT_T;
+ const bits PHYSICS_SHAPE_T = (bits(1) << PHYSICS_SHAPE_ID) | OBJECT_T;
+ const bits PHYSICS_CIRCLE_SHAPE_T = (bits(1) << PHYSICS_CIRCLE_SHAPE_ID) | PHYSICS_SHAPE_T;
+ const bits PHYSICS_POLYGON_SHAPE_T = (bits(1) << PHYSICS_POLYGON_SHAPE_ID) | PHYSICS_SHAPE_T;
+ const bits PHYSICS_EDGE_SHAPE_T = (bits(1) << PHYSICS_EDGE_SHAPE_ID) | PHYSICS_SHAPE_T;
+ const bits PHYSICS_CHAIN_SHAPE_T = (bits(1) << PHYSICS_CHAIN_SHAPE_ID) | PHYSICS_SHAPE_T;
+ const bits PHYSICS_JOINT_T = (bits(1) << PHYSICS_JOINT_ID) | OBJECT_T;
+ const bits PHYSICS_MOUSE_JOINT_T = (bits(1) << PHYSICS_MOUSE_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_DISTANCE_JOINT_T = (bits(1) << PHYSICS_DISTANCE_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_PRISMATIC_JOINT_T = (bits(1) << PHYSICS_PRISMATIC_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_REVOLUTE_JOINT_T = (bits(1) << PHYSICS_REVOLUTE_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_PULLEY_JOINT_T = (bits(1) << PHYSICS_PULLEY_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_GEAR_JOINT_T = (bits(1) << PHYSICS_GEAR_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_FRICTION_JOINT_T = (bits(1) << PHYSICS_FRICTION_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_WELD_JOINT_T = (bits(1) << PHYSICS_WELD_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_ROPE_JOINT_T = (bits(1) << PHYSICS_ROPE_JOINT_ID) | PHYSICS_JOINT_T;
+ const bits PHYSICS_WHEEL_JOINT_T = (bits(1) << PHYSICS_WHEEL_JOINT_ID) | PHYSICS_JOINT_T;
+ // Thread.
+ const bits THREAD_THREAD_T = (bits(1) << THREAD_THREAD_ID) | OBJECT_T;
+ // Modules.
+ const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;
+ const bits MODULE_IMAGE_T = (bits(1) << MODULE_IMAGE_ID) | MODULE_T;
+ const bits MODULE_SOUND_T = (bits(1) << MODULE_SOUND_ID) | MODULE_T;
+ bool getType(const char * in, Type & out);
+ bool getType(Type in, const char *& out);
+#endif // LOVE_TYPES_H
@@ -36,25 +36,25 @@ namespace love
// Convert to UTF-8.
int ok = WideCharToMultiByte(CP_UTF8, 0, wstr, wide_len, utf8_str, utf8_size, 0, 0);
- if(!ok)
- delete [] utf8_str;
+ std::string ret;
+ if (ok)
+ ret = utf8_str;
- return ok ? std::string(utf8_str) : std::string();
+ delete utf8_str;
+ return ret;
void replace_char(std::string & str, char find, char replace)
int length = str.length();
- for(int i = 0; i<length; i++)
+ for (int i = 0; i<length; i++)
- if(str[i] == find)
+ if (str[i] == find)
str[i] = replace;
-#endif // LOVE_WINDOWS
+#endif // LOVE_WINDOWS
@@ -25,12 +25,11 @@ namespace love
// Version stuff.
const int VERSION_MAJOR = 0;
- const int VERSION_MINOR = 7;
- const int VERSION_REV = 1;
- const int VERSION = VERSION_MAJOR*100 + VERSION_MINOR*10 + VERSION_REV;
- const int VERSION_COMPATIBILITY[] = { VERSION, 070, 0 };
- const char * VERSION_STR = "0.7.1";
- const char * VERSION_CODENAME = "Game Slave";
+ const int VERSION_MINOR = 8;
+ const int VERSION_REV = 0;
+ const char * VERSION = "0.8.0";
+ const char * VERSION_COMPATIBILITY[] = { VERSION, 0 };
+ const char * VERSION_CODENAME = "Rubber Piggy";
@@ -52,5 +52,5 @@ namespace love
luax_register_type(L, "Data", w_Data_functions);
return 0;
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*/
+#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 <Box2D/Common/b2Settings.h>
+#include <Box2D/Common/b2Draw.h>
+#include <Box2D/Common/b2Timer.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>
+#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
@@ -0,0 +1,171 @@
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+#include <new>
+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);
+ 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(count >= 2);
+ m_count = count;
+ m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
+ memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
+ m_hasPrevVertex = false;
+ m_hasNextVertex = false;
+void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
+ m_prevVertex = prevVertex;
+void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
+ m_nextVertex = nextVertex;
+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;
+ 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;
+ 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);
+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
+ 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;
@@ -0,0 +1,102 @@
+#ifndef B2_CHAIN_SHAPE_H
+#define B2_CHAIN_SHAPE_H
+#include <Box2D/Collision/Shapes/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.
+ 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.
+ 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_hasPrevVertex = NULL;
+ m_hasNextVertex = NULL;
@@ -0,0 +1,100 @@
+b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
+ void* mem = allocator->Allocate(sizeof(b2CircleShape));
+ b2CircleShape* clone = new (mem) b2CircleShape;
+ *clone = *this;
+int32 b2CircleShape::GetChildCount() const
+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)
+ // 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;
+void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const
+ 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));
@@ -0,0 +1,91 @@
+#ifndef B2_CIRCLE_SHAPE_H
+#define B2_CIRCLE_SHAPE_H
+/// A circle shape.
+class b2CircleShape : public b2Shape
+ b2CircleShape();
+ /// 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);
+inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
+ return m_p;
+inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
+ B2_NOT_USED(index);
+ b2Assert(index == 0);
@@ -0,0 +1,139 @@
+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;
+int32 b2EdgeShape::GetChildCount() const
+bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+// 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,
+ // 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)
+ float32 t = numerator / denominator;
+ if (t < 0.0f || input.maxFraction < t)
+ b2Vec2 q = p1 + t * d;
+ // q = v1 + s * r
+ // s = dot(q - v1, r) / dot(r, r)
+ b2Vec2 r = v2 - v1;
+ if (rr == 0.0f)
+ float32 s = b2Dot(q - v1, r) / rr;
+ if (s < 0.0f || 1.0f < s)
+ output->fraction = t;
+ if (numerator > 0.0f)
+ output->normal = -normal;
+ output->normal = normal;
+void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+ 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
+ massData->center = 0.5f * (m_vertex1 + m_vertex2);
@@ -0,0 +1,74 @@
+#ifndef B2_EDGE_SHAPE_H
+#define B2_EDGE_SHAPE_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
+ b2EdgeShape();
+ /// Set this as an isolated edge.
+ void Set(const b2Vec2& v1, const b2Vec2& v2);
+ /// 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_vertex0.x = 0.0f;
+ m_vertex0.y = 0.0f;
+ m_vertex3.x = 0.0f;
+ m_vertex3.y = 0.0f;
@@ -0,0 +1,361 @@
+b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
+ void* mem = allocator->Allocate(sizeof(b2PolygonShape));
+ b2PolygonShape* clone = new (mem) b2PolygonShape;
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
+ m_vertexCount = 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_centroid = center;
+ b2Transform xf;
+ xf.p = center;
+ xf.q.Set(angle);
+ // Transform vertices and normals.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ m_vertices[i] = b2Mul(xf, m_vertices[i]);
+ m_normals[i] = b2Mul(xf.q, m_normals[i]);
+int32 b2PolygonShape::GetChildCount() const
+static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
+ 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;
+ const float32 inv3 = 1.0f / 3.0f;
+ // 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);
+ m_vertexCount = count;
+ // Copy vertices.
+ m_vertices[i] = vertices[i];
+ // Compute normals. Ensure the edges have non-zero length.
+ int32 i1 = i;
+ int32 i2 = i + 1 < m_vertexCount ? 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();
+#ifdef _DEBUG
+ // Ensure the polygon is convex and the interior
+ // is to the left of each edge.
+ for (int32 j = 0; j < m_vertexCount; ++j)
+ // Don't check vertices on the current edge.
+ if (j == i1 || j == i2)
+ continue;
+ b2Vec2 r = m_vertices[j] - m_vertices[i1];
+ // If this crashes, your polygon is non-convex, has colinear edges,
+ // or the winding order is wrong.
+ float32 s = b2Cross(edge, r);
+ b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order");
+ // Compute the polygon centroid.
+ m_centroid = ComputeCentroid(m_vertices, m_vertexCount);
+bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+ b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
+ float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
+ if (dot > 0.0f)
+bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ // Put the ray into the polygon's frame of reference.
+ float32 lower = 0.0f, upper = input.maxFraction;
+ int32 index = -1;
+ // 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 (numerator < 0.0f)
+ // 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)
+ b2Assert(0.0f <= lower && lower <= input.maxFraction);
+ if (index >= 0)
+ output->fraction = lower;
+ output->normal = b2Mul(xf.q, m_normals[index]);
+void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+ b2Vec2 lower = b2Mul(xf, m_vertices[0]);
+ b2Vec2 upper = lower;
+ for (int32 i = 1; i < m_vertexCount; ++i)
+ b2Vec2 v = b2Mul(xf, m_vertices[i]);
+ lower = b2Min(lower, v);
+ upper = b2Max(upper, v);
+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_vertexCount >= 3);
+ b2Vec2 center; center.Set(0.0f, 0.0f);
+ float32 I = 0.0f;
+ // s is the reference point for forming triangles.
+ b2Vec2 s(0.0f, 0.0f);
+ s += m_vertices[i];
+ s *= 1.0f / m_vertexCount;
+ const float32 k_inv3 = 1.0f / 3.0f;
+ b2Vec2 e1 = m_vertices[i] - s;
+ b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s;
+ 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
+ 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));
@@ -0,0 +1,95 @@
+#ifndef B2_POLYGON_SHAPE_H
+#define B2_POLYGON_SHAPE_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
+ b2PolygonShape();
+ /// Copy vertices. This assumes the vertices define a convex polygon.
+ /// It is assumed that the exterior is the the right of each edge.
+ /// The count must be in the range [3, b2_maxPolygonVertices].
+ void Set(const b2Vec2* vertices, int32 vertexCount);
+ /// Build vertices to represent an axis-aligned box.
+ /// @param hx the half-width.
+ /// @param hy the half-height.
+ void SetAsBox(float32 hx, float32 hy);
+ /// Build vertices to represent an oriented box.
+ /// @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);
+ int32 GetVertexCount() const { return m_vertexCount; }
+ /// Get a vertex by index.
+ b2Vec2 m_centroid;
+ b2Vec2 m_vertices[b2_maxPolygonVertices];
+ b2Vec2 m_normals[b2_maxPolygonVertices];
+ int32 m_vertexCount;
+inline b2PolygonShape::b2PolygonShape()
+ m_type = e_polygon;
+ m_vertexCount = 0;
+inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
+ b2Assert(0 <= index && index < m_vertexCount);
+ return m_vertices[index];
@@ -0,0 +1,101 @@
+#ifndef B2_SHAPE_H
+#define B2_SHAPE_H
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/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
+ 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;
@@ -0,0 +1,122 @@
+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)
+void b2BroadPhase::TouchProxy(int32 proxyId)
+void b2BroadPhase::BufferMove(int32 proxyId)
+ if (m_moveCount == m_moveCapacity)
+ int32* oldBuffer = m_moveBuffer;
+ m_moveCapacity *= 2;
+ 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;
+ return;
+// 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)
+ // Grow the pair buffer as needed.
+ if (m_pairCount == m_pairCapacity)
+ b2Pair* oldBuffer = m_pairBuffer;
+ m_pairCapacity *= 2;
+ memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
+ m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);
+ m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);
+ ++m_pairCount;
@@ -0,0 +1,248 @@
+#ifndef B2_BROAD_PHASE_H
+#define B2_BROAD_PHASE_H
+#include <algorithm>
+struct b2Pair
+ int32 proxyIdA;
+ int32 proxyIdB;
+ int32 next;
+/// 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
+ 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 <typename T>
+ void UpdatePairs(T* callback);
+ /// Query an AABB for overlapping proxies. The callback class
+ /// is called for each proxy that overlaps the supplied AABB.
+ 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.
+ 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;
+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)
+ if (pair1.proxyIdA == pair2.proxyIdA)
+ return pair1.proxyIdB < pair2.proxyIdB;
+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 <typename T>
+void b2BroadPhase::UpdatePairs(T* callback)
+ // Reset pair buffer
+ // Perform tree queries for all moving proxies.
+ m_queryProxyId = m_moveBuffer[i];
+ if (m_queryProxyId == e_nullProxy)
+ // 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
+ // 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.
+ b2Pair* pair = m_pairBuffer + i;
+ if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
+ // Try to keep the tree balanced.
+ //m_tree.Rebalance(4);
+inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
+ m_tree.Query(callback, aabb);
+inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const
+ m_tree.RayCast(callback, input);
@@ -0,0 +1,154 @@
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+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)
+ 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(
+ const b2PolygonShape* polygonA, const b2Transform& xfA,
+ // 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_vertexCount;
+ 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.
+ 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->type = b2Manifold::e_faceA;
+ manifold->localNormal = normals[normalIndex];
+ manifold->localPoint = 0.5f * (v1 + v2);
+ // 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)
+ manifold->localNormal = cLocal - v1;
+ manifold->localNormal.Normalize();
+ manifold->localPoint = v1;
+ else if (u2 <= 0.0f)
+ if (b2DistanceSquared(cLocal, v2) > radius * radius)
+ manifold->localNormal = cLocal - v2;
+ manifold->localPoint = v2;
+ b2Vec2 faceCenter = 0.5f * (v1 + v2);
+ float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
+ if (separation > radius)
+ manifold->localNormal = normals[vertIndex1];
+ manifold->localPoint = faceCenter;
@@ -0,0 +1,698 @@
+ * 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.
+// Compute contact points for edge versus circle.
+// This accounts for edge connectivity.
+void b2CollideEdgeAndCircle(b2Manifold* manifold,
+ const b2EdgeShape* edgeA, const b2Transform& xfA,
+ // 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)
+ // 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)
+ cf.indexA = 0;
+ cf.typeA = b2ContactFeature::e_vertex;
+ manifold->localPoint = P;
+ manifold->points[0].id.cf = cf;
+ // Region B
+ if (u <= 0.0f)
+ b2Vec2 P = B;
+ // 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)
+ cf.indexA = 1;
+ // Region AB
+ float32 den = b2Dot(e, e);
+ b2Assert(den > 0.0f);
+ b2Vec2 P = (1.0f / den) * (u * A + v * B);
+ b2Vec2 n(-e.y, e.x);
+ if (b2Dot(n, Q - A) < 0.0f)
+ n.Set(-n.x, -n.y);
+ n.Normalize();
+ cf.typeA = b2ContactFeature::e_face;
+ manifold->localNormal = n;
+ manifold->localPoint = A;
+// This structure is used to keep track of the best separating axis.
+struct b2EPAxis
+ 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;
+ 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;
+ 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);
+ m_upperLimit = m_normal1;
+ m_lowerLimit = -m_normal2;
+ else if (convex2)
+ m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
+ m_lowerLimit = m_normal1;
+ m_upperLimit = -m_normal0;
+ m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
+ else if (hasVertex0)
+ if (convex1)
+ m_front = offset0 >= 0.0f || offset1 >= 0.0f;
+ m_front = offset0 >= 0.0f && offset1 >= 0.0f;
+ else if (hasVertex3)
+ if (convex2)
+ m_front = offset1 >= 0.0f || offset2 >= 0.0f;
+ m_front = offset1 >= 0.0f && offset2 >= 0.0f;
+ m_front = offset1 >= 0.0f;
+ // Get polygonB in frameA
+ m_polygonB.count = polygonB->m_vertexCount;
+ for (int32 i = 0; i < polygonB->m_vertexCount; ++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;
+ b2EPAxis edgeAxis = ComputeEdgeSeparation();
+ // If no valid normal can be found than this edge should not collide.
+ if (edgeAxis.type == b2EPAxis::e_unknown)
+ if (edgeAxis.separation > m_radius)
+ b2EPAxis polygonAxis = ComputePolygonSeparation();
+ if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
+ // 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;
+ b2ClipVertex ie[2];
+ b2ReferenceFace rf;
+ if (primaryAxis.type == b2EPAxis::e_edgeA)
+ // 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 = 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 = i2;
+ ie[1].id.cf.typeA = b2ContactFeature::e_face;
+ ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
+ rf.i1 = 0;
+ rf.i2 = 1;
+ rf.v1 = m_v1;
+ rf.v2 = m_v2;
+ rf.normal = m_normal1;
+ rf.i1 = 1;
+ rf.i2 = 0;
+ rf.v1 = m_v2;
+ rf.v2 = m_v1;
+ rf.normal = -m_normal1;
+ manifold->type = b2Manifold::e_faceB;
+ ie[0].v = m_v1;
+ ie[0].id.cf.indexB = 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.indexB = 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)
+ // Clip to negative box side 1
+ np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
+ // Now clipPoints2 contains the clipped points.
+ manifold->localNormal = rf.normal;
+ manifold->localPoint = rf.v1;
+ 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)
+ separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
+ if (separation <= m_radius)
+ b2ManifoldPoint* cp = manifold->points + pointCount;
+ cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
+ cp->id = clipPoints2[i].id;
+ 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()
+ axis.type = b2EPAxis::e_unknown;
+ axis.index = -1;
+ axis.separation = -FLT_MAX;
+ b2Vec2 perp(-m_normal.y, m_normal.x);
+ 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;
+ // Adjacency
+ if (b2Dot(n, perp) >= 0.0f)
+ if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
+ if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
+ if (s > axis.separation)
+void b2CollideEdgeAndPolygon( b2Manifold* manifold,
+ b2EPCollider collider;
+ collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
@@ -0,0 +1,317 @@
+// Find the separation between poly1 and poly2 for a give edge normal on poly1.
+static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
+ const b2PolygonShape* poly2, const b2Transform& xf2)
+ const b2Vec2* vertices1 = poly1->m_vertices;
+ const b2Vec2* normals1 = poly1->m_normals;
+ int32 count2 = poly2->m_vertexCount;
+ const b2Vec2* vertices2 = poly2->m_vertices;
+ b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount);
+ // Convert normal from poly1's frame into poly2's frame.
+ b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]);
+ b2Vec2 normal1 = b2MulT(xf2.q, normal1World);
+ // Find support vertex on poly2 for -normal.
+ int32 index = 0;
+ float32 minDot = b2_maxFloat;
+ for (int32 i = 0; i < count2; ++i)
+ float32 dot = b2Dot(vertices2[i], normal1);
+ if (dot < minDot)
+ minDot = dot;
+ b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);
+ b2Vec2 v2 = b2Mul(xf2, vertices2[index]);
+ float32 separation = b2Dot(v2 - v1, normal1World);
+ return separation;
+// Find the max separation between poly1 and poly2 using edge normals from poly1.
+static float32 b2FindMaxSeparation(int32* edgeIndex,
+ const b2PolygonShape* poly1, const b2Transform& xf1,
+ int32 count1 = poly1->m_vertexCount;
+ // Vector pointing from the centroid of poly1 to the centroid of poly2.
+ b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid);
+ b2Vec2 dLocal1 = b2MulT(xf1.q, d);
+ // Find edge normal on poly1 that has the largest projection onto d.
+ int32 edge = 0;
+ float32 maxDot = -b2_maxFloat;
+ for (int32 i = 0; i < count1; ++i)
+ float32 dot = b2Dot(normals1[i], dLocal1);
+ if (dot > maxDot)
+ maxDot = dot;
+ edge = i;
+ // Get the separation for the edge normal.
+ float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+ // Check the separation for the previous edge normal.
+ int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
+ float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
+ // Check the separation for the next edge normal.
+ int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;
+ float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
+ // Find the best edge and the search direction.
+ int32 bestEdge;
+ float32 bestSeparation;
+ int32 increment;
+ if (sPrev > s && sPrev > sNext)
+ increment = -1;
+ bestEdge = prevEdge;
+ bestSeparation = sPrev;
+ else if (sNext > s)
+ increment = 1;
+ bestEdge = nextEdge;
+ bestSeparation = sNext;
+ *edgeIndex = edge;
+ return s;
+ // Perform a local search for the best edge normal.
+ for ( ; ; )
+ if (increment == -1)
+ edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
+ edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
+ s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+ if (s > bestSeparation)
+ bestEdge = edge;
+ bestSeparation = s;
+ *edgeIndex = bestEdge;
+ return bestSeparation;
+static void b2FindIncidentEdge(b2ClipVertex c[2],
+ const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
+ const b2Vec2* normals2 = poly2->m_normals;
+ // 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.
+ float32 dot = b2Dot(normal1, normals2[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)
+ float32 totalRadius = polyA->m_radius + polyB->m_radius;
+ int32 edgeA = 0;
+ float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
+ if (separationA > totalRadius)
+ int32 edgeB = 0;
+ float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
+ if (separationB > totalRadius)
+ const b2PolygonShape* poly1; // reference polygon
+ const b2PolygonShape* poly2; // incident polygon
+ b2Transform xf1, xf2;
+ int32 edge1; // reference edge
+ uint8 flip;
+ if (separationB > k_relativeTol * separationA + k_absoluteTol)
+ poly1 = polyB;
+ poly2 = polyA;
+ xf1 = xfB;
+ xf2 = xfA;
+ edge1 = edgeB;
+ flip = 1;
+ poly1 = polyA;
+ poly2 = polyB;
+ xf1 = xfA;
+ xf2 = xfB;
+ edge1 = edgeA;
+ flip = 0;
+ b2ClipVertex incidentEdge[2];
+ b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
+ 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;
+ int np;
+ np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
+ if (np < 2)
+ np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2);
+ manifold->localNormal = localNormal;
+ manifold->localPoint = planePoint;
+ float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
+ if (separation <= totalRadius)
+ cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
+ 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;
@@ -0,0 +1,249 @@
+void b2WorldManifold::Initialize(const b2Manifold* manifold,
+ const b2Transform& xfA, float32 radiusA,
+ const b2Transform& xfB, float32 radiusB)
+ if (manifold->pointCount == 0)
+ 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;
+ b2Vec2 cA = pointA + radiusA * normal;
+ b2Vec2 cB = pointB - radiusB * normal;
+ points[0] = 0.5f * (cA + cB);
+ 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);
+ case b2Manifold::e_faceB:
+ normal = b2Mul(xfB.q, manifold->localNormal);
+ b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
+ b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
+ b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
+ b2Vec2 cA = clipPoint - radiusA * normal;
+ // Ensure normal points from A to B.
+ normal = -normal;
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
+ const b2Manifold* manifold1, const b2Manifold* manifold2)
+ 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;
+ // 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;
+// 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);
+ for (int32 i = 0; i < 2; ++i)
+ if (absD(i) < b2_epsilon)
+ // Parallel.
+ if (p(i) < lowerBound(i) || upperBound(i) < p(i))
+ 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)
+ // Does the ray start inside the box?
+ // Does the ray intersect beyond the max fraction?
+ if (tmin < 0.0f || input.maxFraction < tmin)
+ // Intersection.
+ output->fraction = tmin;
+// 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 = 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;
@@ -0,0 +1,276 @@
+#ifndef B2_COLLISION_H
+#define B2_COLLISION_H
+#include <climits>
+/// @file
+/// Structures and functions used for computing contact points, distance
+/// queries, and TOI queries.
+class b2Shape;
+class b2CircleShape;
+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
+ 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
+ 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)
+/// -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.
+struct b2Manifold
+ e_circles,
+ e_faceA,
+ e_faceB
+ b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact
+ b2Vec2 localNormal; ///< not use for Type::e_points
+ 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& xfB, float32 radiusB);
+ b2Vec2 normal; ///< world vector pointing from A to B
+ b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
+/// 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.
+ 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
+ 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* circleB, const b2Transform& xfB);
+/// Compute the collision manifold between a polygon and a circle.
+void b2CollidePolygonAndCircle(b2Manifold* manifold,
+/// Compute the collision manifold between two polygons.
+/// Compute the collision manifold between an edge and a circle.
+ const b2EdgeShape* polygonA, const b2Transform& xfA,
+void b2CollideEdgeAndPolygon(b2Manifold* manifold,
+ const b2PolygonShape* circleB, const b2Transform& xfB);
+/// Clipping for contact manifolds.
+ const b2Vec2& normal, float32 offset, int32 vertexIndexA);
+/// Determine if two generic shapes overlap.
+ 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)
+ if (d2.x > 0.0f || d2.y > 0.0f)
@@ -0,0 +1,603 @@
+// 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 = (b2CircleShape*)shape;
+ m_vertices = &circle->m_p;
+ m_count = 1;
+ m_radius = circle->m_radius;
+ case b2Shape::e_polygon:
+ const b2PolygonShape* polygon = (b2PolygonShape*)shape;
+ m_vertices = polygon->m_vertices;
+ m_count = polygon->m_vertexCount;
+ m_radius = polygon->m_radius;
+ case b2Shape::e_chain:
+ const b2ChainShape* chain = (b2ChainShape*)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];
+ m_buffer[1] = chain->m_vertices[0];
+ m_vertices = m_buffer;
+ m_count = 2;
+ m_radius = chain->m_radius;
+ case b2Shape::e_edge:
+ const b2EdgeShape* edge = (b2EdgeShape*)shape;
+ m_vertices = &edge->m_vertex1;
+ m_radius = edge->m_radius;
+ 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.
+ // 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);
+ void WriteCache(b2SimplexCache* cache) const
+ cache->metric = GetMetric();
+ cache->count = uint16(m_count);
+ const b2SimplexVertex* vertices = &m_v1;
+ 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);
+ // Origin is right of e12.
+ return b2Cross(e12, 1.0f);
+ return b2Vec2_zero;
+ b2Vec2 GetClosestPoint() const
+ case 0:
+ return m_v1.w;
+ return m_v1.a * m_v1.w + m_v2.a * m_v2.w;
+ case 3:
+ void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const
+ *pA = m_v1.wA;
+ *pB = m_v1.wB;
+ *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;
+ *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
+ *pB = *pA;
+ float32 GetMetric() const
+ return 0.0;
+ return 0.0f;
+ return b2Distance(m_v1.w, m_v2.w);
+ return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);
+ void Solve2();
+ void Solve3();
+ b2SimplexVertex m_v1, m_v2, m_v3;
+// 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;
+ // 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_v1 = m_v2;
+ // 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;
+// Possible regions:
+// - points[2]
+// - edge points[0]-points[2]
+// - edge points[1]-points[2]
+// - inside the triangle
+void b2Simplex::Solve3()
+ b2Vec2 w3 = m_v3.w;
+ // Edge12
+ // [1 1 ][a1] = [1]
+ // [w1.e12 w2.e12][a2] = [0]
+ // a3 = 0
+ float32 w1e12 = b2Dot(w1, e12);
+ float32 w2e12 = b2Dot(w2, e12);
+ float32 d12_1 = w2e12;
+ float32 d12_2 = -w1e12;
+ // Edge13
+ // [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);
+ if (d12_2 <= 0.0f && d13_2 <= 0.0f)
+ // e12
+ if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
+ // 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_v2 = m_v3;
+ if (d12_1 <= 0.0f && d23_2 <= 0.0f)
+ // w3 region
+ if (d13_1 <= 0.0f && d23_1 <= 0.0f)
+ m_v3.a = 1.0f;
+ m_v1 = m_v3;
+ // 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;
+ // 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;
+ b2Vec2 closestPoint = simplex.GetClosestPoint();
+ float32 distanceSqr1 = closestPoint.LengthSquared();
+ 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)
+ simplex.Solve2();
+ simplex.Solve3();
+ // If we have 3 points, then the origin is in the corresponding triangle.
+ if (simplex.m_count == 3)
+ // 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.
+ // 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;
+ if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])
+ duplicate = true;
+ // If we found a duplicate support point we must exit to avoid cycling.
+ if (duplicate)
+ // 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;
+ output->pointA += rA * normal;
+ output->pointB -= rB * normal;
+ // 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;
@@ -0,0 +1,141 @@
+#ifndef B2_DISTANCE_H
+#define B2_DISTANCE_H
+/// 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);
+ int32 GetVertexCount() const;
+ b2Vec2 m_buffer[2];
+ const b2Vec2* m_vertices;
+/// 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.
+ 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);
+inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
+ 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)
+ return bestIndex;
+inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
+ return m_vertices[bestIndex];
@@ -0,0 +1,771 @@
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+#include <cfloat>
+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;
+ 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_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);
+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)
+ if (m_nodes[proxyId].aabb.Contains(aabb))
+ // Extend AABB.
+ b2AABB b = aabb;
+ 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;
+ b.upperBound.x += d.x;
+ if (d.y < 0.0f)
+ b.lowerBound.y += d.y;
+ b.upperBound.y += d.y;
+ m_nodes[proxyId].aabb = b;
+void b2DynamicTree::InsertLeaf(int32 leaf)
+ ++m_insertionCount;
+ if (m_root == b2_nullNode)
+ m_root = leaf;
+ m_nodes[m_root].parent = b2_nullNode;
+ // 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;
+ 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())
+ aabb.Combine(leafAABB, m_nodes[child2].aabb);
+ cost2 = aabb.GetPerimeter() + inheritanceCost;
+ float32 oldArea = m_nodes[child2].aabb.GetPerimeter();
+ cost2 = newArea - oldArea + inheritanceCost;
+ // Descend according to the minimum cost.
+ if (cost < cost1 && cost < cost2)
+ // Descend
+ if (cost1 < cost2)
+ index = child1;
+ 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;
+ 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;
+ // The sibling was the root.
+ m_root = newParent;
+ // Walk back up the tree fixing heights and AABBs
+ index = m_nodes[leaf].parent;
+ while (index != b2_nullNode)
+ index = Balance(index);
+ 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)
+ 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;
+ 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;
+ m_nodes[grandParent].child2 = sibling;
+ m_nodes[sibling].parent = grandParent;
+ FreeNode(parent);
+ // Adjust ancestor bounds.
+ int32 index = grandParent;
+ m_root = sibling;
+ m_nodes[sibling].parent = b2_nullNode;
+// 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;
+ b2Assert(m_nodes[C->parent].child2 == iA);
+ m_nodes[C->parent].child2 = iC;
+ 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);
+ 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;
+ b2Assert(m_nodes[B->parent].child2 == iA);
+ m_nodes[B->parent].child2 = iB;
+ m_root = iB;
+ 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);
+ 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;
+int32 b2DynamicTree::GetHeight() const
+ return m_nodes[m_root].height;
+float32 b2DynamicTree::GetAreaRatio() const
+ 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
+ totalArea += node->aabb.GetPerimeter();
+ return totalArea / rootArea;
+// Compute the height of a sub-tree.
+int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
+ b2TreeNode* node = m_nodes + nodeId;
+ if (node->IsLeaf())
+ 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)
+ 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;
+ b2Assert(child1 == b2_nullNode);
+ b2Assert(child2 == b2_nullNode);
+ b2Assert(node->height == 0);
+ 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
+ int32 height1 = m_nodes[child1].height;
+ int32 height2 = m_nodes[child2].height;
+ int32 height;
+ height = 1 + b2Max(height1, height2);
+ b2Assert(node->height == height);
+ 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;
+ if (node->height <= 1)
+ b2Assert(node->IsLeaf() == false);
+ 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.
+ if (m_nodes[i].height < 0)
+ // free node in pool
+ if (m_nodes[i].IsLeaf())
+ m_nodes[i].parent = b2_nullNode;
+ nodes[count] = i;
+ ++count;
+ FreeNode(i);
+ while (count > 1)
+ float32 minCost = b2_maxFloat;
+ int32 iMin = -1, jMin = -1;
+ 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();
@@ -0,0 +1,284 @@
+#ifndef B2_DYNAMIC_TREE_H
+#define B2_DYNAMIC_TREE_H
+#include <Box2D/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
+ void* userData;
+ int32 parent;
+ int32 child1;
+ int32 child2;
+ // leaf = 0, free node = -1
+/// 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
+ /// 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.
+ /// Destroy a proxy. This asserts if the id is invalid.
+ /// 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.
+ /// 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();
+ 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
+ return m_nodes[proxyId].userData;
+inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
+ return m_nodes[proxyId].aabb;
+inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
+ b2GrowableStack<int32, 256> stack;
+ stack.Push(m_root);
+ while (stack.GetCount() > 0)
+ int32 nodeId = stack.Pop();
+ if (nodeId == b2_nullNode)
+ const b2TreeNode* node = m_nodes + nodeId;
+ if (b2TestOverlap(node->aabb, aabb))
+ bool proceed = callback->QueryCallback(nodeId);
+ if (proceed == false)
+ stack.Push(node->child1);
+ stack.Push(node->child2);
+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);
+ if (b2TestOverlap(node->aabb, segmentAABB) == false)
+ 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)
+ 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.
+ if (value > 0.0f)
+ // Update segment bounding box.
+ maxFraction = value;
@@ -0,0 +1,483 @@
+#include <cstdio>
+int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
+int32 b2_toiRootIters, b2_toiMaxRootIters;
+struct b2SeparationFunction
+ e_points,
+ // 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();
+ 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]);
+ float32 s = b2Dot(pointA - pointB, normal);
+ if (s < 0.0f)
+ m_axis = -m_axis;
+ s = -s;
+ // 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);
+ b2Vec2 normal = b2Mul(xfA.q, m_axis);
+ m_localPoint = 0.5f * (localPointA1 + localPointA2);
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+ float32 s = b2Dot(pointB - pointA, normal);
+ float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const
+ 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);
+ float32 separation = b2Dot(pointB - pointA, m_axis);
+ case e_faceA:
+ b2Vec2 axisB = b2MulT(xfB.q, -normal);
+ *indexA = -1;
+ float32 separation = b2Dot(pointB - pointA, normal);
+ case e_faceB:
+ b2Vec2 axisA = b2MulT(xfA.q, -normal);
+ *indexB = -1;
+ float32 separation = b2Dot(pointA - pointB, normal);
+ float32 Evaluate(int32 indexA, int32 indexB, float32 t) const
+ b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
+ b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
+ const b2DistanceProxy* m_proxyA;
+ const b2DistanceProxy* m_proxyB;
+ b2Sweep m_sweepA, m_sweepB;
+ 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)
+ ++b2_toiCalls;
+ output->state = b2TOIOutput::e_unknown;
+ output->t = input->tMax;
+ 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
+ // Prepare input for distance query.
+ 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(;;)
+ 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;
+ if (distanceOutput.distance < target + tolerance)
+ // Victory!
+ output->state = b2TOIOutput::e_touching;
+ output->t = t1;
+ // Initialize the separating axis.
+ b2SeparationFunction fcn;
+ fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
+ // 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;
+ // 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)
+ output->state = b2TOIOutput::e_separated;
+ output->t = tMax;
+ done = true;
+ // Has the separation reached tolerance?
+ if (s2 > target - tolerance)
+ // Advance the sweeps
+ t1 = t2;
+ // 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;
+ // Check for touching
+ if (s1 <= target + tolerance)
+ // Victory! t1 should hold the TOI (could be 0.0).
+ // Compute 1D root of: f(x) - target = 0
+ int32 rootIterCount = 0;
+ float32 a1 = t1, a2 = t2;
+ // 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);
+ // Bisection to guarantee progress.
+ t = 0.5f * (a1 + a2);
+ float32 s = fcn.Evaluate(indexA, indexB, t);
+ if (b2Abs(s - target) < tolerance)
+ // t2 holds a tentative value for t1
+ t2 = t;
+ // Ensure we continue to bracket the root.
+ if (s > target)
+ a1 = t;
+ s1 = s;
+ a2 = t;
+ s2 = s;
+ ++rootIterCount;
+ ++b2_toiRootIters;
+ if (rootIterCount == 50)
+ b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
+ ++pushBackIter;
+ if (pushBackIter == b2_maxPolygonVertices)
+ ++b2_toiIters;
+ if (done)
+ if (iter == k_maxIterations)
+ // Root finder got stuck. Semi-victory.
+ b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);
@@ -0,0 +1,58 @@
+#ifndef B2_TIME_OF_IMPACT_H
+#define B2_TIME_OF_IMPACT_H
+/// Input parameters for b2TimeOfImpact
+struct b2TOIInput
+ b2Sweep sweepA;
+ b2Sweep sweepB;
+ float32 tMax; // defines sweep interval [0, tMax]
+// Output parameters for b2TimeOfImpact.
+struct b2TOIOutput
+ enum State
+ e_failed,
+ e_overlapped,
+ e_touching,
+ e_separated
+ State state;
+/// 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);
/*
-* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
@@ -16,11 +16,12 @@
*/
-#include "b2BlockAllocator.h"
#include <cstdlib>
-#include <memory>
#include <climits>
-#include <string.h>
+#include <memory>
int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
@@ -100,7 +101,12 @@ void* b2BlockAllocator::Allocate(int32 size)
if (size == 0)
return NULL;
- b2Assert(0 < size && size <= b2_maxBlockSize);
+ b2Assert(0 < size);
+ if (size > b2_maxBlockSize)
+ return b2Alloc(size);
int32 index = s_blockSizeLookup[size];
b2Assert(0 <= index && index < b2_blockSizes);
@@ -155,7 +161,13 @@ void b2BlockAllocator::Free(void* p, int32 size)
return;
+ b2Free(p);
@@ -164,14 +176,13 @@ void b2BlockAllocator::Free(void* p, int32 size)
// Verify the memory address and size is valid.
int32 blockSize = s_blockSizes[index];
bool found = false;
- int32 gap = (int32)((int8*)&m_chunks->blocks - (int8*)m_chunks);
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 + gap <= (int8*)p);
+ (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
@@ -19,9 +19,9 @@
#ifndef B2_BLOCK_ALLOCATOR_H
#define B2_BLOCK_ALLOCATOR_H
-#include "b2Settings.h"
-const int32 b2_chunkSize = 4096;
+const int32 b2_chunkSize = 16 * 1024;
const int32 b2_maxBlockSize = 640;
const int32 b2_blockSizes = 14;
const int32 b2_chunkArrayIncrement = 128;
@@ -29,16 +29,19 @@ 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
+/// 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
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();
+* Copyright (c) 2011 Erin Catto http://box2d.org
@@ -16,18 +16,29 @@
-#ifndef B2_NULL_CONTACT_H
-#define B2_NULL_CONTACT_H
-#include "../../Common/b2Math.h"
-#include "b2Contact.h"
+b2Draw::b2Draw()
+ m_drawFlags = 0;
+void b2Draw::SetFlags(uint32 flags)
+ m_drawFlags = flags;
-class b2NullContact : public b2Contact
+uint32 b2Draw::GetFlags() const
-public:
- b2NullContact() {}
- void Evaluate(b2ContactListener*) {}
- b2Manifold* GetManifolds() { return NULL; }
+ return m_drawFlags;
-#endif
+void b2Draw::AppendFlags(uint32 flags)
+ m_drawFlags |= flags;
+void b2Draw::ClearFlags(uint32 flags)
+ m_drawFlags &= ~flags;
@@ -0,0 +1,81 @@
+/// 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
+ b2Draw();
+ virtual ~b2Draw() {}
+ 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;
@@ -0,0 +1,85 @@
+* Copyright (c) 2010 Erin Catto http://www.box2d.org
+#ifndef B2_GROWABLE_STACK_H
+#define B2_GROWABLE_STACK_H
+/// 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 <typename T, int32 N>
+class b2GrowableStack
+ b2GrowableStack()
+ m_stack = m_array;
+ 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));
+ std::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()
+ T* m_stack;
+ T m_array[N];
+ int32 m_capacity;
@@ -0,0 +1,94 @@
+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));
+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;
+ b2Vec2 x;
+ x.x = det * (a22 * b.x - a12 * b.y);
+ x.y = det * (a11 * b.y - a21 * b.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;
+ 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 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);
@@ -0,0 +1,731 @@
+#ifndef B2_MATH_H
+#define B2_MATH_H
+#include <limits>
+/// This function is used to ensure that a floating point number is
+/// not a NaN or infinity.
+inline bool b2IsValid(float32 x)
+ if (x != x)
+ // NaN.
+ float32 infinity = std::numeric_limits<float32>::infinity();
+ return -infinity < x && x < infinity;
+/// This is a approximate yet fast inverse square-root.
+inline float32 b2InvSqrt(float32 x)
+ 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);
+#define b2Sqrt(x) std::sqrt(x)
+#define b2Atan2(y, x) std::atan2(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)
+ /// 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)
+ 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
+ b2Vec3() {}
+ b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
+ void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
+ void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
+ b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
+ void operator += (const b2Vec3& v)
+ x += v.x; y += v.y; z += v.z;
+ void operator -= (const b2Vec3& v)
+ x -= v.x; y -= v.y; z -= v.z;
+ 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)
+ /// 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
+ b2Mat22 B;
+ 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
+ b2Vec2 ex, ey;
+/// A 3-by-3 matrix. Stored in column-major order.
+struct b2Mat33
+ b2Mat33() {}
+ b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
+ ez = c3;
+ ex.SetZero();
+ ey.SetZero();
+ ez.SetZero();
+ b2Vec3 Solve33(const b2Vec3& b) const;
+ /// 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.
+ 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)
+ /// Set to the identity rotation
+ 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.
+ 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
+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)
+ return b2Dot(c, c);
+inline b2Vec3 operator * (float32 s, const b2Vec3& a)
+ return b2Vec3(s * a.x, s * a.y, s * a.z);
+inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)
+ return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
+inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
+ return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);
+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;
+inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
+/// 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
+ qr.s = q.c * r.s - q.s * r.c;
+ qr.c = q.c * r.c + q.s * r.s;
+/// 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);
+// 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)
+ C.q = b2MulT(A.q, B.q);
+ C.p = b2MulT(A.q, B.p - A.p);
+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));
+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));
+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));
+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)
+template<typename T> 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;
+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 = (1.0f - beta) * c0 + beta * c;
+ a0 = (1.0f - beta) * a0 + beta * a;
+ 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;
@@ -16,36 +16,37 @@
+#include <cstdarg>
-b2Version b2_version = {2, 0, 1};
-int32 b2_byteCount = 0;
+#include "common/Exception.h"
+b2Version b2_version = {2, 2, 1};
// Memory allocators. Modify these to use your own allocator.
void* b2Alloc(int32 size)
- size += 4;
- b2_byteCount += size;
- char* bytes = (char*)malloc(size);
- *(int32*)bytes = size;
- return bytes + 4;
+ return malloc(size);
void b2Free(void* mem)
- if (mem == NULL)
- return;
+ free(mem);
- char* bytes = (char*)mem;
- bytes -= 4;
- int32 size = *(int32*)bytes;
- b2Assert(b2_byteCount >= size);
- b2_byteCount -= size;
- free(bytes);
+// You can modify this to use your logging facility.
+void b2Log(const char* string, ...)
+ va_start(args, string);
+ vprintf(string, args);
+void loveAssert(bool test, const char *teststr)
+ if (!test)
+ throw love::Exception("Box2D error: %s", teststr);
@@ -19,23 +19,14 @@
#ifndef B2_SETTINGS_H
#define B2_SETTINGS_H
-#include <assert.h>
-//#include <common/Exception.h>
+#include <cassert>
#include <cmath>
-#define B2_NOT_USED(x) x
-#define b2Assert(A) assert(A)
-//#define b2Assert(A) {if(!(A)) throw love::Exception("Box2D error: " #A);}
+void loveAssert(bool test, const char *teststr);
-// need to include NDS jtypes.h instead of
-// usual typedefs because NDS jtypes defines
-// them slightly differently, oh well.
-#ifdef TARGET_IS_NDS
-#include "jtypes.h"
-#else
+#define B2_NOT_USED(x) ((void)(x))
+//#define b2Assert(A) assert(A)
+#define b2Assert(A) loveAssert((A), #A)
typedef signed char int8;
typedef signed short int16;
@@ -43,114 +34,110 @@ typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
-#ifdef TARGET_FLOAT32_IS_FIXED
-#include "Fixed.h"
-typedef Fixed float32;
-#define B2_FLT_MAX FIXED_MAX
-#define B2_FLT_EPSILON FIXED_EPSILON
-#define B2FORCE_SCALE(x) ((x)<<7)
-#define B2FORCE_INV_SCALE(x) ((x)>>7)
typedef float float32;
-#define B2_FLT_MAX FLT_MAX
-#define B2_FLT_EPSILON FLT_EPSILON
-#define B2FORCE_SCALE(x) (x)
-#define B2FORCE_INV_SCALE(x) (x)
+typedef double float64;
-const float32 b2_pi = 3.14159265359f;
+#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
-const int32 b2_maxManifoldPoints = 2;
-const int32 b2_maxPolygonVertices = 8;
-const int32 b2_maxProxies = 2048; // this must be a power of two
-const int32 b2_maxPairs = 8 * b2_maxProxies; // this must be a power of two
-// Dynamics
+/// 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.
-const float32 b2_linearSlop = 0.005f; // 0.5 cm
+#define b2_linearSlop 0.005f
/// A small angle used as a collision and constraint tolerance. Usually it is
-const float32 b2_angularSlop = 2.0f / 180.0f * b2_pi; // 2 degrees
+#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)
-/// Continuous collision detection (CCD) works with core, shrunken shapes. This is the
-/// amount by which shapes are automatically shrunk to work with CCD. This must be
-/// larger than b2_linearSlop.
-const float32 b2_toiSlop = 8.0f * b2_linearSlop;
+/// Maximum number of sub-steps per contact in continuous physics simulation.
+#define b2_maxSubSteps 8
-/// Maximum number of contacts to be handled to solve a TOI island.
-const int32 b2_maxTOIContactsPerIsland = 32;
+// 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.
-const float32 b2_velocityThreshold = 1.0f; // 1 m/s
+#define b2_velocityThreshold 1.0f
/// The maximum linear position correction used when solving constraints. This helps to
/// prevent overshoot.
-const float32 b2_maxLinearCorrection = 0.2f; // 20 cm
+#define b2_maxLinearCorrection 0.2f
/// The maximum angular position correction used when solving constraints. This helps to
-const float32 b2_maxAngularCorrection = 8.0f / 180.0f * b2_pi; // 8 degrees
+#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.
-const float32 b2_maxLinearVelocity = 100.0f;
-const float32 b2_maxLinearVelocity = 200.0f;
-const float32 b2_maxLinearVelocitySquared = b2_maxLinearVelocity * b2_maxLinearVelocity;
+#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
-const float32 b2_maxAngularVelocity = 250.0f;
-#ifndef TARGET_FLOAT32_IS_FIXED
-const float32 b2_maxAngularVelocitySquared = b2_maxAngularVelocity * b2_maxAngularVelocity;
+#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.
-const float32 b2_contactBaumgarte = 0.2f;
+#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.
-const float32 b2_timeToSleep = 0.5f; // half a second
+#define b2_timeToSleep 0.5f
/// A body cannot sleep if its linear velocity is above this tolerance.
-const float32 b2_linearSleepTolerance = 0.01f; // 1 cm/s
+#define b2_linearSleepTolerance 0.01f
/// A body cannot sleep if its angular velocity is above this tolerance.
-const float32 b2_angularSleepTolerance = 2.0f / 180.0f; // 2 degrees/s
+#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)
// Memory Allocation
-/// The current number of bytes allocated through b2Alloc.
-extern int32 b2_byteCount;
/// 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
@@ -163,16 +150,4 @@ struct b2Version
/// Current version.
extern b2Version b2_version;
-/// Friction mixing law. Feel free to customize this.
-inline float32 b2MixFriction(float32 friction1, float32 friction2)
- return sqrtf(friction1 * friction2);
-/// Restitution mixing law. Feel free to customize this.
-inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)
- return restitution1 > restitution2 ? restitution1 : restitution2;
@@ -16,8 +16,8 @@
-#include "b2StackAllocator.h"
-#include "b2Math.h"
+#include <Box2D/Common/b2StackAllocator.h>
b2StackAllocator::b2StackAllocator()
@@ -19,7 +19,7 @@
#ifndef B2_STACK_ALLOCATOR_H
#define B2_STACK_ALLOCATOR_H
const int32 b2_stackSize = 100 * 1024; // 100k
const int32 b2_maxStackEntries = 32;
+#if defined(_WIN32)
+float64 b2Timer::s_invFrequency = 0.0f;
+#include <windows.h>
+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()
+float32 b2Timer::GetMilliseconds() const
+ float64 count = float64(largeInteger.QuadPart);
+ float32 ms = float32(s_invFrequency * (count - m_start));
+ return ms;
+#elif defined(__linux__) || defined (__APPLE__)
+#include <sys/time.h>
+ Reset();
+ timeval t;
+ gettimeofday(&t, 0);
+ m_start_sec = t.tv_sec;
+ m_start_msec = t.tv_usec * 0.001f;
+ return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec;
@@ -0,0 +1,45 @@
+/// Timer for profiling. This has platform specific code and may
+/// not work on every platform.
+class b2Timer
+ /// Constructor
+ b2Timer();
+ /// Reset the timer.
+ void Reset();
+ /// Get the time since construction or the last reset.
+ float32 GetMilliseconds() const;
+ float64 m_start;
+ static float64 s_invFrequency;
+ unsigned long m_start_sec;
+ unsigned long m_start_msec;
@@ -0,0 +1,54 @@
+#include <Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h>
+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);
@@ -0,0 +1,39 @@
+#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H
+#define B2_CHAIN_AND_CIRCLE_CONTACT_H
+class b2BlockAllocator;
+class b2ChainAndCircleContact : public b2Contact
+ 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);
+#include <Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h>
+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)
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
+void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+ b2CollideEdgeAndPolygon( manifold, &edge, xfA,
+ (b2PolygonShape*)m_fixtureB->GetShape(), xfB);
+#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H
+#define B2_CHAIN_AND_POLYGON_CONTACT_H
+class b2ChainAndPolygonContact : public b2Contact
+ b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
+ ~b2ChainAndPolygonContact() {}
@@ -0,0 +1,53 @@
+#include <Box2D/Dynamics/Contacts/b2CircleContact.h>
+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);
+void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+ b2CollideCircles(manifold,
+ (b2CircleShape*)m_fixtureA->GetShape(), xfA,
@@ -16,31 +16,24 @@
-#ifndef CIRCLE_CONTACT_H
-#define CIRCLE_CONTACT_H
+#ifndef B2_CIRCLE_CONTACT_H
+#define B2_CIRCLE_CONTACT_H
-#include "../../Collision/b2Collision.h"
class b2BlockAllocator;
class b2CircleContact : public b2Contact
- static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
- b2CircleContact(b2Shape* shape1, b2Shape* shape2);
+ b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2CircleContact() {}
- void Evaluate(b2ContactListener* listener);
- b2Manifold* GetManifolds()
- return &m_manifold;
- b2Manifold m_manifold;
};
@@ -0,0 +1,240 @@
+#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>
+#include <Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h>
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.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();
+ b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
+ if (createFcn)
+ if (s_registers[type1][type2].primary)
+ return createFcn(fixtureA, indexA, fixtureB, indexB, allocator);
+ return createFcn(fixtureB, indexB, fixtureA, indexA, allocator);
+void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+ b2Assert(s_initialized == true);
+ if (contact->m_manifold.pointCount > 0)
+ contact->GetFixtureA()->GetBody()->SetAwake(true);
+ contact->GetFixtureB()->GetBody()->SetAwake(true);
+ b2Shape::Type typeA = contact->GetFixtureA()->GetType();
+ b2Shape::Type typeB = contact->GetFixtureB()->GetType();
+ 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);
+// 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.
+ 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;
+ if (touching != wasTouching)
+ bodyA->SetAwake(true);
+ bodyB->SetAwake(true);
+ if (touching)
+ m_flags |= e_touchingFlag;
+ 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);
@@ -0,0 +1,331 @@
+#ifndef B2_CONTACT_H
+#define B2_CONTACT_H
+class b2Body;
+class b2Contact;
+class b2Fixture;
+class b2World;
+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 std::sqrt(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
+ /// 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();
+ /// Evaluate this contact with your own manifold and transforms.
+ virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;
+ friend class b2ContactManager;
+ friend class b2World;
+ friend class b2ContactSolver;
+ friend class b2Body;
+ friend class b2Fixture;
+ // Flags stored in m_flags
+ // 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);
+ 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;
+inline b2Manifold* b2Contact::GetManifold()
+ return &m_manifold;
+inline const b2Manifold* b2Contact::GetManifold() const
+inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const
+ const b2Body* bodyA = m_fixtureA->GetBody();
+ const b2Body* bodyB = m_fixtureB->GetBody();
+ 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;
+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
+inline b2Fixture* b2Contact::GetFixtureA()
+ return m_fixtureA;
+inline const b2Fixture* b2Contact::GetFixtureA() const
+inline b2Fixture* b2Contact::GetFixtureB()
+ return m_fixtureB;
+inline int32 b2Contact::GetChildIndexA() const
+ return m_indexA;
+inline const b2Fixture* b2Contact::GetFixtureB() const
+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()
+inline void b2Contact::SetRestitution(float32 restitution)
+ m_restitution = restitution;
+inline float32 b2Contact::GetRestitution() const
+ return m_restitution;
+inline void b2Contact::ResetRestitution()
@@ -0,0 +1,832 @@
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+#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.
+ 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->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;
+ 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()
+ 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);
+ 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;
+ 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.
+ 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();
+ // The constraints are redundant, just use one.
+ // TODO_ERIN use deepest?
+ vc->pointCount = 1;
+void b2ContactSolver::WarmStart()
+ // Warm start.
+ b2Vec2 normal = vc->normal;
+ b2Vec2 tangent = b2Cross(normal, 1.0f);
+ 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()
+ float32 friction = vc->friction;
+ b2Assert(pointCount == 1 || pointCount == 2);
+ // Solve tangent constraints first because non-penetration is more important
+ // than friction.
+ // Relative velocity at contact
+ b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
+ // Compute tangent force
+ float32 vt = b2Dot(dv, tangent);
+ 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;
+ // Solve normal constraints
+ if (vc->pointCount == 1)
+ b2VelocityConstraintPoint* vcp = vc->points + 0;
+ // 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;
+ b2Vec2 P = lambda * normal;
+ // 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);
+ 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);
+ // 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);
+ vn1 = b2Dot(dv1, normal);
+ vn2 = b2Dot(dv2, normal);
+ b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
+ b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
+ // 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)
+ // 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
+ // Case 4: x1 = 0 and x2 = 0
+ // vn1 = b1
+ // vn2 = b2;
+ vn1 = b.x;
+ vn2 = b.y;
+ if (vn1 >= 0.0f && vn2 >= 0.0f )
+ // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
+void b2ContactSolver::StoreImpulses()
+ 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)
+ b2Vec2 pointA = b2Mul(xfA, pc->localPoint);
+ b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]);
+ point = 0.5f * (pointA + pointB);
+ separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB;
+ 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;
+ normal = b2Mul(xfB.q, pc->localNormal);
+ b2Vec2 planePoint = b2Mul(xfB, pc->localPoint);
+ b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]);
+ // Ensure normal points from A to B
+ b2Vec2 point;
+// Sequential solver.
+bool b2ContactSolver::SolvePositionConstraints()
+ float32 minSeparation = 0.0f;
+ int32 indexA = pc->indexA;
+ int32 indexB = pc->indexB;
+ float32 mA = pc->invMassA;
+ float32 iA = pc->invIA;
+ float32 mB = pc->invMassB;
+ float32 iB = pc->invIB;
+ int32 pointCount = pc->pointCount;
+ 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;
+ 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 mA = 0.0f;
+ float32 iA = 0.0f;
+ if (indexA == toiIndexA || indexA == toiIndexB)
+ mA = pc->invMassA;
+ iA = pc->invIA;
+ if (indexB == toiIndexA || indexB == toiIndexB)
+ mB = pc->invMassB;
+ iB = pc->invIB;
+ float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
+ return minSeparation >= -1.5f * b2_linearSlop;